-
Notifications
You must be signed in to change notification settings - Fork 219
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
App Role adjustments from App registrations in Entra are not adopted in Blazor application #3158
Comments
I think there are two parts to this issue:
|
You are right. This is even worse. Microsoft.Identity givs a false sense of security. Revoking user sessions in Entra or blocking a user from signing-in does nothing to an application as long as cookie authentication is in place.
Do you mean, that
This seems not straight-forward at all. Do you have an example for this? |
No, I don't think so. One just really has to know how things work behind the scenes...
It doesn't matter where you get your roles from. If it's from azure ad, you can use graph api. |
Maybe, but I didn't find anything in the documentation about this. I found it by accident.
Well, I agree with you, it is sort of a cache issue. How do you solve it in a MVC application? Do I have to do my 3 steps above? Do you have an example for MVC? |
Something like
|
Ok. Thank you for this code piece. I found React to back-end changes in the cookie documentation. There are also some interesting properties This all can be used for MVC applications but still does not solve the problem in Bazor Web App (Server and Webassembly). This all is at best a workaround for an underlying problem. I still think Microsoft.Identity should handle changed users and especially revoked user sessions in Entra. |
Well... Not sure. This Lib is more for getting, caching and using tokens. What you can do is using a server-side ticket store for your cookies and a background worker for deleting these entries if "something" changed for your users. For Blazor, you will have to mess around with this: https://learn.microsoft.com/en-us/aspnet/core/blazor/security/authentication-state?view=aspnetcore-9.0&pivots=server |
Lots of possibilities for workarounds. |
You are right that the roles, are not re-evaluated until a token is re-issued by ESTS, which happens when tokens expire. As a mitigation, did you try to use a |
Is Continuous access evaluation planed for the (near) future?
I just tried it, but it does not force a relogin after a browser restart (if the browser is configured use the previous browser session) instead it just force a relogin after the This may help only for the "approle" assignment-issue if I lower the But a user can still be signed-in forever with the same approle and maybe even with a deleted user. |
This is what I explored, may not precise, just want to discuss. BasicThe problem here is, the OIDC authentication stores the user claims into the cookie. The framework retrieves claims from cookie if your cookie has not expired, and the cookie won't react to back-end. What I'm planning here is to validate user's role through Thing can be more complicated for Blazor Server because the user's claims are stored in the AuthenticationState, the BFFWe use the access token to get access to our backend API. And the library will store the token into cache, I guess the access token will keep role claims until it's expired. I'm not sure, but the only way I can imagine is to custom the JWT validation, and use the above GraphAPI way. Common Way?There is always a common way, custom role checking and check role for each operation. For each operation, this needs to call GraphAPI or hits your database if you custom the role store/checking. And it will be safest I think, since you are not going to use any kind of cache. It's just more complex. |
@Kumima thank you for your thoughts about this topic. I think your possible solutions for each scenario shows why this should be handled my Microsoft.Identity/ASP.NET Core in a common way and not each project-team figuring it out by themself. We use e.g. Blazor Server without BFF I could implement something as you mentioned above. But I don't think handling authentication/authorization by myself is a good approach.
Calling Microsoft Graph each time whould cause latency and other performance issues in the application. Microsoft themself said somewhere in the documentation, that we shouldn't implement our own authorization mechanism but if we would check each operation by itself we just would do that. By the way, Microsoft has launched the Microsoft Secure Future Initiative. The current solution does not implment the following key principal
|
Hi @habex-ch ,
Authentication and Authorization are two different beasts. Most systems I know don't even use their AD-based groups or roles. We use the login just for authentication which creates a claimsPrincipal with one identity. Within events tokenValidated and slidingWindow we enrich the claimsPrincipal with a second identity which holds the roles. |
Hi @michiproep, But we are build small LOB-applications (LOB = Line-of-Business). We don't have time doing this. We also want to use the default authorization implementation from ASP.NET Core. We don't have time doing a deep dive into claimsPrincipal, cookies and stuff like that. That should be abstracted in ASP.NET Core (as most of it is already). We want to focus on the business side of our applications and not the technical stuff. |
@jmprieur: What are the next steps with this issue? |
I tried a few steps in my Blazor Server App with a custom @Kumima: Do you have a working example for using a custom @jmprieur: I think there should be a Further information about RevalidatingServerAuthenticationStateProvider. |
internal sealed class DemoRevalidatingAuthenticationStateProvider(ILoggerFactory loggerFactory)
: RevalidatingServerAuthenticationStateProvider(loggerFactory)
{
protected override TimeSpan RevalidationInterval => TimeSpan.FromSeconds(5);
protected override Task<bool> ValidateAuthenticationStateAsync(
AuthenticationState authenticationState,
CancellationToken cancellationToken)
{
// Here comes your custom logic to revalidate the authentication state.
Console.WriteLine("Revalidating authentication state.");
return Task.FromResult(true);
}
}
builder.Services.AddScoped<AuthenticationStateProvider, DemoRevalidatingAuthenticationStateProvider>(); Just as simple as this. I've checked that there is the console output every 5 seconds. |
That looks good but it's not bound to requests from the browser. we should also somehow consider to try to sync this with the cookie behaviour. You probably don't want the cookie to still hold an active session or role claims if the RevalidatingServerAuthenticationStateProvider wants to trigger a logout or changes the roles of the user. Plus the other way around: If I delete my cookie I want to be in a clean, loggedOut state. |
@michiproep That's what the CookieEvents.OnValidPrinciple should do. The OnValidPrinciple only triggers before the Blazor circuits establish, such as you have a fully reload navigation. Once the circuit has been established, the claims are stored in the circuit. The Revalidation thing handles the validation and It's a per tab thing. |
@Kumima, thank you very much for this simple example. I found out where I made the mistake. I tried to integrate it directly in my PersistingAuthenticationStateProvider where I inherited from |
For your MVC and Blazor applications I implemented now the following things
The revalidation of the cookie is also required in Blazor because it the The logout for role assigments changes is maybe not the perfect solution but it works. Better would be updating the claims as @michiproep mentioned above but I don't get the time for that right now. |
Microsoft.Identity.Web Library
Microsoft.Identity.Web
Microsoft.Identity.Web version
3.2.0
Web app
Sign-in users
Web API
Not Applicable
Token cache serialization
Not Applicable
Description
I have an ASP.NET Core Blazor server application with a corresponding app regististration in Microsoft Entra. I configured 2 app roles in the App registration and assigned those app roles to our users.
Then I integrate Microsoft.Identity like this
If a user already is signed-in and I then removethe first app role and assign another role to the user, the already signed in user still has the first role assigned.
Even if I restart the browser he always keeps the first role and never get the second role.
Even if I block the user from signing in AzureAD he still is signed in and never gets locked out.
I investigated the whole thing and it seems to be an issue with the cookie authentication. When I delete the cookie ".AspNetCore.Cookies" it gets the new role assigned and the old one removed it its claims.
I can set the ExpireTimeSpan to 1 day like
But if the user keeps his browser open due to SlidingExpiration the cooke gets renewed indefinitly.
For ASP.NET Core Identity there is a way to force the validation of the claims as is explained in this link: https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity-configuration?view=aspnetcore-8.0#isecuritystampvalidator-and-signout-everywhere
But there is no way to this with Microsoft.Identity. This is a real security concern.
There should be a way to force the user validation against AzureAD in an interval.
Reproduction steps
Error message
No response
Id Web logs
No response
Relevant code snippets
Regression
No response
Expected behavior
The text was updated successfully, but these errors were encountered: