2017-12-06 607 views
0

JsonWebTokenFormat 나는 JWT 토큰을 만들고이를 X.509 RSA SSH 256 인증서로 서명하는 클래스가 있습니다.EncryptValue에서 JwtSecurityTokenHandler NotSupportedException

internal class JsonWebTokenFormat : ISecureDataFormat<AuthenticationTicket> 
{ 
    private readonly string _issuer; 
    private readonly ICertificateStore _store; 

    public JsonWebTokenFormat(string issuer, ICertificateStore store) 
    { 
     _issuer = issuer; 
     _store = store; 
    } 

    public string Protect(AuthenticationTicket data) 
    { 
     if (data == null) 
     { 
      throw new ArgumentNullException("data"); 
     } 

     RSA rsaPrivateKey = _store.GetCurrentUserPrivateCertificate(_issuer); 

     SigningCredentials signingCredentials = new SigningCredentials(new RsaSecurityKey(rsaPrivateKey), SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest); 

     DateTimeOffset? issued = data.Properties.IssuedUtc; 
     DateTimeOffset? expires = data.Properties.ExpiresUtc; 

     JwtSecurityToken jwtSecurityToken = new JwtSecurityToken(
      issuer: _issuer, 
      claims: data.Identity.Claims, 
      notBefore: issued.Value.UtcDateTime, 
      expires: expires.Value.UtcDateTime, 
      signingCredentials: signingCredentials); 
     JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler(); 
     string jwtAuthToken = jwtSecurityTokenHandler.WriteToken(jwtSecurityToken); 

     return jwtAuthToken; 
    } 

    public AuthenticationTicket Unprotect(string jwtToken) 
    { 
     // read the issuer from the token 
     JwtSecurityToken jwtSecurityToken = new JwtSecurityToken(jwtToken); 
     RSA rsaPublicKey = _store.GetPublicCertificateForClient(jwtSecurityToken.Issuer); 

     TokenValidationParameters tokenValidationParams = new TokenValidationParameters 
     { 
      ValidIssuer = _issuer, 
      RequireExpirationTime = true, 
      ValidateIssuer = true, 
      RequireSignedTokens = true, 
      ValidateLifetime = true, 
      ValidateAudience = false, 
      IssuerSigningKey = new RsaSecurityKey(rsaPublicKey), 
      ValidateIssuerSigningKey = true 
     }; 

     JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler(); 
     SecurityToken tempToken; 
     ClaimsPrincipal principal = jwtSecurityTokenHandler.ValidateToken(jwtToken, tokenValidationParams, out tempToken); 

     AuthenticationTicket authenticationTicket = new AuthenticationTicket(new ClaimsIdentity(principal.Identity), new AuthenticationProperties()); 

     return authenticationTicket; 
    } 
} 

그리고 ICertificateStore 구현은 다음과 같습니다

class MockCertificateStore : ICertificateStore 
{ 
    private readonly X509Certificate2 _certificate; 

    public MockCertificateStore() 
    { 
     _certificate = new X509Certificate2(
       @"C:\certs\test-client.pfx", 
       "12345", 
       X509KeyStorageFlags.MachineKeySet | 
       X509KeyStorageFlags.Exportable); 
    } 

    public RSA GetCurrentUserPrivateCertificate(string subject) 
    { 
     return _certificate.GetRSAPrivateKey(); 
    } 

    public RSA GetPublicCertificateForClient(string clientId) 
    { 
     return _certificate.GetRSAPublicKey(); 
    } 
} 

그래서이 클래스를 테스트하는이 단위 테스트를 가지고 내 로컬 컴퓨터 (및 다른 개발자 로컬 시스템)하지만, 그것을 잘 작동 Jenkins 빌드 환경에서 실패합니다.

그것은 다음과 같은 예외와 함께 실패합니다

Test method AuthCore.Tests.Token.JsonWebTokenFormatTests.EnsureProtectGeneratesCorrectAuthToken threw exception: 
System.NotSupportedException: Method is not supported. 
Stack Trace: 
    at System.Security.Cryptography.RSA.DecryptValue(Byte[] rgb) 
    at System.Security.Cryptography.RSAPKCS1SignatureFormatter.CreateSignature(Byte[] rgbHash) 
    at System.IdentityModel.Tokens.AsymmetricSignatureProvider.Sign(Byte[] input) in c:\workspace\WilsonForDotNet45Release\src\System.IdentityModel.Tokens.Jwt\AsymmetricSignatureProvider.cs:line 224 
    at System.IdentityModel.Tokens.JwtSecurityTokenHandler.CreateSignature(String inputString, SecurityKey key, String algorithm, SignatureProvider signatureProvider) in c:\workspace\WilsonForDotNet45Release\src\System.IdentityModel.Tokens.Jwt\JwtSecurityTokenHandler.cs:line 854 
    at System.IdentityModel.Tokens.JwtSecurityTokenHandler.WriteToken(SecurityToken token) in c:\workspace\WilsonForDotNet45Release\src\System.IdentityModel.Tokens.Jwt\JwtSecurityTokenHandler.cs:line 815 
    at AuthCore.Token.JsonWebTokenFormat.Protect(AuthenticationTicket data) in C:\Jenkins\workspace\AuthCore\Token\JsonWebTokenFormat.cs:line 38 
    at AuthCore.Tests.Token.JsonWebTokenFormatTests.EnsureProtectGeneratesCorrectAuthToken() in C:\Jenkins\workspace\AuthCore.Tests\Token\JsonWebTokenFormatTests.cs:line 34 

어떤 도움에 감사드립니다. 나는 많은 질문을 보았고 그들 중 누구도 도왔다.

+0

그러나 당신은 당신의 빌드 환경에 대해 아무것도 언급하지 않았다. OS, .net 버전 등등. – Evk

답변

0

해결!

RsaSecurityKey 클래스는 .NET 4.6.0부터 사용되지 않으므로 문제가 발생했습니다. 어떤 이유로이 클래스는 이전 버전의 .NET이 설치되어 있지 않은 컴퓨터에서 사용될 때 던지고 있지만 이전 버전의 .NET이 설치된 컴퓨터에서는 문제가되지 않습니다. 대신 X509SecurityKey 클래스를 사용하십시오.

잠재적 인 솔루션의 다음 문서를 참조하십시오 https://q-a-assistant.com/computer-internet-technology/338482_jwt-generation-and-validation-in-net-throws-key-is-not-supported.html

static string GenerateToken() 
{ 
    var tokenHandler = new JwtSecurityTokenHandler(); 
    var certificate = new X509Certificate2(@"Test.pfx", "123"); 
    var securityKey = new X509SecurityKey(certificate); 

    var tokenDescriptor = new SecurityTokenDescriptor 
    { 
     Subject = new ClaimsIdentity(), 
     Issuer = "Self", 
     IssuedAt = DateTime.Now, 
     Audience = "Others", 
     Expires = DateTime.MaxValue, 
     SigningCredentials = new SigningCredentials(
      securityKey, 
      SecurityAlgorithms.RsaSha256Signature) 
    }; 

    var token = tokenHandler.CreateToken(tokenDescriptor); 
    return tokenHandler.WriteToken(token); 
} 

static bool ValidateToken(string token) 
{ 
    var tokenHandler = new JwtSecurityTokenHandler(); 
    var certificate = new X509Certificate2(@"Test.cer"); 
    var securityKey = new X509SecurityKey(certificate); 

    var validationParameters = new TokenValidationParameters 
    { 
     ValidAudience = "Others", 
     ValidIssuer = "Self", 
     IssuerSigningKey = securityKey 
    }; 

    var principal = tokenHandler.ValidateToken(token, validationParameters, out SecurityToken securityToken); 
    if (principal == null) 
     return false; 
    if (securityToken == null) 
     return false; 

    return true; 
}