App.UseSession() vs App.UseAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) vs App.UseCookiePolicy() - c#

As described in https://learn.microsoft.com/en-us/aspnet/core/fundamentals/app-state?view=aspnetcore-3.1#session-state , one can add session to one's web app like so in Start.ConfigureServices
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromSeconds(10);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
});
and in Startup.Configure
App.UseSession()
There is also the possibility to use cookie authentication without identity via the authentication middleware, as described here https://learn.microsoft.com/en-us/aspnet/core/security/authentication/cookie?view=aspnetcore-3.1
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
...
});
My question is, if I, in Startup.Configure, use both
App.UseSession()
App.UseAuthentication()
Which Cookie settings will be used? Will the Cookie settings in services.AddSession be completely irrelevant (because the Authentication middleware also uses Session Cookies to keep track of users, right? Or am I completely wrong about that)? Or will they just be two different sessions/services running at the same time?
I am aware that Startup.Configure (the HTTP pipeline) is order-sensitive, as described my Microsoft "Adding the middleware to the app processing pipeline is order sensitive—it only affects downstream components registered in the pipeline." My second question is thus, if I put App.UseCookiePolicy(options) before the above, would it override the settings?
App.UseCookiePolicy()
Thanks in advance for any answers!

Related

How to increase session timeout in .net core 5

I have tried to extend the session timeout in my .net core 5.0 application but it seems the application has a default or an overriding method that enables session timeout to less than 30 minutes.
The below are where I have tried configuring the session timeout.
services.ConfigureApplicationCookie(options =>
{
// Cookie settings
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromHours(48);
options.LoginPath = "/Account/Login";
options.LogoutPath = "/Account/Logout";
options.AccessDeniedPath = new PathString("/Administration/AccessDenied");
options.SlidingExpiration = true;
});
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromHours(48);
options.Cookie.IsEssential = true;
});
What is it am I doing wrong.
Kindly assist.
I test your showing codes which should be working, here is the test result: You can see from the picture, the expire time of session is working
So maybe you can try these steps to check what cause your issue:
Make sure you are adding the app.UseSession(); in the Startup.cs
Check that there are no other places in your code where the session timeout is being set as a shorter time. For example, if you have a middleware that sets the lower session timeout, it could be overriding your configuration.
Check that the session middleware is being added after the authentication middleware. The authentication middleware sets its own timeout, and if the session middleware is added before it, it will use that value instead.
Or maybe you can share more information of your project and we can check what may cause your issue.

SIgn-in error in .NET 6 web application using Microsoft Identity (aka: Azure Active Directory)

I'm trying to use Microsoft Identity (formerly: Azure AD) authentication in an ASP.NET web application running on .NET 6
I've used this code to configure authentication in my startup class ConfigureServices method:
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(options => {
options.Instance = appSettings.UserSettings.AzIdInstance;
options.Domain = appSettings.UserSettings.AzIdDomain;
options.TenantId = appSettings.UserSettings.AzIdTenantId;
options.ClientId = appSettings.UserSettings.AzIdClientId;
options.CallbackPath = appSettings.UserSettings.AzIdCallbackPath;
options.SignedOutCallbackPath = appSettings.UserSettings.AzIdSignOutCallbackPath;
});
services.AddAuthorization();
Then in the Configure method, I've added:
app.UseAuthentication();
app.UseAuthorization();
When I try to access a controller action protected by the [Authorize] attribute, it correctly redirects me to the microsoft login page, however after I log in when the app then tries to redirect to my callback path (/signin-oidc) the connection gets reset and I get this browser error:
What am I doing wrong here? Is there a good example online on how to properly configure this?
Apparently, this error was happening because I had set the cookie's SameSite attribute to None with this code (I need it to be None for some cross-domain calls that are done to the server):
services.Configure<CookieAuthenticationOptions>(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
//In-memory cookie store, so sessions are forcibly killed when the webapp restarts
//This ensures that the user's Claims are up to date - remember to restart the service when Azure AD security group memberships are changed!
options.SessionStore = services.BuildServiceProvider().GetService<MemoryCacheTicketStore>();
//We want to disable the same-site policy, otherwise cross-domain API calls from JS won't work
options.Cookie.SameSite = SameSiteMode.None;
});
apparently this by itself causes the error. To fix it, I had to also add the following code:
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.HandleSameSiteCookieCompatibility(s => false);
options.MinimumSameSitePolicy = SameSiteMode.None;
});
this seems to have fixed the problem.

How to Add JwtBearer along with AddMicrosoftIdentityWebAppAuthentication

I am not sure I completely understood the changes for Microsoft.Identity.Web but I was following an article (given by Microsoft here) Where it described how to change in startup
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
to
services.AddMicrosoftIdentityWebAppAuthentication(Configuration);
while this looks good and easy I have a little more work because I have the following snippet in my existing code
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => this.configuration.Bind("AzureAd", options))
.AddJwtBearer(options =>
{
//this code used to validate signing keys
string stsDiscoveryEndpoint = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration";
IConfigurationManager<OpenIdConnectConfiguration> configurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(stsDiscoveryEndpoint, new OpenIdConnectConfigurationRetriever());
OpenIdConnectConfiguration openIdConfig = configurationManager.GetConfigurationAsync(CancellationToken.None).GetAwaiter().GetResult();
var tenantId = this.configuration["TenantId"];
var validIssuer = $"https://sts.windows.net/{tenantId}/";
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidIssuer = validIssuer,
ValidAudience = this.configuration["ClientId"],
IssuerSigningKeys = openIdConfig.SigningKeys,
};
});
To give you a little bit of context we have two variations with this application
User Login and do some staff (here user will get Microsoft login dialog to login using his/her credential)
Microsoft Azure calls our endpoint with some token and we need to validate that token.
The JWTvaliation section you see above is for the 2nd item where once we received a token we validate that token without login and UI workflow.
Question:
The above code is working correctly. The only issue here is if we like to use Microsoft.Identity how should we use the second item (JWT) because services.AddAuthentication().AddAzureAD returns IAuthenticationBuilder which we use further to add AddJwtBearer, While services.AddMicrosoftIdentityWebAppAuthentication does not return IAuthenticationBuilder.
AddMicrosoftIdentityWebAppAuthentication is actually just a fancy way to do the following:
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(…)
So it configures the default scheme to be the OIDC scheme and runs AddMicrosoftIdentityWebApp to configure whatever this ends up doing.
Now, AddAuthentication can actually be called multiple times on the service collection. You just need to be careful not to reconfigure things incorrectly. The parameterless function does not do that, so it is a good way to access the IAuthenticationBuilder to further configure authentication.
That means that you can change your code like this:
// configure Microsoft Identity Web first
// this also sets the default authentication to OIDC
services.AddMicrosoftIdentityWebAppAuthentication(Configuration);
// retrieve an authentication builder without changing the default
services.AddAuthentication()
// add JWT bearer now
.AddJwtBearer(options =>
{
// …
});

AspNet Core Identity, how set options.Cookie.SameSite?

In the latest templates and libraries used httpsonly flag. How can I turn it off?
This same question is outdated and it did not have full configuration sample:
AspNet Core Identity - cookie not getting set in production
In order to configure the application cookie when using Identity, you can use the ConfigureApplicationCookie method inside your Startup’s ConfigureServices:
// add identity
services.AddIdentity<ApplicationUser, IdentityRole>();
// configure the application cookie
services.ConfigureApplicationCookie(options =>
{
options.Cookie.SameSite = SameSiteMode.None;
});
Since Identity essentially adds cookie authentication under the hood, this is the configure action is the same thing you would normally pass to AddCookie() when configuring cookie authentication. It’s just that since AddIdentity() takes care of setting up authentication for you, the ConfigureApplicationCookie offers a way to adjust the cookie authentication options afterwards.
The answer by #poke did not help me set the value to SameSiteMode.None, atleast not in ASP.NET core 2.1.
Any value you set in configure application cookie is overridden by the MinimumSameSitePolicy setting of the cookie policy middleware.
To prevent the override, set MinimumSameSitePolicy for the UseCookiePolicy extension as SameSiteMode.None.
app.UseCookiePolicy(new CookiePolicyOptions
{
MinimumSameSitePolicy = SameSiteMode.None
});
Then set the actual same site value in the AddCookie extension in the ConfigureServices method
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options => options.Cookie.SameSite = SameSiteMode.None;
});
For my case in asp.net core 3.1 two things in combination did the trick
services.ConfigureApplicationCookie(options =>
{
options.Cookie.SameSite = SameSiteMode.Unspecified;
});
services.AddAntiforgery(opts => {
opts.Cookie.SameSite = SameSiteMode.Unspecified;
});

asp.net-core2.0 user auto logoff after 20-30 min

Few days ago I have decided to upgrade my web app from asp.net core 1.1 to core 2.0. Everything seems to work fine after minor changes, except authentication does not persist longer than 20-30 minutes.
We can take the default example from Visual Studio because I experience the same problem in my own webapp and in "ASP.NET Core Web Application" -> .NET Framework 4.6.1 + ASP.NET Core 2.0 + MVC + Individual User Accounts.
Configuration is default and should be users logged in for 14 days:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
...
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
app.UseAuthentication();
...
}
The PROBLEM is that user only stays logged in for 20-30 minutes. When user logs in ("Remember me" is selected) you can navigate through pages, and even reopen the browser, user stays logged in. Thus it seems authentication cookie is working. However, after 20-30 minutes user is logged out automatically, or should I say cookie expires (I do not know what happens). You can login again, and the game starts all over again.
I have tried setting Application cookie expiration, but this does not solve the problem:
services.ConfigureApplicationCookie(options => {
options.ExpireTimeSpan = TimeSpan.FromDays(1); // Just shortens cookie expiration time, but still logs out users after 20-30 minutes.
});
Since it takes 20-30 minutes, it looks like default session timeout:
services.AddSession(options =>
{
options.Cookie.Expiration = TimeSpan.FromDays(1); // This throws an error "Expiration cannot be set for the cookie defined by SessionOptions"
options.IdleTimeout = TimeSpan.FromDays(1); // This changes session sliding expiration time...
});
The same implementation worked fine in ASP.NET Core 1.1.
Ok then I have spammed different forums regarding this :) And here are my discoveries. Original https://github.com/aspnet/Identity/issues/1389
It seems there was a big gap in my understanding about how does this all work. I also found that I have lied a little. So to finish up for other as stupid as me.
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.Configure<SecurityStampValidatorOptions>(options => options.ValidationInterval = TimeSpan.FromSeconds(10));
services.AddAuthentication()
.Services.ConfigureApplicationCookie(options =>
{
options.SlidingExpiration = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
});
According my understanding this works like this:
the check if user is logged happens ~every 10 seconds, depending on requests ratio. Server checks security stamps upon every request to the server options.ValidationInterval = TimeSpan.FromSeconds(10)).
cookie is valid at minimum for 30 minutes options.ExpireTimeSpan = TimeSpan.FromMinutes(30);, but can be extended with options.SlidingExpiration = true; if page is refreshed or navigated.
important! do not be too "smart" like me and do no run _userManager.UpdateSecurityStampAsync(user); just after successful login. Because this updates security stamp and next validation validation will fail.
The server retains a session for a limited time after the last request. You can either set the session timeout or use the default value of 20 minutes.
To change the default value edit the ConfigureServices method.
public void ConfigureServices(IServiceCollection services)
{
....
services.AddSession(options => {
options.IdleTimeout = TimeSpan.FromMinutes(30);
options.CookieName = ".MyApplication";
});
}
I'm not an expert, and I'm sure this post will reveal that, but I've had this problem before running older versions of ASP.NET (Web Forms) on IIS.
The problem was that IIS has its own settings for session timeout which are set on the server itself, and AFAIK they cannot be in any way overridden by anything you configure on your site before deployment.
This makes sense especially for shared servers serving ASP.NET Web Forms-- they don't want their clients' users accumulating who-knows-how-much session data and having to keep it available indefinitely.
Using AJAX calls to keep the session alive should work, I think.
Please see this topic it help to you make session live for long time.
Keep Session Live
It's possible to set the cookie lifetime with the cookie policy:
services.AddCookiePolicy(opts => {
opts.CheckConsentNeeded = ctx => false;
opts.OnAppendCookie = ctx => {
ctx.CookieOptions.Expires = DateTimeOffset.UtcNow.AddDays(14);
};
});
Source

Categories

Resources