IdentityServer / IdentityServer3.AccessTokenValidation

OWIN Middleware to validate access tokens from IdentityServer3
Apache License 2.0
90 stars 150 forks source link

Token validation and key rolling #143

Closed andrew-laughlin closed 7 years ago

andrew-laughlin commented 7 years ago

We're having a challenging with token validation during key rolling.

We use IS 4 and sign tokens with a single RSA key -- the primary signing key (PSK). Every 14 days a second RSA key (SSK) is generated and exposed via the well known endpoint. 24 hours after the SSK is created, we begin signing tokens with it. 24 hours after signing begins with the SSK, the PSK is removed and the SSK is promoted to the PSK. In general it takes 48 hours to complete a key roll.

We're experiencing an issue with middleware being unable to validate tokens. This issue seems to occur during key rolling, at the point the SSK starts signing. The exception in the middleware is

Authentication failed System.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException

It appears the issue is that the middleware receives a token, signed with a key it doesn't know about (SSK).

I've done some digging and hopefully the following is accurate. We're using the 2.14.0 middleware. The following class implements the caching for the middleware, with a default cache time of 1 day. If I understand the behavior correctly, the middleware will retrieve keys at startup, and roughly every 24 hours thereafter.

https://github.com/IdentityServer/IdentityServer3.AccessTokenValidation/blob/master/source/AccessTokenValidation/Plumbing/DiscoveryDocumentIssuerSecurityTokenProvider.cs

To perform the actual key retrieval, the middleware calls into to configuration manager:

private void RetrieveMetadata()
{
    if (_syncAfter >= DateTimeOffset.UtcNow)
    {
        return;
    }

    _synclock.EnterWriteLock();
    try
    {
        var result = AsyncHelper.RunSync(async () => await _configurationManager.GetConfigurationAsync());
        ...

The 2.14.0 package depends on <package id="Microsoft.IdentityModel.Protocol.Extensions" version="1.0.2.206221351" targetFramework="net45" />, which contains the code for ConfigurationManager here:

https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/1.0.2.206221351/src/Microsoft.IdentityModel.Protocol.Extensions/Configuration/ConfigurationManager.cs

It appears this code is caching as well, with a default time of 5 days. If this is correct, it could be 6 days before the middleware picks up new keys. Updated versions of ConfigurationManager<T> use a 1 day cache.

https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/master/src/Microsoft.IdentityModel.Protocols/Configuration/ConfigurationManager.cs

leastprivilege commented 7 years ago

What's the proposed solution?

andrew-laughlin commented 7 years ago

@leastprivilege Take a look at the PR I submitted and see if that feels like a good direction.

leastprivilege commented 7 years ago

Check the PR. thanks!