ASP.NET Core Web App UI part supports https only but API calls inside Web App supports http only - asp.net-core

I need to develop an asp.net core web app. Besides UI part of the web application, it needs to support api calls also. When the user accessing the web application, it should only support https. However, when other old web applications make api calls to this web application, it should support http only.
The web application will be deployed to linux box using the kestrel for hosting. Right now, aps.net core 3.1 is used for the web application. The kestrel-related part in the launchSettings.json are:
"WebApplication": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
I know I can use UseHttpsRedirection to make sure web application will direct all UI accessing to https only. But how to make api calls go through http only?
Can anyone shed some light on how I can achieve this? Some code snips will be extremely appreciated.

When other old web applications make api calls to this web
application, it should support http only.
Well, it can be configured in numerous way. As you can see in applicationUrl two port has been assigned by default which are "https://localhost:5001;http://localhost:5000"
If you call your API by http port it would listen to that port as well. However, if you specifically want to configure kestrel server you can either configure launchSettings.json or in program.cs file.
Kestrel server appsettings.json For HTTP:
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://localhost:53211"
},
"useSSL": false
},
Note: As launchSettings.json file doesn't publish, so Kestrel the option in appsettings.json we can set above configuration. You can check here.
Kestrel server program.cs For HTTP:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args).
ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureKestrel(serverOptions =>
{
serverOptions.Listen(IPAddress.Loopback, 5080);
}).UseStartup<Startup>();
});
Note: Once you modify above ConfigureKestrel in your program.cs file ommit app.UseHttpsRedirection(); because it would use https middleware to search https port. Before, implementaing above non http configure, please have a look our official document to know details how the configurations works.

Related

What the difference between "Urls" and "Endpoints" in Kestrel settings?

In ASP Net core web application, you can set which URL the application will listen in two different ways inside the appsettings.json:
1)
{
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://localhost:9999"
}
}
}
}
{
"Urls": "http://localhost:9999"
}
What are the differences between both approaches and why they exist?
As far as I know, both “Urls” and “Endpoints” is used to configure endpoints for the ASP.NET Core Kestrel web server.
The urls host configuration key have the limitations.(a default certificate must be available for HTTPS endpoint configuration).
But if you use the Endpoints points, you could have multiple endpoints settings with each own certificate.
Besides, the Url parameter in Endpoints is required for each endpoint. These endpoints replace those defined in the top-level Urls configuration rather than adding to them. Endpoints defined in code via Listen are cumulative with the endpoints defined in the configuration section.
More details, you could refer to this article.

What is the difference between using Kestrel Server or SignalR Server in ASP.NET Core?

As far as my understanding, SignalR allows you to add real-time functionality to web applications by allowing “server to client” and “client to server” communication. It runs on a specified port, which can be used for communication.Hubs need to be created with functions to be called.
Krestel server is a type of minified IIS server, which also runs in a given port and client application can connect to that port.
So, my question is what is the difference between using SignalR or Krestel server, since both run on given port and client applications connect to that port?
Remember that the idea of all frameworks is to encapsulate complexity!
Kestrel is the default, cross-platform Web server implementation that Microsoft implemented in the ASP.NET Core framework, just as Tomcat is the default on Spring Framework for Java.
More Info here
Kestrel, as a Web Server, handle traffic coming from outside to your app through http, and in the case of SignalR it also handles traffic bidirectional through webSockets, and it also can handle http/2 and others.
Remember that WebSockets is a different protocol on layer 7 just like http or https, websockets go through ws or wss these are also managed by a web server like Kestrel.
This being said, SignalR is just a library, part of the ASP.NET Core framework to handle WebSockets and other types of connections, making it easier for you as developer to build applications, abstracting all the complexity of:
a Web Server (Using Kestrel)
WebSockets (Using SignalR)
More info here
As Andy says, the Signalr is a kind of service which running on the kestrel. In my opinion, it is a web framework like MVC or web api.
We will add the Signalr like a service as MVC , Razor Pages and add its routes like below:
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddSignalR();
}
Endpoint:
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapHub<UserActivityHub>("/active");
});
The kestrel is a webserver, which is used to host the core application. It will listen for HTTP requests and surfaces them to the app as a set of request features composed into an HttpContext. Details about kestrel server ,you could refer to this article.

ASP.NET Core grpc-Web on IIS returns 404

.NET Core gRPC-Web client calling ASP.NET Core gRPC-Web server on http://localhost:5000 works fine.
Same client code calling server deployed to an IIS server with a virtual application (e.g., "http://build.mycompany.ca/myapp") results in
Status(StatusCode="Unimplemented", Detail="Bad gRPC response. HTTP status code: 404")
My ASP.NET Core 3.1 server is set up correctly. i.e.,
app.UseGrpcWeb(new GrpcWebOptions { DefaultEnabled = true });
is in between
app.UseRouting()
and
app.UseEndpoints(endpoints => {
endpoints.MapControllers();
endpoints
.MapGrpcService<GrpcClientService>()
.EnableGrpcWeb();
});
Any ideas what I'm missing here?
only the host portion of the URI is used in the Grpc client. A DelegatingHandler is required to redirect to a subdirectory on the target host.
https://github.com/grpc/grpc-dotnet/issues/880

Azure AD Authentication redirect_uri not using https on linux-hosted (Cloud Foundry) ASP.NET Core 2.2 application

I'm having an ASP.NET Core application hosted on a linux container in the SAP Cloud environment (Cloud-Foundry).
I am implementing Azure AD authentication using the Microsoft.AspNetCore.Authentication.AzureAD.UI libraries.
The authentication fails because no matter what protocol I initially access the web application, it generates the redirect_uri with the http protocol.
This fails because it does not match the https url defined in the app-registration in Azure.
AADSTS50011: The reply url specified in the request does not match the reply urls configured for the application
In the options, you can pass in the CallbackPath, but this only accepts a relative path (must start with /).
Otherwise it's coming from the redirect_url which is automatically generated based on the scheme, host, port and path extracted from the current request.
What I don't understand is that even when I access the application directly in the browser with https, it still uses http in the redirect_uri.
I guess the underlying problem is that the application hosted in Cloud Foundry accepts http requests.
Here's the code parts of how I implemented the Azure AD Authentication.
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("Authentication:AzureAD", options));
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
options.Authority = options.Authority + "/v2.0"; // Microsoft identity platform
options.TokenValidationParameters.ValidateIssuer = true;
});
app.UseHsts();
app.UseHttpsRedirection();
"Authentication": {
"AzureAD": {
"Instance": "https://login.microsoftonline.com/",
"ClientId": "{app-application-id}",
"TenantId": "{my-tenant-id}"
}
}
Tony Ju provided an excellent link to a similar issue, helping me to narrow down and eventually fix my issue.
However, that solution only provides code examples, I'd like to write a little bit more how I got to the final implementation.
The problem is related when your application is behind a proxy server and/or load balancers. The proxy obscures information about the initial request, such as the original schema, making services in your application that rely on this information behave incorrect (such as the return_url).
There is an excellent documentation about how to configure your ASP.NET Core application.
From the document, here's the root cause of my issue.
When HTTPS requests are proxied over HTTP, the original scheme (HTTPS)
is lost and must be forwarded in a header.
And the Cloud Foundry Security documentation tells the following:
Protocols
All traffic from the public internet to the Cloud Controller
and UAA happens over HTTPS. Inside the boundary of the system,
components communicate over a publish-subscribe (pub-sub) message bus
NATS, HTTP, and SSL/TLS.
In short, you need to forward certain HttpHeaders with the use of a standard Middleware.
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
app.UseForwardedHeaders();
However there is a known issue with .net core 2.1 when your app is deployed on a linux machine with no IIS as a proxy.
This becomes even more visible when you add the UseHttpRedirection middleware.
Taken from this blog post:
OAuth and OIDC also fail in this configuration because they generate
incorrect redirects. Calls to UseIISIntegration add and configure
forwarded headers middleware when running behind IIS, but there’s no
matching automatic configuration for Linux (Apache or Nginx
integration). The fix for this issue is discussed in more detail in
the doc article Forward the scheme for Linux and non-IIS reverse proxies.
This post eventually also provides the working fix for the current situation.
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
ForwardedHeaders.XForwardedProto;
// Only loopback proxies are allowed by default.
// Clear that restriction because forwarders are enabled by explicit
// configuration.
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
Looks like this is no longer needed for .net core 3, but SAP has not yet updated their dotnet container yet, so I cannot verify it at the time of writing.
Your issue is similar to this one. The difference is that you deployed the app in cloudfoundry, the other one deployed the app in Azure web app.
If your app is forced to use https, you can simply force the redirect_uri to use https.
If you want a common solution that both http and https will work(the premise is that you have configured both http and https as the redirect url in azure portal), you can try to find the real proto in the headers.

.NET Core ASP CORS is not restricting on Azure VM

So I've developed an asp .net core API that has to allow cross domain access. I've been able to get everything setup and running. I've enabled CORS and want it to apply the same setting across all of my endpoints so have the following in my Config method:
app.UseCors(builder => builder.WithOrigins(
"http://localhost:3000",
"http://localhost:3001",
"https://staging.example.com",
"https://production.server.com")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
And in my ConfigureServices method:
services.AddCors();
The code is before the MVC middleware and when running locally I have to send requests from localhost:3000 as all others are rejected/blocked (as expected).
Also on staging and live the app works fine and can call the API without any issues.
However, when deployed to the staging or production I can call the API from my local machine using Postman as well as by pointing my local copy of the web app (an AngularJS app) to the API.
Maybe I'm missing something or my understanding is wrong but I thought this shouldn't be allowed! And if not then any thoughts about where I may be going wrong? It seems as though my API is allowing any request from any domain.
CORS is only about ajax requests from web pages in domain A to domain B. Postman is a dev tool not a web page, and it doesn't care about CORS, that's why your Postman requests are not blocked. It is the same as building console application making http requests to your api, i.e. the requests won't be blocked.
Regarding the angular client, your requests are not blocked because you allow http://localhost:3000 and http://localhost:3001 origins. If you try ajax calls from lets say http://localhost:3002, it should be blocked
An option here is to extract the origins in config/json files. For example, you will have appsettings.Development.json with something like:
{
"cors": {
"Origins": ["http://localhost:3000", "http://localhost:3001"]
}
}
And additional files appsettings.Production(Staging).json when running in Production(Staging) environment.
If you want to totally secure your rest API, you should consider adding JWT authentication. For example, adding Identity Server 4 in the game, or using Azure B2C AD. But this mean that you should also add Login for the Angular client.