-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Make it easier to discover how to enforce/require auth in an application #42048
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
Comments
FYI @HaoK @blowdart @Tratcher @captainsafia @jcjiang @CamiloTerevint Interested in folks' thoughts on this one. The idea is to make it much easier to require authentication for the whole app. Today this is done something like the following which isn't terribly intuitive: builder.Services.AddAuthorization(c =>
{
c.FallbackPolicy = c.DefaultPolicy;
}); I think the thought was that we could enable something like this that would essentially do the above in a way that can't be overridden by other builder.Authentication.RequireAuthentication(); Alternatively perhaps it could be inverted: builder.Authentication.AllowAnonymousUsers = false; |
Why are you concerned about it being overridden? Do you think it would be common for people to have conflicting authz setups?
This is fine. |
So |
I'm concerned about scenarios where it's unclear that something else has loosened the auth requirements. |
Definitely prefer require over AllowAnonymous=false, but allowanonymous on endpoints still needs to override |
Yeah that's a great point. The idea is this should "do whatever it takes" to force all users of the app to be authenticated, with exceptions for resources that are explicitly marked as anonymous allowed. |
Right this is a valid concern, as if we don't change what RequireAuthentication does, it does not really require authentication as implemented only via fallback policy. You would easily bypass this by either changing the default policy, or specifying a policy that doesn't add the DenyAnonymous requirement. |
With those points clarified, what would the implementation of this look like? Does it need a new concept? |
Right so I'm fine with the name, but it needs to be implemented differently (in addition to using the fallback policy) |
It doesn't need a new concept, it just needs to fully do what we want it to do which is probably additional logic in Combine or the actual AuthZ service to be aware of this flag |
We have an Authorization requirement doing exactly what we want already, we would just need to force that requirement for all of Authorization perhaps when this turned on. |
Right, kind of like a "global requirement". |
Yeah we are getting a bit fragmented as we'd have Default Policy which is subtly different from fallback policy, and now global requirements, I guess we can introduce it that way and implement it like that |
A new IEnumerable on AuthorizationProperties (GlobalRequirements), RequireAuthentication would just add DenyAnonymous to the global requirements, we always add all global requirements to all Authorization requests. |
Where is |
Oops AuthorizationOptions |
Ah got it. That seems fairly straightforward then. Something would have to explicitly remove it then to "undo" what the proposed method does. |
We could have the global requirements as a mutable |
There is a bit of a danger here though as lifetime of these requirements becomes very tricky, as options are singleton lifetime, and for some requirements you may want to pull things from DI/request, so there's some complications here which we need to be careful about. |
So we'd probably need some kind of IGlobalAuthZRequirementProvider that enables requirements are more complicated in terms of construction |
So we have a method today |
That's... verbose 😄 How about |
Is there a reason we shouldn't build this as a full fledged security feature for all to use via AuthenticationBuilder? |
It requires authorization services to be present right? |
Sure, but is there no way for us to support the automatic adding of these services/middleware (only when needed) in a way that everyone could take advantage?
|
I'm leaning towards
We could integrate this logic in the base |
How would we do this without |
I haven't looked at the host builder code since probably before the 1.0 timeframe so maybe I'm super far off base here, but couldn't we do something like this?
|
Yeah I think we should keep this kind of behavior to |
Please no, that was absolutely horrible (that and automatic 401 responses hijacking a-la-
Well, in both cases, it's going to be a massive breaking change as all the libraries that don't currently use endpoints will need to use them to opt in a "no-op authorization policy" to be compatible with this flag: not just third-party libs, but also all the middleware and authentication handlers that ship as part of ASP.NET Core itself, including all the social/OIDC providers (e.g their callback actions can't require authorization or they'll just stop working completely 😄) |
@kevinchalet I'll point back to the original motivation then: make it easier to require auth for "the app". Today, that usually involves setting both the |
Correct me if I'm wrong, but in another issue, you mentioned that you planned to update As reminded in your OP,
Once its use is generalized, library writers will have basically two options to make their middleware work with
Given that option 1) is rather impractical - as a library author, you can't be sure the user will re-register the authorization middleware - option 2) will be the de facto choice and that's why I mentioned endpoints. Moving to a world where all middleware declare their endpoints in the routing mechanism might not be a bad thing, but it's clearly a paradigm change and potentially very impactful. |
We indeed have introduced the feature that configuring AuthN via the I'm not sure I share your concern regarding the interplay between this new (opt-in) behavior, If we are to limit this to endpoints only, we'd need to name it accordingly, but even then my concern is that it's very difficult to make clear exactly which resources will be protected and which won't, as whether a middleware/framework integrates via routing/endpoints is fairly opaque. |
I disagree, the experience is completely different: currently, the model is explicit: By hiding all these things in your So sure, it makes templates super minimalist, but it doesn't help folks understand how components are linked together and I don't think it's a good thing. Sometimes, less is not better. (IMHO, |
Can you help me understand what you would like to see instead of I would far prefer that configuring AuthN/AuthnZ leads to issues due to more protection than desired than less. That said, I'm keen to find ways we can make identifying and correcting AuthN configuration issues easier, e.g. via logging, analyzers, API design, etc. |
In my experience (and you mentioned System.Web ACLs earlier), most people are actually interested in securing whole "sections" of their apps, not really the entire app without any distinction at all, so something URL-based would have - IMHO - made more sense that a unique
Oh great to hear that, then PTAL at #4656 (comment) 😄 |
Making |
Wasn't the original plan supposed to simplify things? |
For background, FallbackPolicy was added for NegotiateAuth to emulate the IIS Windows Auth behavior of requiring all requests to authenticate. The middleware ordering still let you make exceptions for things like static files, but it's intentionally not more granular than that. |
Which is super bad from a security perspective, as IWA is - like cookies or basic - an automatic authentication method. By making IWA easy to enforce globally, you're just encouraging them to shoot themselves in the foot without realizing it: as soon as they'll innocently add an API endpoint, they'll end up with a CSRF vulnerability. I know all these automatic/default features are very appealing, but security is all about making the right choice and hiding everything behind defaults that can't work for all scenarios is, IMHO, a bad move. |
I agree that it's often logical to think about configuring AuthN/AuthZ in a URL-based manner, similar to the old While it's likely beyond the scope of what we can achieve now in .NET 7, given your extensive experience and interest in the area, I'll ask you, if you could make any changes to AuthN/AuthZ in ASP.NET Core, factoring in our limitations RE breaking changes, legacy, etc., what would you do? |
Regarding #4656, I would:
The current opt-in-for-authenticated-users approach is bad and leads to subtle security issues that could be easily mitigated by inverting the logic as I mentioned in 2018. The option suggested by @HaoK - depending on the global "require authenticated user" to add Regarding the API suggested in this thread, if it's really the approach you want to promote, I would avoid introducing a new layer if it ends up being as limited as public static void RequireAuthentication(this AuthorizationOptions options)
=> options.FallbackPolicy = options.DefaultPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
public static void RequireAuthentication(this AuthorizationOptions options, params string[] schemes)
=> options.FallbackPolicy = options.DefaultPolicy = new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(schemes)
.RequireAuthenticatedUser()
.Build(); ... with extensive XML documentation indicating that it could break existing scenarios, as explained in this thread. Since it will stay at the authorization middleware level, authentication handlers like the OAuth 2.0/OIDC/Negotiate or the aspnet-contrib/OpenIddict projects shouldn't be impacted as their endpoints are handled by That said, as I had mentioned in the other thread, OpenIddict will be impacted by the integration of |
Its complex because the primary concern was with layering, and we don't want authZ to require authN always, which is why there needs to be an explicit gesture (aka the new RequireAuthentication() method). That said, effectively all AuthorizationPolicies will have the behavior of always adding DenyAnonymousAuthorizationRequirement but only when RequireAuthentication is called |
Thanks for your input. To be clear, the proposal in this thread was not to make the new method enforce any AuthN requirement earlier than when
This has been suggested internally (hi there @halter73) and definitely seems worth exploring. Do we think it's as straightforward as always adding the CORS middleware before the authentication/authorization in the case where they'll be added (i.e. schemes are added via |
What do you mean exactly by "layering" here?
That's exactly why I suggested adding an I'd suggest re-reading #4656 so you can appreciate the number of people who've been trapped by this design problem. Making it more complex is likely not going to help 😄 |
@DamianEdwards can you put this in a milestone? |
Thanks for contacting us. We're moving this issue to the |
Moving to .NET 8. I implemented two approaches to enabling this via path-based authorization over at https://github.com/DamianEdwards/AspNetCorePathAuthorization @kevinchalet you might find this matches the kind of idea you proposed. One approach uses a custom middleware which effectively has to do its own route matching via a custom trie, etc. (eww) and another approach actually integrates with routing by attaching metadata to any endpoint based on route pattern, even if there isn't an endpoint already registered there! That means you can make endpoint-aware middleware "activate" even for requests with no endpoints, e.g. authorization can run on and protect requests for static files. |
@DamianEdwards looks nice and flexible 👍🏻 |
From #39857 (comment)
The text was updated successfully, but these errors were encountered: