Deploy WebAPI alongside web site in IIS on port 80 - c#

I believe this might be a troublesome request but I want to give it due diligence because I didn't know how best to respond to the requester.
We have an AngularJS client that is making a call through $resources to RESTful ASP.NET WebApi services deployed to IIS.
When I was demoing the connections, I served the WebApi on port 56730 out of Visual Studio (IIS Express) and my client's service is structured something like this:
app.service('repository', ['$resource', function ($resource) {
var repository = $resource(
'http://localhost:56730/api/Foo/:component',
{},
{
bars: {
method: 'GET'
,isArray: false
,url: 'http://localhost:56730/api/Foo/bars'
}
}
);
return repository;
}]);
To cut right to the chase, he was wondering why the WebAPI was not being served on Port 80 seeing as how it is "just serving json data." I wanted to respond that it's running inside its own process and the http server is running on port 80, but I wanted to respect his request on the off chance that I can deploy an ASP.NET WebApi project side-by-side with a client site on port 80.
I think this essentially boils down to the desire to have the "/api/{controller}/{id}" area of the site handled by WebAPI and have the http://server.com/resource requests handled as static resources.
Can it be done?
If it can, is it worth the trouble?

Related

Self-hosted SignalR in Windows .Net Service blocked by CORS on same server, works on other servers

I've been using a Self-Hosted SignalR Windows service accessed from multiple production servers (now in Azure) for 6+ years without a problem. I created an identical server for development in Azure but when I'm accessing SignalR from a browser on the SAME SERVER, SignalR gives me the following error when using either http:6287 or https:6286:
Access to XMLHttpRequest at 'http://myserver.learn.net:6287/signalr/negotiate?clientProtocol=1.5&xxxxxxx' from origin 'http://myserver.learn.net' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
However... It WORKS when connecting from OTHER SERVERS! I'm starting the connection with no errors using:
SignalR = WebApp.Start("http://myserver.learn.net:6287/");
SignalRSSL = WebApp.Start("https://myserver.learn.net:6286/");
(also SignalR = WebApp.Start("*:628x/" for both);
In my client code, I include the following script:
<script src="http://myserver.learn.net:6287/signalr/hubs"></script>
When I enter that url (or https version) in a browser ON THE SAME OR DIFFERENT SERVER, it shows the ASP.NET SignalR JavaScript Library v2.3.0-rtm page correctly! I've turned off the firewall with no change, added Microsoft.Owin.Host.HttpListener (someone suggested). I have also entered the wildcard certificate with netsh so the SignalR service can deal with the SSL connection using:
netsh http add sslcert ipport=0.0.0.0:6286 appid={12345678-db90-4b66-8b01-88f7af2e36bf} certhash=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Edit: I've also tried changing the ipport value to the real internal IP of the server as well as the public IP but no change.
So, why can't I access SignalR from the same server?
I found a solution in another answer here that worked. I changed:
$j.connection.hub.start().done(function () {
To:
$j.connection.hub.start({ jsonp: true, xdomain: true }).done(function () {
Which worked for both internal and external clients. xdomain:true alone didn't work but when I added jsonp:true it did. I have no real idea why, just that it's working now.

Azure App Service terminating https before application? [duplicate]

This question already has answers here:
Is current request being made over SSL with Azure deployment
(2 answers)
Closed 3 months ago.
I'm building an asp.net core web application on framework 2.2 and hosting on an azure app service on a linux app service plan.
Inside my application I inspect HttpRequest.Scheme. Running locally this returns https if I make a request using https. Running on azure it returns http.
It appears Azure App Services is terminating the SSL connection and proxying to my app. Is there a way to configure Azure App Services so the https request makes it to my application unmodified? Or at least HttpRequest.Scheme matches the original request?
I've built a sample diagnostic page to show this behavior:
var healthStatus = new
{
Port = context.Request.Host.Port?.ToString() ?? "unknown",
context.Request.Scheme,
context.Request.IsHttps,
Headers = context.Request.Headers.Select(x => $"{x.Key}:{x.Value}").ToArray()
};
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(JsonConvert.SerializeObject(healthStatus));
Debugging in VS Locally: https://localhost:1234/ping:
{
"Port":1234,
"Scheme": "https",
"IsHttps": true,
"Headers": <standard headers - nothing interesting>
}
Deploying to Azure App Services: https://appServiceExample.myDomain.com/ping:
{
"Port":"unknown",
"Scheme": "http",
"IsHttps": false,
Headers: [
// there are several more headers, but only these looked interesting:
"X-Forwarded-For:195.206.xxx.xxx:6922",
"X-Forwarded-Proto:https",
"X-AppService-Proto:https"
]
}
As a workaround: Could I solve this problem my relying on the X-AppService-Proto or X-Forwarded-Proto header? But this seems a bit of a hack, as I'd rather inspect the original incoming request - and I'm unsure how reliable these headers are.
Just summarize your comment.
The Azure App Service frontend layer TERMINATES the TLS channel (aka TLS offloading) and opens a new plain HTTP connection to your Web Worker, where your code lives. Routing is performed by ARR (Application Request Routing).
Therefore, from the point of view of your code every single request is "insecure".
X-Forwarded-Proto=https hints about the original request (that hit the frontends).
If checks have to be made, make them against X-ARR-SSL instead.
For more details, you could refer to this SO thread.

Asp.Net Core 2.0 HTTP -> HTTPS on Kestrel

I am learning Web-Based Programming and currently chose to work on Asp.Net Core 2.0.
I had successfully created a Web App with 2 layers of Controllers Home & API.
The Home Controller interacts directly with my Views while the API controller is called using GetAsync, PostAsync, PutAsync, etc. from my Home controller.
Recent I decided to move this app into HTTPS. Learned about self-signed certificates and had successfully gotten it to run except my API becomes inaccessible.
With SSL switched off, I could still call my API with Postman.
I used to call my API using this URI: http://localhost:5667/api/WebApi.
var response = client.GetAsync(“SomeApi”)
response.Wait();
Now I tried using URI: https://localhost:5667/api/WebApi but breaks at response.Wait().
Any advice, please. Thanks in advance
As requested: here’s a portion of my Startup.cs
services.AddMvc(
options =>
{
options.SslPort=5667;
options.Filters.Add(new RequireHttpsAttribute());
}
);
services.AddAntiforgery(
options =>
{
options.Cookie.Name=“_af”;
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy=CookieSecurePolicy.Always;
options.HeaderName=“X-XSRF-TOKEN”;
}
)
HTTP and HTTPS cannot be served over the same port. If your localhost HTTP endpoint is on 5667, then likely your HTTPS endpoint is on 5668 - though you can check the port number for yourself in the info that Kestrel will log on startup.
In production, HTTP is typically served over port 80, while HTTPS is served over port 443. These are the defaults if you don't specify otherwise.
Separately, you might want to consider enabling HTTPS redirection in your Configure block:
app.UseHttpsRedirection();

How do people test their [RequireHttps] attribute in a Web API?

Quick version
I'm sure many people have implemented a [RequireHttps] SSL check of some description (message handler, attribute, whatever) at some point in their Web API development. How do you guys and gals test that it works correctly both in terms of success and failure?
Not so quick version
I'm developing a REST service in a OWIN self-hosted ASP.NET Web API 2. I have already successfully secured the service with SSL and have implemented a custom [RequireHttps] attribute (derived from the answers to this SO question).
In the case when the client is calling the correct URL (e.g. https://my.server.com/api/values), if I add a breakpoint in the attribute definition, the debugger correctly breaks in the code (just calls the base and all is well, as expected).
The question is: how can I exercise the failure scenario for this attribute, such that the attribute code will return an error response without interfering with other server processes?
My Web API service listens on base address https://+:9443/. I've tried removing the s such that I connect to http://my.server.com:9443/api/values, but I get an error response status 502 (connection failed) after about a minute's timeout. Fair enough I suppose, but I was actually hoping to return a response ("SSL required") from my [RequireHttps] attribute.
Then I've tried creating the following StartOptions object:
var options = new StartOptions();
options.Urls.Add("https://+:9443/"); // listen on port 9443 with SSL
options.Urls.Add("http://+:80/"); // listen to standard HTTP port 80
and passing it to the WebApp like this:
WebApp.Start<Startup>(options)
Again, this didn't work when I connected to http://my.server.com:9443/api/values, but it worked when I connected to http://my.server.com:80/api/values.
However, this is not what I want to do. My production server hosts both secure (HTTPS) and insecure (HTTP on port 80) resources so my code will intercept legitimate calls to other processes that rely on port 80 and tell them to reconnect via https, which is wrong.
Can someone please advise on what options I have? Is there even a point to have [RequireHttps] given my situation, as it never seems to do anything useful?
What you are trying to do can't be done. Basically, you're trying to do the same thing as typing
http:443//www.google.com
Notice how that doesn't work either
The problem is that you're trying to access an http protocol over an SSL protocol port, and that is what's failing. Your code for the RequireHttps doesn't even get to execute because the request can't even be processed through IIS.

How can I implement ServiceStack.net rest call over HTTPS?

I would like to authenticate users of my servicestack.net rest services using basic auth over HTTPS.
Can anyone explain how the https portion of this would work or point me in the right direction? Is it the responsibility of the client to ensure the calls are made over https? Do I need to do anything involving SSL Certificates to enable this?
This service will most likely live on AppHarbor if that matters.
EDIT
Can anyone cite specific examples of how to accomplish this in service stack. I think that I would be having all of the services in my api require HTTPS. Would I be able to accomplish this using request filters?
You will need to have an SSL Certificate purchased and installed to handle https (you should be able to get one from your domain name provider, which you will then need to install on your hosting server). The service clients will generally be allowed to connect by any method they choose. It will be your responsibility to stop the request and generate an error message to the client if they attempt to connect by http, instead of allowing them access.
You can validate whether they are on http or https by checking the Request.Url.Scheme property in your REST Service API. Typically, a request for http on a service that requires https will return an HTTP 403 (forbidden) status code. If you have access to IIS, you can force HTTPS easily without doing any coding: http://www.sslshopper.com/iis7-redirect-http-to-https.html
If you don't need on all services the following at the top of any service that needs the security does the job:
if (!Request.IsSecureConnection)
{
throw new HttpError(HttpStatusCode.Forbidden,"403","HTTPS ONLY");
}
However it's better to this as a filter attribute: https://github.com/ServiceStack/ServiceStack/wiki/Filter-attributes
If you want it globally, you could apply your attribute to a shared BaseService or better use a global filter: https://github.com/ServiceStack/ServiceStack/wiki/Request-and-response-filters
...Like this:
this.GlobalRequestFilters.Add((req, res, dto) =>
{
if (!req.IsSecureConnection)
{
res.StatusCode = (int)HttpStatusCode.Forbidden;
res.Close();
}
});
If you want one that redirects to https rather than reject request then you could base it on this: http://weblogs.asp.net/dwahlin/requiring-ssl-for-asp-net-mvc-controllers

Categories