Open Exagram opened 2 years ago
They can't both be active so that's not the right approach. I think you have 2 options. Add a policy scheme that selects the right scheme based on the incoming request. See https://docs.microsoft.com/en-us/aspnet/core/security/authentication/policyschemes?view=aspnetcore-6.0
cc @HaoK Do we have this in the box (pass N schemes to an uber scheme and it'll pick the first one that succeeds).
No we don't have any additional logic in our policy (uber) schemes, the only sugar we have is the set of ForwardXyz properties on the default auth options for schemes (Authenticate/Challenge/Forbid) that will make it easy to forward to another scheme. You have to implement your own handler today to try N schemes and stop on the first one.
Certainly easy to add some built in policy schemes that do some common scenarios though, but it seems like people haven't had too much trouble rolling there own
Or maybe we should just add a ne example of this pick first scheme that succeeds Authenticate to the policyschemes docs
The ForwardDefaultSelector is an implementation detail of our auth handlers, there's no concept of this in the authentication/authorization stacks themselves. So its not exposed at the AddAuthentication level because not all auth schemes will support that concept
Let’s update the docs for this scenario
Is it good enough to document the common case of having the default scheme fallback to another scheme if it doesn't succeed? I don't think the N scheme case is really that common, its usually just between 2 schemes right?
Is 2 -> 3 much harder?
Depends on exactly what we want to illustrate, something like logic in the ForwardDefaultSelector doesn't really care as that's just a big switch. Are we looking to document that pattern? Alternatively I could just show something generic like a FallbackPolicyScheme, which you could then chain up like a linked list, i.e.
services.AddAuthentication("Primary")
.AddScheme<FallbackPolicyScheme>("Primary", o => o.FallbackScheme("Secondary"); o.ForwardAuthenticate("Cookies"))
.AddScheme<FallbackPolicyScheme>("Secondary", o => o.FallbackScheme("Third"); o.ForwardAuthenticate("Bearer"));
.AddScheme<FallbackPolicyScheme>("Third", o => o.FallbackScheme("Fourth"; o.ForwardAuthenticate("Cookie2"))
.AddCookie("Fourth")
And show how to implement the FallbackPolicyScheme to do this kind of chaining
I guess if we wanted to make this in the box, we could also just add the concept of FallbackAuthenticateScheme
to our default implementation so this kind of thing just works for authenticate (check yourself for authentication, if you don't have anything, then fallback to the FallbackAuthenticateScheme), its basically a second Foward, but instead of always forwarding, you only fallback
Thanks for contacting us.
We're moving this issue to the .NET 7 Planning
milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s).
If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues.
To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.
I have to support 3 schemes (ADFS2012, ADFS2016, and Azure AD). Azure AD is new I am adding. When I added Azure AD as teh 3rd scheme via AddMicrosoftIdentityWebApi where my .NET6 WebAPI is deployed to Azure App Service. The Trace log started filling up with IDX10503, IDX10223, IDX10516, IDX10205 errors. Not sure why these classified as errors and then go to Trace and not Exceptions. I removed AddMicrosoftIdentityWebApi and used AddJwtBearer instead to remove the errors.
Can someone please make it more clear how to implement the forward selector? In my case I wish to authorize all 3 to every controller. I currently have the following which always tries all 3.
builder.Services .AddAuthorization(options => { options.DefaultPolicy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .AddAuthenticationSchemes(AzureAd, Adfs2012, Adfs2016) .RequireRole(User_Roles) .Build(); });
Depends on exactly what we want to illustrate, something like logic in the ForwardDefaultSelector doesn't really care as that's just a big switch. Are we looking to document that pattern? Alternatively I could just show something generic like a FallbackPolicyScheme, which you could then chain up like a linked list, i.e.
services.AddAuthentication("Primary") .AddScheme<FallbackPolicyScheme>("Primary", o => o.FallbackScheme("Secondary"); o.ForwardAuthenticate("Cookies")) .AddScheme<FallbackPolicyScheme>("Secondary", o => o.FallbackScheme("Third"); o.ForwardAuthenticate("Bearer")); .AddScheme<FallbackPolicyScheme>("Third", o => o.FallbackScheme("Fourth"; o.ForwardAuthenticate("Cookie2")) .AddCookie("Fourth")
And show how to implement the FallbackPolicyScheme to do this kind of chaining
@HaoK That is interesting. I'm strugling w/ one use case I have on my company, and I hope this ForwardAuthenticate pattern will help me to provide an elegant solution.
We actually solve the use case described by @exagran by delegate the responsibility to handle multiple ISP providers to a SSO Gateway. This gateway generates authorization tokens to all my applications. But my aplications has a very diverse authorization strategies. Some of then use rbac, some use permission/claims, and other a mix of rbac at high level and permissions at application level. In short, I have a JWT Bearer as Authentication Scheme with provides the user identity and some enterprise (SSO) level rbac. But I also have a custom scheme that loads application level claims and join those to the ClaimsPrincipal.
Initially, we wrote an Middleware to grant the local claims to the authenticated identity. Then we migrate this code to authorization scheme level because it seems the right place to put this code. So we have now the AppSchemeHandler that uses JwtBearerHandler as dependency by composition that validates the JWT and create the Principal, then AppScheme attach additional claims and officially return AuthenticateResult.Success.
So, my question is, can this proposal pattern of ForwardAuthentication fit my use case instead of build an AuthorizationSchema w/ dependencies by composition, and chain then as an Authorization workflow?
Or i'm messing up the authorization schema purpose?
Hey @maxandriani let me see if I understand your scenario properly before trying to answer anything:
It sounds like you have a jwt bearer scheme which has your basic user / roles claims. And then you want to also have additional application level claims that you want included in the ClaimsPrincipal.
There are indeed lots of different ways you can do this:
Thanks to clarify @HaoK ! We choose the option 2 strategy. It worked like a charm.
Thanks for contacting us.
We're moving this issue to the .NET 8 Planning
milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s).
If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues.
To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.
Hi, also met the same issue, RequireAuthenticated() method forces all authentication schemes to be tried. If i properly understood, that was designed to collect as much information about user as possible. But in our case we have different api clients, that are supposed to authenticate via different schemas, and it's a bit annoying to see a lot of error logs, when in fact user pas authentication.
@devich2 Hi! As far as I understood the thread and your use case, I think you should write you own proxy scheme and properly evaluate wich schema to challenge based some information about the origin of the request (client id registration table, …).
We're using multiple Azure AD and Azure AD B2C schemes in various applications. What we would like to do is create a generic policy scheme selector based on issuer matching. Ideally, instead of using a static list of issuers, we want to match the HTTP request's token issuer to a configured jwtOptions.ClaimsIssuer
or jwtOptions.Configuration.Issuer
. However, MSAL retrieves issuer information using a ConfigurationManager
, and the configuration hasn't been loaded by the time ForwardDefaultSelector()
method is called. We can try to manually load the configuration using jwtOptions.ConfigurationManager.GetConfigurationAsync()
in order to retrieve the issuer value. However, that requires a blocking wait, since that's an async method, but ForwardDefaultSelector()
isn't!
The other (minor) downside to the above approach is that the token had to be decoded twice -- once by the policy scheme handler, and then again by the real scheme handler.
Is there an existing issue for this?
Describe the bug
I have a React SPA and a Mobile App that calls a Web API protected by Azure AD OIDC.
AddMicrosoftIdentityWebApi()
extensionGoal: If AT LEAST one of the schemes succeeds then the user should be authenticated. Unfortunately the two schemes are mutually exclusive:
AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
then the React SPA authenticates the user but the Mobile App returns 401AddAuthenticationSchemes(MobileAuthenticationDefaults.AuthenticationScheme)
then the Mobile App authenticates the user but the React SPA returns 401Expected Behavior
Both React SPA and Mobile App should be able to authenticate using their separate authentication schemes.
Steps To Reproduce
startup.cs example with JWT default:
MobileAuthenticationHandler:
MobileAuthenticationOptions.cs:
MobileAuthenticationDefaults.cs:
Exceptions (if any)
N/A
.NET Version
6.0.101
Anything else?