XSRF-TOKEN not updated when using IISExpress and localhost - asp.net-core

.Net Core api layer and .Net Core MVC w/ Angular2 front end. Locally, they are running in different website (localhost:xxx1 and localhost:xxx2) and published, the api is running in a sub directory of the frontend.
I've set up the .Net Core Antiforgery like so:
in the ConfigureServices section:
services.AddAntiforgery(options =>
{
options.HeaderName = "X-XSRF-TOKEN";
});
in the Configure section:
app.Use(next => context =>
{
var tokens = antiforgery.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, new CookieOptions() { HttpOnly = false });
return next(context);
});
When i initially launch the sites and browse to the website in Chrome, I do get the 2 Antiforgery tokens (.AspNetCore.Antiforgery.xxxx and the XSRF-TOKEN) and when I make a get/post/etc call I see the x-xsrf-token header is added to the call.
The problem is on each call, the api returns a new XSRF-TOKEN cookie but locally my cookie is not updated, it always contains the original value. When published online, this doesn't happen, the cookie updates every time.
I've tried setting the sites up locally to use localhost.somedomain.com but that didn't work.
Any suggestions as to what I'm doing wrong or how to get it working locally?

The issue on my local machine was that I was running each app in its own IIS Express (localhost:xxx1 and localhost:xxx2).
I ended up setting IIS up to host .net core following this article (https://learn.microsoft.com/en-us/aspnet/core/publishing/iis) and i'm getting the expected result.

Related

Angular with OData batch request fails on IIS

I am using Odata with .Net Core web api. For client side i am usin angular 13. OData batch request works fine in localhost. After published on iis with 'ng-build' i am getting a cors error from odata batch request. I already allow origins. What am i missing?
I am not sure but think it was really related with cors.
I only added this code block in to "Configure" method in startup.cs and problem solved.
app.Use((context, next) => {
context.Response.Headers["Access-Control-Allow-Origin"] = "*";
return next.Invoke();
});
But before the batch, i didn't need this code block i have added. All request works fine (except batch) without the code block i have added. I am trying to understand this part.

Microsoft.Identity.Web.UI works locally but not in App Service

I've been trying to add auth to my web app following: https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/master/1-WebApp-OIDC/1-1-MyOrg
If I run locally with appsettings.Development.json via dotnet run, I can log in using my organization credentials as expected. When I containerize and deploy to my Web App in Azure, I do not get logged in successfully. The url in the browser stays at /signin-oidc and goes to the Error page from the default Razor pages app.
The App Service logs have messages saying .AspNetCore.Correlation.OpenIdConnect.[key?] cookie not found
[Update] The auth flow works on my phone but not on desktop.
Why would the same code work locally but not deployed?
Why isn't the cookie found?
Why does it work on iOS but not Windows?
Try to remove app.UseCookiePolicy(); in startup class.
Take a look here
Or the problem was IdentityServer was still using AddDeveloperSigningCredential
You can add a certificate in your code it will work perfectly
Refer here for more info
tl;dr - Setting the same-site cookie options in the authentication settings fixed this.
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(options =>
{
Configuration.Bind("AzureAd", options);
options.NonceCookie.SameSite = SameSiteMode.Unspecified;
options.CorrelationCookie.SameSite = SameSiteMode.Unspecified;
});
This seems to be because the App Service enforces TLS-only and handles the TLS termination. Because of this, requests to the application are always HTTP even though the browser URL is HTTPS. This causes a number of problems, the first was that the redirect URL never matched since the Identity library uses the request scheme to form the redirect URL. I had "fixed" this by injecting a redirect URL rewrite:
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(options =>
{
Configuration.Bind("AzureAd", options);
options.Events ??= new OpenIdConnectEvents();
options.Events.OnRedirectToIdentityProvider += _fixRedirect;
});
...
private async Task _fixRedirect(RedirectContext context)
{
context.Request.Scheme = "https";
if(!context.ProtocolMessage.RedirectUri.StartsWith("https"))
context.ProtocolMessage.RedirectUri = context.ProtocolMessage.RedirectUri.Replace("http", "https");
await Task.CompletedTask;
}
However, the correlation cookie also seems to use the same HTTP request so that when the redirect comes back, the HTTPS doesn't match. Relaxing the SameSiteMode explicitly tells the browser(?) to allow the differing schemes. This is why my phone, with a different browser with different cookie policy, worked while desktop did not. Running locally using the dev-certs allowed the schemes to match since the app was terminating the TLS rather than the App Service.
I hooked into the CookiePolicyOptions.OnAppendCookie event to inspect the cookies while debugging to find this out.

Angular 11, HMR, wrong schema set, when used behind a asp.net core app with UseSpa

I have an asp.net core app that uses:
app.UseSpa(x =>
{
if (env.IsDevelopment())
{
x.Options.SourcePath = "ClientApp";
x.UseProxyToSpaDevelopmentServer("http://localhost:4200");
}
else
{
// x.Options.SourcePath
x.Options.DefaultPageStaticFileOptions = new StaticFileOptions
{
OnPrepareResponse = context =>
{
context.Context.Response.Headers.Add("Cache-Control", "no-cache, no-store");
context.Context.Response.Headers.Add("Expires", "-1");
}
};
}
});
angular is started with:
ng serve which then serves the site on http://localhost:4200
The --public-host does not seem to respect the schema.
The docs says: The URL that the browser client (or live-reload client, if enabled) should use to connect to the development server. Use for a complex dev server setup, such as one with reverse proxies.
My API is hosted in the asp.net core app.
The browser tries to connect to: https://localhost:4200/sockjs-node/info?t=1605229799939 ... which is not running. Notice the https, which is gets from the asp.net core app which is being served over https.
I can get it to work if I start the angular dev server with --ssl, trust the certicate in my certificate store in Windows, so .NET trusts that certificate. The issues is that there is no override for the UseSpa as I have found, to trust self signed certificates, when running in development.
I want the setup to be as clean as possible, with the least amount of hacks, like trusting self signed certs on local machine.
Is there any way to let the HMR/nodejs/angular-cli know what it needs to connect to?
Well ... setting --public-host to localhost:5000 solved the issue.
Then it's just going though the asp.net core app which acts as a proxy. Not sure why I didn't think of that before creating this issue.

Sign out not working if deployed to IIS as a web application

Good morning. We have an asp .net core 2.1 with Angular application.
We use asp.net identity.
To logout users we use await HttpContext.SignOutAsync();
It works fine running the application in visual studio and deploying to a root website, but if we deploy to a webapplication inside a website in IIS, the logout doesn't work at all.
I assumed that the SignOutAsync deleted all information server side so even if the cookies were not modified, the server would reject any future request, but it seems it isn't.
Any idea?
It seems solved.
Using await _signInManager.SignOutAsync(); works fine.
I don't know the difference regarding using HttpContext.SignOutAsync()
You are using the Asp.net Core Identity ,so the authentication ticket in inside in .AspNetCore.Identity.Application cookie , you can try to delete the cookie by set specific scheme :
await HttpContext.SignOutAsync(IdentityConstants.ApplicationScheme);
But use SignInManager.SignOutAsync() is better which will delete below cookies :
await Context.SignOutAsync(IdentityConstants.ApplicationScheme);
await Context.SignOutAsync(IdentityConstants.ExternalScheme);
await Context.SignOutAsync(IdentityConstants.TwoFactorUserIdScheme);

UrlHelper returning http links on Azure App Service

I have a service that when deployed on Azure App Services returns http links instead of https links when using UrlHelper. When testing on my development machine it returns https links as expected, and the service is available and accessed through https requests.
An example of the type of route from my startup I'm trying to use is:
routes.MapRoute(
"FooBar",
"api/Foo/{Id}/Bar");
The link is then constructed using:
IUrlHelper _urlHelper = // Injected into class via service registration
int id = 42; // Arbitrary value for example
_urlHelper.Link("FooBar", new {Id = id});
When running on my local machine using Docker on Windows from Visual Studio I get a link of https://localhost:1234/api/Foo/42/Bar, but on my deployed Linux Container App Service on Azure I get http://my-app-name.azurewebsites.net/api/Foo/42/Bar.
I don't know what I'm doing wrong to get an http link instead of an https link, and would appreciate any advice/pointing in the right direction.
So I found the solution was with the configuration of the ASP.Net Core app itself. I performed the following modifications and then everything worked correctly:
Added app.UseForwardedHeaders(); to the request pipeline.
Added the following snippet to service container registration:
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.All;
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
The KnownNetworks and KnownProxies need to be cleared as they default to assuming an IIS hosting environment. For extra security you can add the known proxy/network IPs instead of clearing them here.