Open acblksun opened 5 years ago
Does it hit this code path? https://github.com/aspnet/AspNetCore/blob/71c5c66b211c7ab9d44751e39cef27c525124bb7/src/Security/Authentication/JwtBearer/src/JwtBearerHandler.cs#L112-L121 A) Token arrives for Auth-B. B) Authenticate runs for Auth-A, fails with SecurityTokenSignatureKeyNotFoundException (?), requests a rate limited refresh of metadata C) Authenticate runs for Auth-B and succeeds.
If this is what's happening then you should only see refreshes for A, not B. Disabling RefreshOnIssuerKeyNotFound would prevent it.
We're having the exact same problem where RefreshOnIssuerKeyNotFound
is firing on either Bearer Scheme failing. One of the two will always fail for us, while the other succeeds.
@HudsonAkridge it should only ever fire for the first provider. Can you confirm?
@Tratcher If I add 4 JWTBearerHandlers and only one can validate the token, it reloads the configuration on the other 3. Hope that helps. https://github.com/aspnet/AspNetCore/issues/14397
Does it happen every time? Every so often isn't unsurprising as it will go through the handlers in order and refresh to see if there's a new key.
Maybe this section from the issue I created helps.
This behavior is acceptable as long as there's only one JWTBearerHandler
.
Having multiple JWTBearerHandlers
results in unwanted traffic to the configuration endpoints.
This can be currently mitigated by:
RefreshInterval
to something different than its default (30 seconds)RefreshOnIssuerKeyNotFound
to false in all the JWTBearerHandlers
My proposed solution is to create an additional OnSignatureValidationFailed
event that can be triggered before Options.ConfigurationManager.RequestRefresh();
in JwtBearerHandler.cs
https://github.com/aspnet/AspNetCore/blob/master/src/Security/Authentication/JwtBearer/src/JwtBearerHandler.cs
This with the purpose of allowing the caller to intercept the RequestRefresh
and in this case, inject logic that can compare the invalid token
audience and authority, with the audience and authority of the handler
, if they are the same, then trigger the refresh otherwise it means we are trying to validate a token that is going to fail the validation no matter if we refresh.
The only change to the JWTBearerHandler is the addition of the OnSignatureValidationFailed
event. I have a PR ready but wanted to discuss if this could bring any value or not.
@blowdart this is functioning as intended, and the mitigations listed above are effective:
One way to redesign this would be to build one JwtAuthHandler that could contain multiple configurations. It would loop through all of them before triggering this kind of failure. Similar logic already exists when there are multiple token validators configured.
Recommend backlog.
@blowdart can I help with it?
@eliaslopezgt feel free to make some proposals, but for a refactor this large we want to agree on a design before starting any PRs.
If anyone else is struggling with this, I stumbled across a workaround for this issue here: https://oliviervaillancourt.com/posts/Fixing-IDX10501-MultipleAuthScheme
Basically, the issue seems to be that when running multiple auth schemes every auth scheme will attempt to validate the token. For the correct auth scheme everything happens as expected. For the other auth schemes, signature validation will fail with SecurityTokenSignatureKeyNotFoundException: IDX10501: Signature validation failed. Unable to match key
since the jwt token was issued by a different Idp. This marks the auth scheme with the RefreshOnIssuerKeyNotFound
and the metadata is forced to reload.
The solution from the blog is basically to only attempt token validation if the issuer on the token matches the authority issuer:
var token = jwtHandler.ReadJwtToken(jwtToken);
if (string.Equals(token.Issuer, authorityIssuer, StringComparison.OrdinalIgnoreCase))
{
// means the token was issued by this authority, we make sure full validation runs as normal
return await base.HandleAuthenticateAsync();
}
else
{
// Skip validation since the token as issued by a an issuer that this instance doesn't know about
// That has zero of success, so we will not issue a "fail" since it crowds the logs with failures of type IDX10501
// which are not really true and certainly not useful.
this.Logger.LogDebug($"Skipping jwt token validation because token issuer was {token.Issuer} but the authority issuer is: {authorityIssuer}");
return AuthenticateResult.NoResult();
}
As a side note, it also gets rid of the problem in #18940
Describe the bug
We require accepting multiple JwtBearer audience/authority pairs for our api.
When we setup multiple JwtBearer authentication for our api, we notice that aspnetcore middleware is continually calling the
.well-known/openid-configuration
at the minimum refresh interval of 30 seconds instead of the desired AutomaticRefreshInterval of 1 day.To Reproduce
Steps to reproduce the behavior:
[Authorize]
and pass the token correctly.well-known/openid-configuration
for all configured JwtBearer's will be called every 30 seconds (or everyRefreshInterval
) instead of once a day (or everyAutomaticRefreshInterval
).Expected behavior
Expect the default Refresh Interval of 30 seconds, and AutomaticRefreshInterval of 1 day to be sufficient, and the
.well-known/openid-configuration
to be called at most once per day per scheme.Note that I did perform a test of a single Jwt Bearer registered as the default, and it did perform as expected only calling at the AutomaticRefreshInterval
Additional context
Include the output of
dotnet --info
Code to reproduce. I used the VS2019 template for a webapi and modified it slightly.