/// <summary> /// Validates the lifetime of a <see cref="SecurityToken"/>. /// </summary> /// <param name="notBefore">The 'notBefore' time found in the <see cref="SecurityToken"/>.</param> /// <param name="expires">The 'expiration' time found in the <see cref="SecurityToken"/>.</param> /// <param name="securityToken">The <see cref="SecurityToken"/> being validated.</param> /// <param name="validationParameters"><see cref="TokenValidationParameters"/> required for validation.</param> /// <exception cref="ArgumentNullException">If 'vaidationParameters' is null.</exception> /// <exception cref="SecurityTokenNoExpirationException">If 'expires.HasValue' is false and <see cref="TokenValidationParameters.RequireExpirationTime"/> is true.</exception> /// <exception cref="SecurityTokenInvalidLifetimeException">If 'notBefore' is > 'expires'.</exception> /// <exception cref="SecurityTokenNotYetValidException">If 'notBefore' is > DateTime.UtcNow.</exception> /// <exception cref="SecurityTokenExpiredException">If 'expires' is < DateTime.UtcNow.</exception> /// <remarks>All time comparisons apply <see cref="TokenValidationParameters.ClockSkew"/>.</remarks> public static void ValidateLifetime(DateTime?notBefore, DateTime?expires, SecurityToken securityToken, TokenValidationParameters validationParameters) { if (validationParameters == null) { throw LogHelper.LogArgumentNullException(nameof(validationParameters)); } if (validationParameters.LifetimeValidator != null) { if (!validationParameters.LifetimeValidator(notBefore, expires, securityToken, validationParameters)) { throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidLifetimeException(LogHelper.FormatInvariant(LogMessages.IDX10230, securityToken)) { NotBefore = notBefore, Expires = expires }); } return; } if (!validationParameters.ValidateLifetime) { LogHelper.LogInformation(LogMessages.IDX10238); return; } if (!expires.HasValue && validationParameters.RequireExpirationTime) { throw LogHelper.LogExceptionMessage(new SecurityTokenNoExpirationException(LogHelper.FormatInvariant(LogMessages.IDX10225, securityToken == null ? "null" : securityToken.GetType().ToString()))); } if (notBefore.HasValue && expires.HasValue && (notBefore.Value > expires.Value)) { throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidLifetimeException(LogHelper.FormatInvariant(LogMessages.IDX10224, notBefore.Value, expires.Value)) { NotBefore = notBefore, Expires = expires }); } DateTime utcNow = DateTime.UtcNow; if (notBefore.HasValue && (notBefore.Value > DateTimeUtil.Add(utcNow, validationParameters.ClockSkew))) { throw LogHelper.LogExceptionMessage(new SecurityTokenNotYetValidException(LogHelper.FormatInvariant(LogMessages.IDX10222, notBefore.Value, utcNow)) { NotBefore = notBefore.Value }); } if (expires.HasValue && (expires.Value < DateTimeUtil.Add(utcNow, validationParameters.ClockSkew.Negate()))) { throw LogHelper.LogExceptionMessage(new SecurityTokenExpiredException(LogHelper.FormatInvariant(LogMessages.IDX10223, expires.Value, utcNow)) { Expires = expires.Value }); } // if it reaches here, that means lifetime of the token is valid LogHelper.LogInformation(LogMessages.IDX10239); }
/// <summary> /// Reads and validates a well fromed Saml2 token. /// </summary> /// <param name="securityToken">A Saml2 token.</param> /// <param name="validationParameters">Contains data and information needed for validation.</param> /// <param name="validatedToken">The <see cref="SamlSecurityToken"/> that was validated.</param> /// <exception cref="ArgumentNullException">'securityToken' is null or whitespace.</exception> /// <exception cref="ArgumentNullException">'validationParameters' is null.</exception> /// <exception cref="ArgumentException">'securityToken.Length' > <see cref="MaximumTokenSizeInBytes"/>.</exception> /// <returns>A <see cref="ClaimsPrincipal"/> generated from the claims in the Saml2 securityToken.</returns> public virtual ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken) { validatedToken = null; if (string.IsNullOrWhiteSpace(securityToken)) { throw new ArgumentNullException("securityToken"); } if (validationParameters == null) { throw new ArgumentNullException("validationParameters"); } if (securityToken.Length > MaximumTokenSizeInBytes) { throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, ErrorMessages.IDX10209, securityToken.Length, MaximumTokenSizeInBytes)); } Saml2SecurityToken samlToken; using (StringReader sr = new StringReader(securityToken)) { using (XmlDictionaryReader reader = XmlDictionaryReader.CreateDictionaryReader(XmlReader.Create(sr))) { samlToken = (new Saml2Handler() { Configuration = new SecurityTokenHandlerConfiguration { IssuerTokenResolver = new SecurityKeyResolver(securityToken, validationParameters), MaxClockSkew = validationParameters.ClockSkew, ServiceTokenResolver = SecurityTokenResolver.CreateDefaultSecurityTokenResolver(validationParameters.ClientDecryptionTokens, true), } }).ReadToken(reader) as Saml2SecurityToken; } } if (samlToken.IssuerToken == null && validationParameters.RequireSignedTokens) { throw new SecurityTokenValidationException(ErrorMessages.IDX10213); } if (samlToken.Assertion == null) { throw new ArgumentException(ErrorMessages.IDX10202); } DateTime?notBefore = null; DateTime?expires = null; if (samlToken.Assertion.Conditions != null) { notBefore = samlToken.Assertion.Conditions.NotBefore; expires = samlToken.Assertion.Conditions.NotOnOrAfter; } Validators.ValidateTokenReplay(securityToken, expires, validationParameters); if (validationParameters.ValidateLifetime) { if (validationParameters.LifetimeValidator != null) { if (!validationParameters.LifetimeValidator(notBefore: notBefore, expires: expires, securityToken: samlToken, validationParameters: validationParameters)) { throw new SecurityTokenInvalidLifetimeException(string.Format(CultureInfo.InvariantCulture, ErrorMessages.IDX10230, securityToken)); } } else { ValidateLifetime(notBefore: notBefore, expires: expires, securityToken: samlToken, validationParameters: validationParameters); } } // TODO // need to validate ValidateConfirmationData(subjectConfirmation.SubjectConfirmationData); if (validationParameters.ValidateAudience) { List <string> audiences = new List <string>(); if (samlToken.Assertion.Conditions != null && samlToken.Assertion.Conditions.AudienceRestrictions != null) { foreach (Saml2AudienceRestriction restriction in samlToken.Assertion.Conditions.AudienceRestrictions) { if (restriction == null) { continue; } foreach (Uri uri in restriction.Audiences) { if (uri == null) { continue; } audiences.Add(uri.OriginalString); } } } if (validationParameters.AudienceValidator != null) { if (!validationParameters.AudienceValidator(audiences, samlToken, validationParameters)) { throw new SecurityTokenInvalidAudienceException(string.Format(CultureInfo.InvariantCulture, ErrorMessages.IDX10231, securityToken)); } } else { ValidateAudience(audiences, samlToken, validationParameters); } } string issuer = samlToken.Assertion.Issuer != null ? samlToken.Assertion.Issuer.Value : null; if (validationParameters.ValidateIssuer) { if (validationParameters.IssuerValidator != null) { issuer = validationParameters.IssuerValidator(issuer, samlToken, validationParameters); } else { issuer = ValidateIssuer(issuer, samlToken, validationParameters); } } if (samlToken.IssuerToken != null) { ValidateIssuerSecurityKey(samlToken.IssuerToken.SecurityKeys[0], samlToken, validationParameters); } ClaimsIdentity identity = CreateClaimsIdentity(samlToken, issuer, validationParameters); if (validationParameters.SaveSigninToken) { identity.BootstrapContext = new BootstrapContext(securityToken); } validatedToken = samlToken; return(new ClaimsPrincipal(identity)); }