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

JWTBearer.CreateToken with TokenSigningStyle.Asymmetric throws ObjectDisposedException #372

Closed
Want100Cookies opened this issue Feb 3, 2023 · 1 comment
Labels
bug Something isn't working fixed the bug has been squashed

Comments

@Want100Cookies
Copy link

I was trying out the Asymmetric signing style with FastEndpoints and ran into the following bug.

System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'RSACng'.
   at System.Security.Cryptography.CngAlgorithmCore.ThrowIfDisposed()
   at System.Security.Cryptography.CngAlgorithmCore.GetOrGenerateKey(Int32 keySize, CngAlgorithm algorithm)
   at System.Security.Cryptography.RSACng.get_Key()
   at System.Security.Cryptography.RSACng.ExportKeyBlob(Boolean includePrivateParameters)
   at System.Security.Cryptography.RSACng.ExportParameters(Boolean includePrivateParameters)
   at Microsoft.IdentityModel.Tokens.RsaSecurityKey.ComputeJwkThumbprint()
   at Microsoft.IdentityModel.Tokens.SecurityKey.<SetInternalId>b__19_0()
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy`1.CreateValue()
   at Microsoft.IdentityModel.Tokens.SecurityKey.get_InternalId()
   at Microsoft.IdentityModel.Tokens.InMemoryCryptoProviderCache.GetCacheKeyPrivate(SecurityKey securityKey, String algorithm, String typeofProvider)
   at Microsoft.IdentityModel.Tokens.InMemoryCryptoProviderCache.TryGetSignatureProvider(SecurityKey securityKey, String algorithm, String typeofProvider, Boolean willCreateSignatures, SignatureProvider& signatureProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForSigning(SecurityKey key, String algorithm, Boolean cacheProvider)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForSigning(SecurityKey key, String algorithm)
   at Microsoft.IdentityModel.JsonWebTokens.JwtTokenUtilities.CreateEncodedSignature(String input, SigningCredentials signingCredentials)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.CreateJwtSecurityTokenPrivate(String issuer, String audience, ClaimsIdentity subject, Nullable`1 notBefore, Nullable`1 expires, Nullable`1 issuedAt, SigningCredentials signingCredentials, EncryptingCredentials encryptingCredentials, IDictionary`2 claimCollection, String tokenType)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.CreateToken(SecurityTokenDescriptor tokenDescriptor)
   at FastEndpoints.Security.JWTBearer.CreateToken(String signingKey, Nullable`1 expireAt, IEnumerable`1 permissions, IEnumerable`1 roles, IEnumerable`1 claims, String issuer, String audience, TokenSigningStyle signingStyle)
   at FastEndpoints.Security.JWTBearer.CreateToken(String signingKey, TokenSigningStyle signingStyle, String issuer, String audience, Nullable`1 expireAt, IEnumerable`1 permissions, IEnumerable`1 roles, ValueTuple`2[] claims)
   at GrafanaDemo.LoginEndpoint.HandleAsync(LoginEndpointRequest req, CancellationToken ct) in C:\data\grafana-demo\GrafanaDemo\LoginEndpoint.cs:line 16
   at FastEndpoints.Endpoint`2.ExecAsync(CancellationToken ct)
   at FastEndpoints.Endpoint`2.ExecAsync(CancellationToken ct)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

It is thrown in a simple LoginEndpoint:

string token = JWTBearer.CreateToken(
	await File.ReadAllTextAsync("rsa.key", ct),
	JWTBearer.TokenSigningStyle.Asymmetric,
	expireAt: DateTime.UtcNow + TimeSpan.FromDays(1),
	claims: new[]
	{
		(JwtRegisteredClaimNames.Sub, "the_username"),
		(JwtRegisteredClaimNames.Name, "The User"),
		(JwtRegisteredClaimNames.Email, "the_user@example.com")
	},
	roles: new[]
	{
		"Admin"
	});

I generated the keys with:

if (!File.Exists("rsa.key"))
{
	using RSA rsa = RSA.Create(2048);

	File.WriteAllText("rsa.key", Convert.ToBase64String(rsa.ExportRSAPrivateKey()));
	File.WriteAllText("rsa.pub", Convert.ToBase64String(rsa.ExportRSAPublicKey()));
}

I thought it could be related to a using here:

using var rsa = RSA.Create();

I tried inlining the GetSigningCredentials function in the CreateToken function above it and moved the using outside the if statement but the exception persisted. Then I just remove the using statement completely and my code worked fine.

Is this a bug in FastEndpoints or in the dotnet libraries?

Relevant software:
FastEndpoints: 5.7.0
dotnet --version: 7.0.102

@dj-nitehawk
Copy link
Member

so yeah... even though it's an IDisposable, looks like we're not meant to dispose it in this context.
fixed in v5.7.0.2-beta

@dj-nitehawk dj-nitehawk added bug Something isn't working fixed the bug has been squashed labels Feb 3, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working fixed the bug has been squashed
Development

No branches or pull requests

2 participants