/// <summary> /// Validates that the signature, if found and / or required is valid. /// </summary> /// <param name="token">A 'JSON Web Token' (JWT) that has been encoded as a JSON object. May be signed /// using 'JSON Web Signature' (JWS).</param> /// <param name="validationParameters"><see cref="TokenValidationParameters"/> that contains signing keys.</param> /// <exception cref="ArgumentNullException"> thrown if 'token is null or whitespace.</exception> /// <exception cref="ArgumentNullException"> thrown if 'validationParameters is null.</exception> /// <exception cref="SecurityTokenValidationException"> thrown if a signature is not found and <see cref="TokenValidationParameters.RequireSignedTokens"/> is true.</exception> /// <exception cref="SecurityTokenSignatureKeyNotFoundException"> thrown if the 'token' has a key identifier and none of the <see cref="SecurityKey"/>(s) provided result in a validated signature. /// This can indicate that a key refresh is required.</exception> /// <exception cref="SignatureVerificationFailedException"> thrown if after trying all the <see cref="SecurityKey"/>(s), none result in a validated signture AND the 'token' does not have a key identifier.</exception> /// <returns><see cref="JwtSecurityToken"/> that has the signature validated if token was signed and <see cref="TokenValidationParameters.RequireSignedTokens"/> is true.</returns> /// <remarks><para>If the 'token' is signed, the signature is validated even if <see cref="TokenValidationParameters.RequireSignedTokens"/> is false.</para> /// <para>If the 'token' signature is validated, then the <see cref="JwtSecurityToken.SigningKey"/> will be set to the key that signed the 'token'.</para></remarks> protected virtual JwtSecurityToken ValidateSignature(string token, TokenValidationParameters validationParameters) { if (string.IsNullOrWhiteSpace(token)) { throw new ArgumentNullException("token"); } if (validationParameters == null) { throw new ArgumentNullException("validationParameters"); } JwtSecurityToken jwt = this.ReadToken(token) as JwtSecurityToken; byte[] encodedBytes = Encoding.UTF8.GetBytes(jwt.RawHeader + "." + jwt.RawPayload); byte[] signatureBytes = Base64UrlEncoder.DecodeBytes(jwt.RawSignature); if (signatureBytes == null) { throw new ArgumentNullException("signatureBytes"); } if (signatureBytes.Length == 0) { if (!validationParameters.RequireSignedTokens) { return jwt; } throw new SecurityTokenValidationException(string.Format(CultureInfo.InvariantCulture, ErrorMessages.IDX10504, jwt.ToString())); } string mappedAlgorithm = jwt.Header.Alg; if (mappedAlgorithm != null && InboundAlgorithmMap.ContainsKey(mappedAlgorithm)) { mappedAlgorithm = InboundAlgorithmMap[mappedAlgorithm]; } SecurityKeyIdentifier ski = jwt.Header.SigningKeyIdentifier; // if a securityKeyIdentifier exists, look for match. if (ski.Count > 0) { SecurityKey securityKey = null; if (validationParameters.IssuerSigningKeyResolver != null) { securityKey = validationParameters.IssuerSigningKeyResolver(token, jwt, ski, validationParameters); if (securityKey == null) { throw new SecurityTokenSignatureKeyNotFoundException(string.Format(CultureInfo.InvariantCulture, ErrorMessages.IDX10505, ski, jwt.ToString())); } } else { securityKey = ResolveIssuerSigningKey(token, jwt, ski, validationParameters); if (securityKey == null) { throw new SecurityTokenSignatureKeyNotFoundException(string.Format(CultureInfo.InvariantCulture, ErrorMessages.IDX10500, ski, jwt.ToString())); } } try { if (this.ValidateSignature(encodedBytes, signatureBytes, securityKey, mappedAlgorithm)) { jwt.SigningKey = securityKey; return jwt; } } catch (Exception ex) { throw new SignatureVerificationFailedException(string.Format(CultureInfo.InvariantCulture, ErrorMessages.IDX10502, CreateKeyString(securityKey), ex.ToString(), jwt.ToString()), ex); } throw new SignatureVerificationFailedException(string.Format(CultureInfo.InvariantCulture, ErrorMessages.IDX10501, CreateKeyString(securityKey), jwt.ToString())); } else { Exception firstException = null; StringBuilder exceptionStrings = new StringBuilder(); StringBuilder keysAttempted = new StringBuilder(); // Try all keys since there is no keyidentifier foreach (SecurityKey securityKey in GetAllKeys(token, jwt, ski, validationParameters)) { try { if (this.ValidateSignature(encodedBytes, signatureBytes, securityKey, mappedAlgorithm)) { jwt.SigningKey = securityKey; return jwt; } } catch (Exception ex) { if (DiagnosticUtility.IsFatal(ex)) { throw; } if (firstException == null) { firstException = ex; } exceptionStrings.AppendLine(ex.ToString()); } keysAttempted.AppendLine(CreateKeyString(securityKey)); } throw new SignatureVerificationFailedException(string.Format(CultureInfo.InvariantCulture, ErrorMessages.IDX10503, keysAttempted.ToString(), exceptionStrings.ToString(), jwt.ToString()), firstException); } }
private IEnumerable<SecurityKey> GetAllKeys(string token, SecurityToken securityToken, SecurityKeyIdentifier keyIdentifier, TokenValidationParameters validationParameters) { // gets keys from metadata if (validationParameters.IssuerSigningKeyResolver != null) { yield return validationParameters.IssuerSigningKeyResolver(token, securityToken, keyIdentifier, validationParameters); } else { if (validationParameters.IssuerSigningKey != null) yield return validationParameters.IssuerSigningKey; if (validationParameters.IssuerSigningKeys != null) foreach (SecurityKey securityKey in validationParameters.IssuerSigningKeys) yield return securityKey; if (validationParameters.IssuerSigningToken != null) foreach (SecurityKey k in validationParameters.IssuerSigningToken.SecurityKeys) yield return k; if (validationParameters.IssuerSigningTokens != null) foreach (SecurityToken t in validationParameters.IssuerSigningTokens) foreach (SecurityKey securityKey in t.SecurityKeys) yield return securityKey; } }