Control Keep Me Signed In (KMSI) with Microsoft Identity in ASP.NET - asp.net

I've implemented Microsoft Identity in a .NET 5 application. I want the user to always be prompted to log in to the app whenever a challenge occurs, hence the following code:
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(options =>
{
options.CallbackPath = ...
options.Events.OnRedirectToIdentityProvider = c =>
{
c.ProtocolMessage.Prompt = "login";
return Task.CompletedTask;
};
})
This works as expected. Is there a property (outside of the tenant-wide option) to also disable the KMSI prompt that still occurs? I went through each of the properties off of the root but it wasn't clear to me. Thank you.

Related

How to handle default antiforgery cookie in ASP.NET Core 6?

I published an ASP.NET Core 6 web app to an IIS 10 server.
Apparently the site produces an antiforgery cookie:
Does anyone know how to get rid of it or rename it?
I tried:
builder.Services.AddAntiforgery(options =>
{
options.HeaderName = "heres-a-cookie";
});
But that just added another cookie
The following also didn't help - it renamed the identity cookie.
builder.Services.AddAntiforgery(options =>
{
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.Name = "heres-a-cookie";
});
Thanks in advance.
services.AddMvc().AddRazorPagesOptions(o=>
{
o.Conventions.ConfigureFilter(new IgnoreAntiforgeryTokenAttribute());
});
try above.

.Net Core 6 Can't get Claims after authenticated by ADFS

I recently got a problem about authenticated by ADFS
In dot net core 6, below is my scenario.
I got one Web-Api site host on IIS in server 2019, and an ADFS server
Web -Api domain like https://xxx.domain.com
ADFS one like https://ooo.domain.com
I use WS-federation in my program
both browsers can't get value, edge and chrome
setting is
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme;
}).AddWsFederation(options =>
{ options.MetadataAddress = "my adfs url/FederationMetadata/2007-06/FederationMetadata.xml";
options.Wreply = "https://my webpai url/checkstate";
options.CallbackPath = "/checkstate";
options.BackchannelTimeout = TimeSpan.FromMinutes(1);
options.RemoteAuthenticationTimeout = TimeSpan.FromMinutes(15);
})
.AddCookie();
web-api
signin action for auth and will redirect to adfs server login page
and auth back to the checkstate action this part are work very well.
But I can't Get the value what I want.
In my understanding use the ws-federation(Microsoft.AspNetCore.Authentication.WsFederation6.0.3)
don't need to fetch other service for parse the value.
whole workflow should like this
Users fetch the Api => auth => adfs login => success and get adfs shared value in cookies
=> back to the callback action => get value in action and do something.
When I opened the Dev tools, I can see the real flow like
Signin 302 =>adfs 200 this with a lot cookies
prefix and key is "MSISAUTH"
=> checkstate 200 but, no cookies
I already contact with the ADFS server cruise member and got response said
"We done every setting and it's look fine. "
My question is Did I miss some key-part ?
and is any misunderstanding on workflow?
[Authorize]
[HttpGet("signin")]
public IActionResult Signin()
{
return new EmptyResult();
}
[HttpPost("checkstate")]
public IActionResult CheckState()
{
var name = User.Claims.FirstOrDefault(x=>x.Type == ClaimTypes.Name)?.Value;
return Ok($"Name:{name}");
}
My question is Did I miss some key-part ?
and is any misunderstanding on workflow?
How can I get the Claims value ?

ASP.NET Core 2.0 EventLog change Application name in Event Viewer

I have an ASP.NET Core 2.0 application using Microsoft.Extensions.Logging.EventLog to log to Windows Event Viewer with
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddEventLog();
logging.AddConsole();
})
On Event Viewer I can see my application working and logging itself to it, but it has the default name of Application under Source, and I'm trying to figure out on how to change it's name so it can Log under a different source name.
You can control that by passing an EventLogSettings to the extension method that adds logging.
var eventLogSettings = new EventLogSettings
{
LogName = "Something",
SourceName = "Something 2"
};
logging.AddEventLog(eventLogSettings);

ASP .NET Core Cookie Authentication expiration changes from timestamp to "Session" upon return

I am using ASP .NET Core RC1 with Facebook-authentication and silding window cookie expiration set up like this:
app.UseIdentity();
app.UseFacebookAuthentication();
and
services.AddIdentity<ApplicationUser, IdentityRole>((options =>
{
options.Cookies.ApplicationCookie.CookieName = "myauthcookie";
options.Cookies.ApplicationCookie.ExpireTimeSpan = TimeSpan.FromDays(5);
options.Cookies.ApplicationCookie.SlidingExpiration = true;
}))
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
This works fine when the user first logs in - the cookie expiration is set correctly. However, when the user returns to the page, the expiration of the cookie is set to "Session", so in practice the user has to re-authenticate every other visit.
Why is this happening? Have I not configured it correctly?
Update:
I have now done some testing without SlidingExpiration, and the issue remains the same. Upon returning to the page, the expiration of the cookie is changed to "Session". I am using Chrome.
Also, I am not running on https. Might this be a factor?
Short Answer
Set isPersistent: true when calling SignInManager.ExternalLoginSignInAsync.
Details
In the ASP.NET Core Web Application template, the AccountController.ExternalLoginCallback method contains this code:
_signInManager.ExternalLoginSignInAsync(
info.LoginProvider,
info.ProviderKey,
isPersistent: true); <------ set a persistent cookie.
If we set isPersistent: true when calling ExternalLoginSignInAsync , this startup configuration...
services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
options.Cookies.ApplicationCookie.CookieName = "MyApplicationCookie";
options.Cookies.ApplicationCookie.ExpireTimeSpan = TimeSpan.FromDays(5);
options.Cookies.ApplicationCookie.SlidingExpiration = true;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
...results in this application cookie...
...which persists across browser sessions.

ASP.NET Unauthorized access on a controller should return 401 instead of 200 and the login page

In an ASP.NET 5 Application I configured MVC and Identity framework like this:
app.UseMvc(config=>{
config.MapRoute("Default", "{controller}/{action}/{id?}", new
{
controller = "Home",
action = "Index"
});
});
and adding Identity Services :
services.AddAuthentication();
services.AddAuthorization();
services.AddIdentity<CrmUser, CrmUserRole>(config => {
config.User.RequireUniqueEmail = true;
})
.AddUserStore<MongoUserStore>()
.AddRoleStore<MongoUserStore>()
.AddDefaultTokenProviders();
and
app.UseIdentity()
.UseCookieAuthentication(i => { i.LoginPath = "/Account/Login";});
The example is defined as this:
public class MyApiController : Microsoft.AspNet.Mvc.Controller
{
[Authorize]
public async Task<ActionResult> Foo()
{
return Ok();
}
}
This works fine, but i also have some controller which I want to use in a API way. In ASP.NET 5, they all have same base class so there is no difference between API and View Controllers.
As a result when calling an unauthorized api which requires authorization, I get an HTTP 200 and the Login page instead of an HTTP 401.
In a blog post by Shawn Wildermuth I found this
services.AddCookieAuthentication(config =>
{
config.LoginPath = "/Auth/Login";
config.Events = new CookieAuthenticationEvents()
{
OnRedirect = ctx =>
{
if (ctx.Request.Path.StartsWithSegments("/api") &&
ctx.Response.StatusCode == 200)
{
ctx.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
return Task.FromResult<object>(null);
}
else
{
ctx.Response.Redirect(ctx.RedirectUri);
return Task.FromResult<object>(null);
}
}
};
});
But should this really be the expected way to do this? For me this smells a little.
This issue has been fixed in RC1.
Check GitHub comment here: Issue
To upgrade to RC1, go to http://get.asp.net.
To be even more sure, you can also clear your %userprofile%\.dnx\ folder prior to getting the latest version.
One solution to this is send the request with a the following header:
[{"key":"X-Requested-With","value":"XMLHttpRequest"}]
Here is an example using Postman without the header returns 200 and login webpage html
With the header returns 401 and no content (note there is not a tick next to it)
The sample app is based on the ASP.NET Core default solution with Individual User Authentication
Why this works:
CookieAuthenticationEvents.OnRedirectToLogin() uses IsAjaxRequest(context.Request) to decide whether to return a 401 or a redirect. So you have to have a header that will make IsAjaxRequest(context.Request) return true. It appears like a lot of JavaScript libraries add this automatically for you if you call your API through AJAX, but you might be not be using them.
Related questions you might find helpful
ASP.NET MVC - What does IsAjaxRequest() actually mean?
Request.IsAjaxRequest() always returning false in MVC4, tried all suggestions in SO, etc
Detecting IsAjaxRequest() with ASP.NET MVC and JQuery Form Plugin / File Upload
This behaviour was introduced as a result of a request the OP put in (which they mention under the question)
link to the current version of CookieAuthenticationEvents.cs at time of writing.
One (work around) option is to make the coockie options to redirect you to a controller action returning (unauthorized) result
Sorry I'm replying using my phone I'll try to enhance my answer when I'm using my PC...

Resources