-
Notifications
You must be signed in to change notification settings - Fork 223
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
Return TokenValidatedContext.Fail instead of throwing UnauthorizedAccessException in case of missing Roles / Scopes #1717
Conversation
Refactor to move the `AllowWebApiToBeAuthorizedByACL` check to before the `OnTokenValidated` event chain. This is both a minor performance win in the ACL case (possibly removing an event per token if the user doesn't already have an event), and is a minor simplification of the conditional logic. As a result it's no longer easy to validate the behavior in the ACL case; if that's deemed important we can move the whole logic set into another helper method.
Today, if a token is validated, but is: 1. Missing both Scopes and Roles 2. Not authorized via ACL Then the `JwtBearerHandler` will throw an `UnauthorizedAccessException` that looks like this: System.UnauthorizedAccessException: IDW10201: Neither scope or roles claim was found in the bearer token. at Microsoft.Identity.Web.MicrosoftIdentityWebApiAuthenticationBuilderExtensions.<>c__DisplayClass3_1.<<AddMicrosoftIdentityWebApiImplementation>b__1>d.MoveNext() at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync() at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync() at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.AuthenticateAsync() at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, String scheme) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) which by default results in an unhandled exception in the auth middleware pipeline, which in turn results in a 500 error for the user. While one could make the argument that a 500 is appropriate in this scenario, as the most likely cause is a misconfiguration on the AAD side, similar types of misconfiguration, such as a missing `tid` or `tenantId` claim results in a 401 Unauthorized error. As a result, replacing the throw statement with a call to mark the `ResultContext` as failed.
This could be a one-line change to switch the |
Additionally, I searched back through the history to see if there was an intentional change to make this an exception, and I wasn't able to see one back to the "initial commit" 6a393a9. From browsing, it appears that the exception was to be symmetric with APIs like If I missing any motivation for why the API is this way, please let me know. Thanks! |
...soft.Identity.Web/WebApiExtensions/MicrosoftIdentityWebApiAuthenticationBuilderExtensions.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks so much for the contribution @MattKotsenas Really appreciate it. |
Today, if a token is valid, but both:
Then the
JwtBearerHandler
will throw anUnauthorizedAccessException
that looks like this:which by default results in an unhandled exception in the auth middleware pipeline, which in turn results in a 500 error for the user.
While one could make the argument that a 500 is appropriate in this scenario, as the most likely cause is a misconfiguration on the AAD side, similar types of misconfiguration, such as a missing
tid
ortenantId
claim results in a 401 Unauthorized error.In order to make this change testable, I did the refactor in three steps, each in its own commit, to make the process easier to follow.
First, I moved the Roles / Scopes validation logic from the registration codepath into a new internal helper method, so that it could be called directly from unit tests. I used the
JwtBearerMiddlewareDiagnosticsTests
as a template.Second, to simplify the new helper, I moved the
AllowWebApiToBeAuthorizedByACL
check out of the token validation codepath, and instead returned it to the registration codepath. This is both a minor performance win for ACL cases (because it skips the event callback when it isn't needed) and slightly reduces complexity of the helper (by making the conditional simpler), at the expense of making the ACL case difficult to test again. If there's desire to test the ACL case, we can make follow up changes.Lastly, with the logic in a helper and tests written to validate the behavior, I replace the exception with a call to
TokenValidatedContext.Fail(message)
.Fixes #1716