/// <summary>
        /// Returns all <see cref="SecurityKey"/> to use when validating the signature of a token.
        /// </summary>
        /// <param name="token">The <see cref="string"/> representation of the token that is being validated.</param>
        /// <param name="samlToken">The <see cref="SecurityToken"/> that is being validated.</param>
        /// <param name="tokenKeyInfo">The <see cref="KeyInfo"/> field of the token being validated</param>
        /// <param name="validationParameters">A <see cref="TokenValidationParameters"/> required for validation.</param>
        /// <param name="keyMatched">A <see cref="bool"/> to represent if a a issuer signing key matched with token kid or x5t</param>
        /// <returns>Returns all <see cref="SecurityKey"/> to use for signature validation.</returns>
        internal static IEnumerable <SecurityKey> GetKeysForTokenSignatureValidation(string token, SecurityToken samlToken, KeyInfo tokenKeyInfo, TokenValidationParameters validationParameters, out bool keyMatched)
        {
            keyMatched = false;

            if (validationParameters.IssuerSigningKeyResolver != null)
            {
                return(validationParameters.IssuerSigningKeyResolver(token, samlToken, tokenKeyInfo?.Id, validationParameters));
            }
            else
            {
                SecurityKey key = ResolveTokenSigningKey(tokenKeyInfo, validationParameters);

                if (key != null)
                {
                    keyMatched = true;
                    return(new List <SecurityKey> {
                        key
                    });
                }
                else
                {
                    keyMatched = false;
                    if (validationParameters.TryAllIssuerSigningKeys)
                    {
                        return(TokenUtilities.GetAllSigningKeys(validationParameters));
                    }
                }
            }
            return(null);
        }
示例#2
0
        protected virtual IEnumerable <SecurityKey> GetSigningKeys(string token, TokenValidationParameters validationParameters)
        {
            List <SecurityKey> keys = null;

            if (validationParameters.IssuerSigningKeyResolver != null)
            {
                keys = validationParameters.IssuerSigningKeyResolver(token, null, null, validationParameters)?.ToList();
            }

            if (keys == null || !keys.Any())
            {
                keys = new List <SecurityKey>();
                if (validationParameters.IssuerSigningKey != null)
                {
                    keys.Add(validationParameters.IssuerSigningKey);
                }
                if (validationParameters.IssuerSigningKeys != null && validationParameters.IssuerSigningKeys.Any())
                {
                    keys.AddRange(validationParameters.IssuerSigningKeys);
                }
            }

            return(keys);
        }
        /// <summary>
        /// Validates the JWT signature.
        /// </summary>
        private JsonWebToken ValidateSignature(string token, TokenValidationParameters validationParameters)
        {
            if (string.IsNullOrWhiteSpace(token))
            {
                throw LogHelper.LogArgumentNullException(nameof(token));
            }

            if (validationParameters == null)
            {
                throw LogHelper.LogArgumentNullException(nameof(validationParameters));
            }

            if (validationParameters.SignatureValidator != null)
            {
                var validatedToken = validationParameters.SignatureValidator(token, validationParameters);
                if (validatedToken == null)
                {
                    throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidSignatureException(LogHelper.FormatInvariant(TokenLogMessages.IDX10505, token)));
                }

                var validatedJsonWebToken = validatedToken as JsonWebToken;
                if (validatedJsonWebToken == null)
                {
                    throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidSignatureException(LogHelper.FormatInvariant(TokenLogMessages.IDX10506, typeof(JsonWebToken), validatedJsonWebToken.GetType(), token)));
                }

                return(validatedJsonWebToken);
            }

            JsonWebToken jwtToken = null;

            if (validationParameters.TokenReader != null)
            {
                var securityToken = validationParameters.TokenReader(token, validationParameters);
                if (securityToken == null)
                {
                    throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidSignatureException(LogHelper.FormatInvariant(TokenLogMessages.IDX10510, token)));
                }

                jwtToken = securityToken as JsonWebToken;
                if (jwtToken == null)
                {
                    throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidSignatureException(LogHelper.FormatInvariant(TokenLogMessages.IDX10509, typeof(JsonWebToken), securityToken.GetType(), token)));
                }
            }
            else
            {
                jwtToken = new JsonWebToken(token);
            }

            string[] tokenParts = jwtToken.EncodedToken.Split(new char[] { '.' }, JwtConstants.MaxJwtSegmentCount + 1);

            byte[] encodedBytes = Encoding.UTF8.GetBytes(tokenParts[0] + "." + tokenParts[1]);
            if (string.IsNullOrEmpty(tokenParts[2]))
            {
                if (validationParameters.RequireSignedTokens)
                {
                    throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidSignatureException(LogHelper.FormatInvariant(TokenLogMessages.IDX10504, token)));
                }
                else
                {
                    return(jwtToken);
                }
            }

            bool kidMatched = false;
            IEnumerable <SecurityKey> keys = null;

            if (validationParameters.IssuerSigningKeyResolver != null)
            {
                keys = validationParameters.IssuerSigningKeyResolver(token, jwtToken, jwtToken.Kid, validationParameters);
            }
            else
            {
                var key = ResolveIssuerSigningKey(jwtToken, validationParameters);
                if (key != null)
                {
                    kidMatched = true;
                    keys       = new List <SecurityKey> {
                        key
                    };
                }
            }

            if (keys == null)
            {
                // control gets here if:
                // 1. User specified delegate: IssuerSigningKeyResolver returned null
                // 2. ResolveIssuerSigningKey returned null
                // Try all the keys. This is the degenerate case, not concerned about perf.
                keys = GetAllSigningKeys(token, validationParameters);
            }

            // keep track of exceptions thrown, keys that were tried
            var  exceptionStrings = new StringBuilder();
            var  keysAttempted    = new StringBuilder();
            bool kidExists        = !string.IsNullOrEmpty(jwtToken.Kid);

            byte[] signatureBytes;

            try
            {
                signatureBytes = Base64UrlEncoder.DecodeBytes(tokenParts[2]);
            }
            catch (FormatException e)
            {
                throw new SecurityTokenInvalidSignatureException(TokenLogMessages.IDX10508, e);
            }

            foreach (var key in keys)
            {
                try
                {
                    if (ValidateSignature(encodedBytes, signatureBytes, key, jwtToken.Alg, validationParameters))
                    {
                        LogHelper.LogInformation(TokenLogMessages.IDX10242, token);
                        jwtToken.SigningKey = key;
                        return(jwtToken);
                    }
                    ;
                }
                catch (Exception ex)
                {
                    exceptionStrings.AppendLine(ex.ToString());
                }

                if (key != null)
                {
                    keysAttempted.AppendLine(key.ToString() + " , KeyId: " + key.KeyId);
                    if (kidExists && !kidMatched && key.KeyId != null)
                    {
                        kidMatched = jwtToken.Kid.Equals(key.KeyId, key is X509SecurityKey ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
                    }
                }
            }

            if (kidExists)
            {
                if (kidMatched)
                {
                    throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidSignatureException(LogHelper.FormatInvariant(TokenLogMessages.IDX10511, keysAttempted, jwtToken.Kid, exceptionStrings, jwtToken)));
                }
                else
                {
                    throw LogHelper.LogExceptionMessage(new SecurityTokenSignatureKeyNotFoundException(LogHelper.FormatInvariant(TokenLogMessages.IDX10501, jwtToken.Kid, jwtToken)));
                }
            }
            else
            {
                if (keysAttempted.Length > 0)
                {
                    throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidSignatureException(LogHelper.FormatInvariant(TokenLogMessages.IDX10503, keysAttempted, exceptionStrings, jwtToken)));
                }
                else
                {
                    throw LogHelper.LogExceptionMessage(new SecurityTokenSignatureKeyNotFoundException(TokenLogMessages.IDX10500));
                }
            }
        }
        private bool ResolvesToSigningToken(SecurityKeyIdentifierClause keyIdentifierClause, out SecurityKey key, out SecurityToken token)
        {
            token = null;
            key   = null;
            CertMatcher certMatcher = null;

            // for SAML tokens the highest probability are certs, with RawData first
            X509RawDataKeyIdentifierClause rawCertKeyIdentifierClause = keyIdentifierClause as X509RawDataKeyIdentifierClause;

            if (rawCertKeyIdentifierClause != null)
            {
                certMatcher = rawCertKeyIdentifierClause.Matches;
            }
            else
            {
                X509SubjectKeyIdentifierClause subjectKeyIdentifierClause = keyIdentifierClause as X509SubjectKeyIdentifierClause;
                if (subjectKeyIdentifierClause != null)
                {
                    certMatcher = subjectKeyIdentifierClause.Matches;
                }
                else
                {
                    X509ThumbprintKeyIdentifierClause thumbprintKeyIdentifierClause = keyIdentifierClause as X509ThumbprintKeyIdentifierClause;
                    if (thumbprintKeyIdentifierClause != null)
                    {
                        certMatcher = thumbprintKeyIdentifierClause.Matches;
                    }
                    else
                    {
                        X509IssuerSerialKeyIdentifierClause issuerKeyIdentifierClause = keyIdentifierClause as X509IssuerSerialKeyIdentifierClause;
                        if (issuerKeyIdentifierClause != null)
                        {
                            certMatcher = issuerKeyIdentifierClause.Matches;
                        }
                    }
                }
            }

            if (_validationParameters.IssuerSigningKeyResolver != null)
            {
                key = _validationParameters.IssuerSigningKeyResolver(token: _securityToken, securityToken: null, keyIdentifier: new SecurityKeyIdentifier(keyIdentifierClause), validationParameters: _validationParameters);
                if (key != null)
                {
                    this.IsKeyMatched = true;
                }
            }

            if (_validationParameters.IssuerSigningKey != null)
            {
                if (Matches(keyIdentifierClause, _validationParameters.IssuerSigningKey, certMatcher, out token))
                {
                    key = _validationParameters.IssuerSigningKey;
                    this.IsKeyMatched = true;
                }
            }

            if (_validationParameters.IssuerSigningKeys != null)
            {
                foreach (SecurityKey securityKey in _validationParameters.IssuerSigningKeys)
                {
                    if (Matches(keyIdentifierClause, securityKey, certMatcher, out token))
                    {
                        key = securityKey;
                        this.IsKeyMatched = true;
                        break;
                    }
                }
            }

            if (_validationParameters.IssuerSigningToken != null)
            {
                if (_validationParameters.IssuerSigningToken.MatchesKeyIdentifierClause(keyIdentifierClause))
                {
                    token             = _validationParameters.IssuerSigningToken;
                    key               = token.SecurityKeys[0];
                    this.IsKeyMatched = true;
                }
            }

            if (_validationParameters.IssuerSigningTokens != null)
            {
                foreach (SecurityToken issuerToken in _validationParameters.IssuerSigningTokens)
                {
                    if (_validationParameters.IssuerSigningToken.MatchesKeyIdentifierClause(keyIdentifierClause))
                    {
                        token             = issuerToken;
                        key               = token.SecurityKeys[0];
                        this.IsKeyMatched = true;
                        break;
                    }
                }
            }

            return(this.IsKeyMatched);
        }