SecurityTokenHandler.ValidateToken(SecurityToken) Método
Definição
Importante
Algumas informações se referem a produtos de pré-lançamento que podem ser substancialmente modificados antes do lançamento. A Microsoft não oferece garantias, expressas ou implícitas, das informações aqui fornecidas.
Quando substituído em uma classe derivada, valida o token de segurança especificado. O token deve ser do tipo processado pela classe derivada.
public:
virtual System::Collections::ObjectModel::ReadOnlyCollection<System::Security::Claims::ClaimsIdentity ^> ^ ValidateToken(System::IdentityModel::Tokens::SecurityToken ^ token);
public virtual System.Collections.ObjectModel.ReadOnlyCollection<System.Security.Claims.ClaimsIdentity> ValidateToken(System.IdentityModel.Tokens.SecurityToken token);
abstract member ValidateToken : System.IdentityModel.Tokens.SecurityToken -> System.Collections.ObjectModel.ReadOnlyCollection<System.Security.Claims.ClaimsIdentity>
override this.ValidateToken : System.IdentityModel.Tokens.SecurityToken -> System.Collections.ObjectModel.ReadOnlyCollection<System.Security.Claims.ClaimsIdentity>
Public Overridable Function ValidateToken (token As SecurityToken) As ReadOnlyCollection(Of ClaimsIdentity)
Parâmetros
- token
- SecurityToken
O token a ser validado.
Retornos
As identidades contidas no token.
Exemplos
O código a seguir mostra uma substituição do ValidateToken método para um manipulador de token de segurança que processa SWT (tokens Web simples). O código é extraído do CustomToken exemplo. Para obter informações sobre este exemplo e outros exemplos disponíveis para WIF e onde baixá-los, consulte o Índice de Exemplo de Código WIF.
/// <summary>
/// This method validates the Simple Web Token.
/// </summary>
/// <param name="token">A simple web token.</param>
/// <returns>A Claims Collection which contains all the claims from the token.</returns>
public override ReadOnlyCollection<ClaimsIdentity> ValidateToken(SecurityToken token)
{
if ( token == null )
{
throw new ArgumentNullException( "token" );
}
SimpleWebToken simpleWebToken = token as SimpleWebToken;
if ( simpleWebToken == null )
{
throw new ArgumentException("The token provided must be of type SimpleWebToken.");
}
if ( DateTime.Compare( simpleWebToken.ValidTo.Add( Configuration.MaxClockSkew ), DateTime.UtcNow ) <= 0 )
{
throw new SecurityTokenExpiredException("The incoming token has expired. Get a new access token from the Authorization Server.");
}
ValidateSignature( simpleWebToken );
ValidateAudience( simpleWebToken.Audience );
ClaimsIdentity claimsIdentity = CreateClaims( simpleWebToken );
if (this.Configuration.SaveBootstrapContext)
{
claimsIdentity.BootstrapContext = new BootstrapContext(simpleWebToken.SerializedToken);
}
List<ClaimsIdentity> claimCollection = new List<ClaimsIdentity>(new ClaimsIdentity[] { claimsIdentity });
return claimCollection.AsReadOnly();
}
O código a seguir mostra CreateClaims o método que é invocado da substituição do ValidateToken método no exemplo anterior. Esse método retorna um ClaimsIdentity objeto que é criado a partir das declarações no token. O código é extraído do CustomToken exemplo. Para obter informações sobre este exemplo e outros exemplos disponíveis para WIF e onde baixá-los, consulte o Índice de Exemplo de Código WIF.
/// <summary>Creates <see cref="Claim"/>'s from the incoming token.
/// </summary>
/// <param name="simpleWebToken">The incoming <see cref="SimpleWebToken"/>.</param>
/// <returns>A <see cref="ClaimsIdentity"/> created from the token.</returns>
protected virtual ClaimsIdentity CreateClaims( SimpleWebToken simpleWebToken )
{
if ( simpleWebToken == null )
{
throw new ArgumentNullException( "simpleWebToken" );
}
NameValueCollection tokenProperties = simpleWebToken.GetAllProperties();
if ( tokenProperties == null )
{
throw new SecurityTokenValidationException( "No claims can be created from this Simple Web Token." );
}
if ( Configuration.IssuerNameRegistry == null )
{
throw new InvalidOperationException( "The Configuration.IssuerNameRegistry property of this SecurityTokenHandler is set to null. Tokens cannot be validated in this state." );
}
string normalizedIssuer = Configuration.IssuerNameRegistry.GetIssuerName( simpleWebToken );
ClaimsIdentity identity = new ClaimsIdentity(AuthenticationTypes.Federation);
foreach ( string key in tokenProperties.Keys )
{
if ( ! IsReservedKeyName(key) && !string.IsNullOrEmpty( tokenProperties[key] ) )
{
identity.AddClaim( new Claim( key, tokenProperties[key], ClaimValueTypes.String, normalizedIssuer ) );
if ( key == AcsNameClaimType )
{
// add a default name claim from the Name identifier claim.
identity.AddClaim( new Claim( DefaultNameClaimType, tokenProperties[key], ClaimValueTypes.String, normalizedIssuer ) );
}
}
}
return identity;
}
O código a seguir mostra ValidateSignature o método que é invocado da substituição do ValidateToken método no manipulador de token da Web simples. Esse método valida a assinatura no token usando o .IssuerTokenResolver O código é extraído do CustomToken exemplo. Para obter informações sobre este exemplo e outros exemplos disponíveis para WIF e onde baixá-los, consulte o Índice de Exemplo de Código WIF.
/// <summary>
/// Validates the signature on the incoming token.
/// </summary>
/// <param name="simpleWebToken">The incoming <see cref="SimpleWebToken"/>.</param>
protected virtual void ValidateSignature( SimpleWebToken simpleWebToken )
{
if ( simpleWebToken == null )
{
throw new ArgumentNullException( "simpleWebToken" );
}
if ( String.IsNullOrEmpty( simpleWebToken.SerializedToken ) || String.IsNullOrEmpty( simpleWebToken.Signature ) )
{
throw new SecurityTokenValidationException( "The token does not have a signature to verify" );
}
string serializedToken = simpleWebToken.SerializedToken;
string unsignedToken = null;
// Find the last parameter. The signature must be last per SWT specification.
int lastSeparator = serializedToken.LastIndexOf( ParameterSeparator );
// Check whether the last parameter is an hmac.
if ( lastSeparator > 0 )
{
string lastParamStart = ParameterSeparator + SimpleWebTokenConstants.Signature + "=";
string lastParam = serializedToken.Substring( lastSeparator );
// Strip the trailing hmac to obtain the original unsigned string for later hmac verification.
if ( lastParam.StartsWith( lastParamStart, StringComparison.Ordinal ) )
{
unsignedToken = serializedToken.Substring( 0, lastSeparator );
}
}
SimpleWebTokenKeyIdentifierClause clause = new SimpleWebTokenKeyIdentifierClause(simpleWebToken.Audience);
InMemorySymmetricSecurityKey securityKey = null;
try
{
securityKey = (InMemorySymmetricSecurityKey)this.Configuration.IssuerTokenResolver.ResolveSecurityKey(clause);
}
catch (InvalidOperationException)
{
throw new SecurityTokenValidationException( "A Symmetric key was not found for the given key identifier clause.");
}
string generatedSignature = GenerateSignature( unsignedToken, securityKey.GetSymmetricKey() );
if ( string.CompareOrdinal( generatedSignature, simpleWebToken.Signature ) != 0 )
{
throw new SecurityTokenValidationException( "The signature on the incoming token is invalid.") ;
}
}
/// <summary>
/// Generates an HMACSHA256 signature for a given string and key.
/// </summary>
/// <param name="unsignedToken">The token to be signed.</param>
/// <param name="signingKey">The key used to generate the signature.</param>
/// <returns>The generated signature.</returns>
protected static string GenerateSignature(string unsignedToken, byte[] signingKey)
{
using (HMACSHA256 hmac = new HMACSHA256(signingKey))
{
byte[] signatureBytes = hmac.ComputeHash(Encoding.ASCII.GetBytes(unsignedToken));
string signature = HttpUtility.UrlEncode(Convert.ToBase64String(signatureBytes));
return signature;
}
}
O código a seguir mostra ValidateAudience o método que é invocado da substituição do ValidateToken método no manipulador de token da Web simples. Esse método valida o público-alvo contido no token em relação às URIs de audiência especificadas na configuração. O código é extraído do CustomToken exemplo. Para obter informações sobre este exemplo e outros exemplos disponíveis para WIF e onde baixá-los, consulte o Índice de Exemplo de Código WIF.
/// <summary>
/// Validates the audience of the incoming token with those specified in configuration.
/// </summary>
/// <param name="tokenAudience">The audience of the incoming token.</param>
protected virtual void ValidateAudience( string tokenAudience )
{
if ( Configuration.AudienceRestriction.AudienceMode != AudienceUriMode.Never )
{
if ( String.IsNullOrEmpty( tokenAudience ) )
{
throw new SecurityTokenValidationException("The incoming token does not have a valid audience Uri and the Audience Restriction is not set to 'None'.");
}
if ( Configuration.AudienceRestriction.AllowedAudienceUris.Count == 0 )
{
throw new InvalidOperationException( " Audience Restriction is not set to 'None' but no valid audience URI's are configured." );
}
IList<Uri> allowedAudienceUris = Configuration.AudienceRestriction.AllowedAudienceUris;
Uri audienceUri = null;
Uri.TryCreate(tokenAudience, UriKind.RelativeOrAbsolute, out audienceUri);
// Strip off any query string or fragment.
Uri audienceLeftPart;
if ( audienceUri.IsAbsoluteUri )
{
audienceLeftPart = new Uri( audienceUri.GetLeftPart( UriPartial.Path ) );
}
else
{
Uri baseUri = new Uri( "http://www.example.com" );
Uri resolved = new Uri( baseUri, tokenAudience );
audienceLeftPart = baseUri.MakeRelativeUri( new Uri( resolved.GetLeftPart( UriPartial.Path ) ) );
}
if ( !allowedAudienceUris.Contains( audienceLeftPart ) )
{
throw new AudienceUriValidationFailedException(
"The Audience Uri of the incoming token is not present in the list of permitted Audience Uri's.");
}
}
}
Comentários
Por padrão, esse método gera uma NotImplementedException exceção.
O ValidateToken método é chamado pela infraestrutura para validar e extrair as declarações do token de segurança desserializado. Essas declarações são retornadas na coleção de ClaimsIdentity objetos retornados pelo método. No caso típico, essa coleção conterá uma única identidade.
Em classes derivadas, a validação normalmente inclui validar o público-alvo pretendido especificado no token em relação às URIs de audiência especificadas na SecurityTokenHandlerConfiguration.AudienceRestriction propriedade do objeto de configuração do manipulador de token especificado na Configuration propriedade. Normalmente, essas URIs são definidas no arquivo de configuração no <elemento audienceUris> . Se o público-alvo não puder ser validado, uma exceção AudienceUriValidationFailedException deverá ser gerada.
Ao processar o token, o emissor normalmente é validado passando o token do emissor para um dos GetIssuerName métodos no IssuerNameRegistry objeto configurado para o manipulador por meio da Configuration propriedade. O registro de nome do emissor normalmente é configurado por meio do <elemento issuerNameRegistry> no arquivo de configuração. O GetIssuerName retorna o nome do emissor. Esse nome deve ser usado para definir a Claim.Issuer propriedade em declarações contidas no token. Se o registro de nome do emissor não contiver uma entrada para o token emissor, GetIssuerName retornará null. Nesse caso, normalmente um SecurityTokenException é gerado em classes derivadas, mas esse comportamento cabe ao designer da classe.