Skip to content
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

JwtSecurityTokenHandler.ValidateToken throws ObjectDisposedException #1433

Closed
Tratcher opened this issue Jun 3, 2020 · 5 comments
Closed
Assignees
Labels
Customer reported Indicates issue was opened by customer Question User has asked a question

Comments

@Tratcher
Copy link
Contributor

Tratcher commented Jun 3, 2020


Issue moved from dotnet/aspnetcore#22490


From @vlkchris on Wednesday, June 3, 2020 9:50:59 AM

Describe the bug

I use RSA.Create() to create an RSA instance, and then use .ImportSubjectPublicKeyInfo to import public key.

  • The first time I call my validate token method it runs fine.
  • The second time I call it, I get SecurityTokenInvalidSignatureException (but only when I import the same key) This exception contains ObjectDisposedException
  • The third time it is ok again.
  • The fourth time it fails
    and so on.

To Reproduce

Please check the following test project. It shows how and when Exceptions occur.
https://github.com/vlkchris/JwtHelper

Exceptions (if any)

SecurityTokenInvalidSignatureException
message:
IDX10503: Signature validation failed. Keys tried: 'Microsoft.IdentityModel.Tokens.RsaSecurityKey, KeyId: '', InternalId: '-mBjPYLobIiFBJ_q6K4LP22czPQyTHkg4NrmHV4h_ZE'. , KeyId:
'.
Exceptions caught:
'System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'RSA'.
at System.Security.Cryptography.RSAImplementation.RSACng.ThrowIfDisposed()
at System.Security.Cryptography.RSAImplementation.RSACng.GetDuplicatedKeyHandle()
at System.Security.Cryptography.RSAImplementation.RSACng.VerifyHash(ReadOnlySpan1 hash, ReadOnlySpan1 signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)
at System.Security.Cryptography.RSAImplementation.RSACng.VerifyHash(Byte[] hash, Byte[] signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)
at Microsoft.IdentityModel.Tokens.AsymmetricAdapter.VerifyWithRsa(Byte[] bytes, Byte[] signature)
at Microsoft.IdentityModel.Tokens.AsymmetricAdapter.Verify(Byte[] bytes, Byte[] signature)
at Microsoft.IdentityModel.Tokens.AsymmetricSignatureProvider.Verify(Byte[] input, Byte[] signature)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Byte[] encodedBytes, Byte[] signature, SecurityKey key, String algorithm, SecurityToken securityToken, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
'.
token: '{"alg":"RS256","typ":"JWT"}.{"someclaim":"some value"}'.

Further technical details

  • ASP.NET Core version = netcoreapp3.1

  • Include the output of dotnet --info

dotnet --info
.NET Core SDK (reflecting any global.json):
Version: 3.1.101
Commit: b377529961

Runtime Environment:
OS Name: Windows
OS Version: 10.0.17134
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\3.1.101\

Host (useful for support):
Version: 3.1.1
Commit: a1388f194c

.NET Core SDKs installed:
2.1.505 [C:\Program Files\dotnet\sdk]
2.1.602 [C:\Program Files\dotnet\sdk]
2.1.700-preview-009601 [C:\Program Files\dotnet\sdk]
2.1.700 [C:\Program Files\dotnet\sdk]
2.1.800-preview-009677 [C:\Program Files\dotnet\sdk]
2.1.801 [C:\Program Files\dotnet\sdk]
2.2.105 [C:\Program Files\dotnet\sdk]
3.0.100 [C:\Program Files\dotnet\sdk]
3.1.101 [C:\Program Files\dotnet\sdk]

.NET Core runtimes installed:
Microsoft.AspNetCore.All 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.1.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.1.12 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.1.13 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.2.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.App 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.1.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.1.12 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.1.13 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.2.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 3.1.1 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.1.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.1.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.1.13 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.2.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 3.1.1 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 3.1.1 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

To install additional .NET Core runtimes or SDKs:
https://aka.ms/dotnet-download

  • The IDE (VS / VS Code/ VS4Mac) you're running on, and it's version
    Visual Studio Professional 16.3.5
@GeoK
Copy link
Member

GeoK commented Jun 4, 2020

Hi @vlkchris, the issue here is that IdentityModel by default caches signature providers, together with and keys which you disposed.

In your sample, first validation succeeds, and IdentityModel adds a signature provider (with your key) to the cache.
In the second validation, IdentityModel recognizes the key and uses a cached signature provider to validate a token, but the key of that provider is now disposed.


There are a few possible workarounds for this issue:

  1. Don't dispose your RSA key here.

  2. Don't cache a signature provider for a key, by replacing this line with:

SecurityKey key = new RsaSecurityKey(rsa)
{
    CryptoProviderFactory = new CryptoProviderFactory()
    {
        CacheSignatureProviders = false
    }
};
  1. Don't cache a signature provider associated with keys from a TokenValidationParameters object, by adding the following here:
var validationParameters = new TokenValidationParameters
{
...
    CryptoProviderFactory = new CryptoProviderFactory()
    {
        CacheSignatureProviders = false
    }
...
};
  1. Turn off caching of signature providers at the app level by adding this line to startup:
CryptoProviderFactory.DefaultCacheSignatureProviders = false;

@GeoK GeoK self-assigned this Jun 4, 2020
@GeoK GeoK added the Question User has asked a question label Jun 4, 2020
@vlkchris
Copy link

vlkchris commented Jun 4, 2020

Hi George,

Thank you for this explanation and te proposed workarounds.
I was already working with solution 1 and that is working fine, but I was worried about not disposing the object. Lots of examples on RSA contain a using statement, so I assumed that not disposing would be a bad idea.
Can you elaborate a bit on how this provider caching works? Am I right in assuming that these cached entries will never expire? I would prefer that cached entries would expire after not being used for a configured amount of time.

Thanks,
Chris

@brentschmaltz brentschmaltz added the Customer reported Indicates issue was opened by customer label Jun 5, 2020
@GeoK
Copy link
Member

GeoK commented Jun 12, 2020

@vlkchris - Apologies for the delay in getting a response to you.

Crypto provider caching is introduced as a feature in 5.2.2 to improve perf in some of the hot paths.
In 5.5.0, caching of signature providers was enabled by default (#1129).

You are correct, cached entries will not expire by default and that is a great candidate for an improvement. I opened up a ticket #1447.

In the meantime, please use one of the workarounds described above.

@vlkchris
Copy link

@GeoK - No worries about the delay, there is no urgency on my side.
I am happy using workaround #1 for now, and if necessary I'll disable caching.
I'll be on the lookout for any development on this, subscribed to #1447

@brentschmaltz
Copy link
Member

@GeoK @Tratcher @vlkchris I am closing this as we are looking at this holistically in: #1434

ChadNedzlek added a commit to ChadNedzlek/arcade-services that referenced this issue May 4, 2022
It sounds like, based on
AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet#1433
that the default behavior sometimes changes to "true", which is basically
an alias for "destroy my process with no way out"

So lets override the caching behavior to be false and see if that helps
ChadNedzlek added a commit to dotnet/arcade-services that referenced this issue May 4, 2022
…ice (#1882)

It sounds like, based on
AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet#1433
that the default behavior sometimes changes to "true", which is basically
an alias for "destroy my process with no way out"

So lets override the caching behavior to be false and see if that helps
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Customer reported Indicates issue was opened by customer Question User has asked a question
Projects
None yet
Development

No branches or pull requests

4 participants