public void ValidateToken_FailsOnLifetime() { string token = "eyJhbGciOiJSUzI1NiIsImtpZCI6ImxlZ2FjeS10b2tlbi1rZXkiLCJ0eXAiOiJKV1QifQ.eyJqdGkiOiI0YjM2NmY4MDdlMjU0MzlmYmRkOTEwZDc4ZjcwYzlhMSIsInN1YiI6ImZlNmExYmUyLWM5MTEtNDM3OC05Y2MxLTVhY2Y1NjA1Y2ZjMiIsInNjb3BlIjpbImNsb3VkX2NvbnRyb2xsZXIucmVhZCIsImNsb3VkX2NvbnRyb2xsZXJfc2VydmljZV9wZXJtaXNzaW9ucy5yZWFkIiwidGVzdGdyb3VwIiwib3BlbmlkIl0sImNsaWVudF9pZCI6Im15VGVzdEFwcCIsImNpZCI6Im15VGVzdEFwcCIsImF6cCI6Im15VGVzdEFwcCIsImdyYW50X3R5cGUiOiJhdXRob3JpemF0aW9uX2NvZGUiLCJ1c2VyX2lkIjoiZmU2YTFiZTItYzkxMS00Mzc4LTljYzEtNWFjZjU2MDVjZmMyIiwib3JpZ2luIjoidWFhIiwidXNlcl9uYW1lIjoiZGF2ZSIsImVtYWlsIjoiZGF2ZSIsImF1dGhfdGltZSI6MTQ3MzYxNTU0MSwicmV2X3NpZyI6IjEwZDM1NzEyIiwiaWF0IjoxNDczNjI0MjU1LCJleHAiOjE0NzM2Njc0NTUsImlzcyI6Imh0dHBzOi8vdWFhLnN5c3RlbS50ZXN0Y2xvdWQuY29tL29hdXRoL3Rva2VuIiwiemlkIjoidWFhIiwiYXVkIjpbImNsb3VkX2NvbnRyb2xsZXIiLCJteVRlc3RBcHAiLCJvcGVuaWQiLCJjbG91ZF9jb250cm9sbGVyX3NlcnZpY2VfcGVybWlzc2lvbnMiXX0.Hth_SXpMAyiTf--U75r40qODlSUr60U730IW28K2VidEltW3lN3_CE7HkSjolRGr-DYuWHRvy3i_EwBfj1WTkBaXL373UzPVvNBnat9Gi-vjz07LwmBohk3baG1mmlL8IoGbQwtsmfUPhmO5C6_M4s9wKmTf9XIZPVo_w7zPJadrXfHLfx6iQob7CYpTTix2VBWya29iL7kmD1J1UDT5YRg2J9XT30iFuL6BvPQTkuGnX3ivDuUOSdxM8Z451i0VJmc0LYFBCLJ-Tz6bJ2d0wrtfsbCfuNtxjmGJevcL2jKQbEoiliYj60qNtZdT-ijGUdZjE9caxQ2nOkDkowacpw"; string keyset = "{ 'keys':[{'kid':'legacy-token-key','alg':'SHA256withRSA','value':'-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk+7xH35bYBppsn54cBW+\nFlrveTe+3L4xl7ix13XK8eBcCmNOyBhNzhks6toDiRjrgw5QW76cFirVRFIVQkiZ\nsUwDyGOax3q8NOJyBFXiplIUScrx8aI0jkY/Yd6ixAc5yBSBfXThy4EF9T0xCyt4\nxWLYNXMRwe88Y+i+MEoLNXWRbhjJm76LN7rsdIxALbS0vJNWUDALWjtE6FeYX6uU\nL9msAzlCQkdnSvwMmr8Ij2O3IVMxHDJXOZinFqt9zVfXwO11o7ZmiskZnRz1/V0f\nvbUQAadkcDEUt1gk9cbrAhiipg8VWDMsC7VUXuekJZjme5f8oWTwpsgP6cTUzwSS\n6wIDAQAB\n-----END PUBLIC KEY-----','kty':'RSA','use':'sig','n':'AJPu8R9+W2AaabJ+eHAVvhZa73k3vty+MZe4sdd1yvHgXApjTsgYTc4ZLOraA4kY64MOUFu+nBYq1URSFUJImbFMA8hjmsd6vDTicgRV4qZSFEnK8fGiNI5GP2HeosQHOcgUgX104cuBBfU9MQsreMVi2DVzEcHvPGPovjBKCzV1kW4YyZu+ize67HSMQC20tLyTVlAwC1o7ROhXmF+rlC/ZrAM5QkJHZ0r8DJq/CI9jtyFTMRwyVzmYpxarfc1X18DtdaO2ZorJGZ0c9f1dH721EAGnZHAxFLdYJPXG6wIYoqYPFVgzLAu1VF7npCWY5nuX/KFk8KbID+nE1M8Ekus=','e':'AQAB'}]}"; var keys = JsonWebKeySet.Create(keyset); var webKey = keys.Keys[0]; var parameters = new TokenValidationParameters(); CloudFoundryOptions options = new CloudFoundryOptions(); options.TokenKeyResolver = new CloudFoundryTokenKeyResolver(options); options.TokenValidator = new CloudFoundryTokenValidator(options); options.TokenValidationParameters = parameters; options.TokenKeyResolver.FixupKey(webKey); options.TokenKeyResolver.Resolved["legacy-token-key"] = webKey; parameters.ValidateAudience = false; parameters.ValidateIssuer = false; parameters.ValidateLifetime = true; parameters.IssuerSigningKeyResolver = options.TokenKeyResolver.ResolveSigningKey; var result = options.TokenValidator.ValidateToken(token); Assert.False(result); }
public override async Task ValidateAsync([NotNull] AppleValidateIdTokenContext context) { if (!_tokenHandler.CanValidateToken) { throw new NotSupportedException($"The configured {nameof(JwtSecurityTokenHandler)} cannot validate tokens."); } byte[] keysJson = await _keyStore.LoadPublicKeysAsync(context); string json = Encoding.UTF8.GetString(keysJson); var keySet = JsonWebKeySet.Create(json); var parameters = new TokenValidationParameters() { ValidAudience = context.Options.ClientId, ValidIssuer = context.Options.TokenAudience, IssuerSigningKeys = keySet.Keys, }; try { _tokenHandler.ValidateToken(context.IdToken, parameters, out var _); } catch (Exception ex) { _logger.LogError( ex, "Apple ID token validation failed for issuer {TokenIssuer} and audience {TokenAudience}. ID Token: {IdToken}", parameters.ValidAudience, parameters.ValidIssuer, context.IdToken); throw; } }
public void SuccessfulTokenValidationFromMetadata() { GrantedTokenResponse tokenResponse = null !; JsonWebKeySet jwks = null !; "And a valid token".x( async() => { var tokenClient = new TokenClient( TokenCredentials.FromClientCredentials("clientCredentials", "clientCredentials"), Fixture.Client, new Uri(WellKnownOpenidConfiguration)); var response = await tokenClient.GetToken(TokenRequest.FromScopes("api1")).ConfigureAwait(false) as Option <GrantedTokenResponse> .Result; Assert.NotNull(response); tokenResponse = response.Item; }); "then can download json web key set".x( async() => { var jwksJson = await Fixture.Client().GetStringAsync(BaseUrl + "/jwks").ConfigureAwait(false); Assert.NotNull(jwksJson); jwks = JsonWebKeySet.Create(jwksJson); }); "Then can create token validation parameters from service metadata".x( () => { var validationParameters = new TokenValidationParameters { IssuerSigningKeys = jwks.Keys, ValidIssuer = "https://localhost", ValidAudience = "clientCredentials" }; var handler = new JwtSecurityTokenHandler(); handler.ValidateToken(tokenResponse.AccessToken, validationParameters, out var securityToken); Assert.NotNull(securityToken); }); }
static async Task <JwtSecurityToken> DecodeJwtTokenAsync(HttpClient httpClient, string token) { // the first step is to validate the id_token before we can trust it // but validation requires the public signing key which can be downloaded // from a well-known location on the GrowthZone server var signingKeys = JsonWebKeySet.Create(await httpClient.GetStringAsync("openid/well-known/jwks")).GetSigningKeys(); var validationParameters = new TokenValidationParameters { ValidateAudience = true, ValidAudience = GrowthZoneClient.ClientId, ValidateIssuer = true, ValidIssuer = GrowthZoneClient.Host + "/", ValidateIssuerSigningKey = true, IssuerSigningKey = signingKeys[0] }; // if the validation has passes without throwing an exception then we can // trust that the token is from GrowthZone and hasnt been tampered with new JwtSecurityTokenHandler().ValidateToken(token, validationParameters, out var securityToken); return(securityToken as JwtSecurityToken); }
private void AddAuthentication(IServiceCollection services) { HttpDocumentRetriever documentRetriever = new HttpDocumentRetriever() { RequireHttps = false }; JsonWebKeySet keySet = JsonWebKeySet.Create( documentRetriever.GetDocumentAsync(Configuration["JwkAddress"], new System.Threading.CancellationToken()).Result ); services.AddAuthentication(o => { o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer("BrassLoon", o => { o.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters { ValidateAudience = true, ValidateIssuer = true, ValidateIssuerSigningKey = true, ValidateLifetime = true, ValidateActor = false, ValidateTokenReplay = false, RequireAudience = false, RequireExpirationTime = true, RequireSignedTokens = true, ValidAudience = Configuration["Issuer"], ValidIssuer = Configuration["Issuer"], IssuerSigningKey = keySet.Keys[0] }; o.IncludeErrorDetails = true; }) ; }
public void JWE_CreateAndDecrypt() { // create JWKS var jsonWebKeySet = JsonWebKeySet.Create(Jwks); // ENCRYPTION // Find first encryption key - todo ignore invalid var encKey = jsonWebKeySet.Keys.First(k => k.Use == "enc"); // Build the RSA public key from the JWK properties. Ripe for extension method using var rsaEncKey = RSA.Create(); var rsaPublicKeyParams = new RSAParameters { Modulus = Base64UrlEncoder.DecodeBytes(encKey.N), Exponent = Base64UrlEncoder.DecodeBytes(encKey.E), }; rsaEncKey.ImportParameters(rsaPublicKeyParams); var rsaPublicKey = new RsaSecurityKey(rsaEncKey) { KeyId = encKey.KeyId }; // create a signed, encrypted JWE var tokenHandler = new JwtSecurityTokenHandler(); var tokenDescriptor = new SecurityTokenDescriptor { Claims = new Dictionary <string, object> { { "foo", 123 } }, SigningCredentials = new SigningCredentials(jsonWebKeySet.GetSigningKeys().First(), SecurityAlgorithms.RsaSsaPssSha512), EncryptingCredentials = new EncryptingCredentials(rsaPublicKey, SecurityAlgorithms.RsaOaepKeyWrap, SecurityAlgorithms.Aes256CbcHmacSha512) }; var token = tokenHandler.CreateEncodedJwt(tokenDescriptor); // DECRYPTION (token validation) // Now decrypt using private key using var rsaDecKey = RSA.Create(); var rsaPrivateKeyParams = new RSAParameters { P = Base64UrlEncoder.DecodeBytes(encKey.P), Q = Base64UrlEncoder.DecodeBytes(encKey.Q), D = Base64UrlEncoder.DecodeBytes(encKey.D), DP = Base64UrlEncoder.DecodeBytes(encKey.DP), DQ = Base64UrlEncoder.DecodeBytes(encKey.DQ), InverseQ = Base64UrlEncoder.DecodeBytes(encKey.QI), Exponent = Base64UrlEncoder.DecodeBytes(encKey.E), Modulus = Base64UrlEncoder.DecodeBytes(encKey.N), }; rsaDecKey.ImportParameters(rsaPrivateKeyParams); var rsaPrivateKey = new RsaSecurityKey(rsaDecKey); var tokenValidationParams = new TokenValidationParameters { ValidateAudience = false, // validate sig ValidateIssuer = false, // validate sig RequireSignedTokens = true, IssuerSigningKeys = jsonWebKeySet.GetSigningKeys(), TokenDecryptionKey = rsaPrivateKey }; var claimsPrincipal = tokenHandler.ValidateToken(token, tokenValidationParams, out var securityToken); // the encryption and signing should be as expected Assert.Equal("encryptor", ((JwtSecurityToken)securityToken).Header.Kid); Assert.Equal("signatory", ((JwtSecurityToken)securityToken).InnerToken.Header.Kid); // claims are in the securityToken as well but claimsPrincipal is a more common object to interrogate Assert.Equal("123", claimsPrincipal.Claims.First(c => c.Type == "foo").Value); }
public virtual JsonWebKeySet GetJsonWebKeySet(string json) { return(JsonWebKeySet.Create(json)); }