Compartilhar via


Como: criar um serviço de token de segurança

Um serviço de token de segurança implementa o protocolo definido na especificação WS-Trust. Esse protocolo define formatos de mensagem e padrões de troca de mensagens para emitir, renovar, cancelar e validar tokens de segurança. Um determinado serviço de token de segurança fornece um ou mais desses recursos. Este tópico analisa o cenário mais comum: implementar a emissão de token.

Emissão de tokens

A WS-Trust define formatos de mensagem, com base no elemento de esquema XSD (linguagem de definição de esquema XML) doRequestSecurityToken e no elemento de esquema XSD RequestSecurityTokenResponsepara executar a emissão de token. Além disso, ele define os URIs (Uniform Resource Identifiers) de ação associados. O URI de ação associado à mensagem RequestSecurityToken é http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue. O URI de ação associado à mensagem RequestSecurityTokenResponse é http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue.

Estrutura de mensagem de solicitação

A estrutura de mensagem de solicitação de problema geralmente consiste nos seguintes itens:

  • Um URI de tipo de solicitação com um valor de http://schemas.xmlsoap.org/ws/2005/02/trust/Issue.

  • Um URI de tipo de token. Para tokens SAML (Security Assertions Markup Language) 1.1, o valor desse URI é http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1.

  • Um valor de tamanho de chave que indica o número de bits na chave a serem associados ao token emitido.

  • Um URI de tipo de chave. Para chaves simétricas, o valor desse URI é http://schemas.xmlsoap.org/ws/2005/02/trust/SymmetricKey.

Além disso, alguns outros itens podem estar presentes:

  • Material de chave fornecido pelo cliente.

  • Informações de escopo que indicam o serviço de destino com o qual o token emitido será usado.

O serviço de token de segurança usa as informações na mensagem de solicitação de problema quando constrói a mensagem de Resposta ao Problema.

Estrutura de mensagens de resposta

A estrutura da mensagem de solicitação de problema geralmente consiste nos seguintes itens:

  • O token de segurança emitido, por exemplo, uma declaração SAML 1.1.

  • Um token de prova associado ao token de segurança. Para chaves simétricas, trata-se geralmente de uma forma criptografada do material de chave.

  • Referências ao token de segurança emitido. Normalmente, o serviço de token de segurança retorna uma referência que pode ser usada quando o token emitido aparece em uma mensagem subsequente enviada pelo cliente e outra que pode ser usada quando o token não está presente em mensagens subsequentes.

Além disso, alguns outros itens podem estar presentes:

  • Material de chave fornecido pelo serviço de token de segurança.

  • O algoritmo necessário para calcular a chave compartilhada.

  • As informações de tempo de vida do token emitido.

Processando mensagens de solicitação

O serviço de token de segurança processa a solicitação de problema examinando as várias partes da mensagem de solicitação e garantindo que ela possa emitir um token que atenda à solicitação. O serviço de token de segurança deve determinar o seguinte antes de construir o token a ser emitido:

  • A solicitação realmente é uma solicitação para que um token seja emitido.

  • O serviço de token de segurança dá suporte ao tipo de token solicitado.

  • O solicitante não está autorizado a fazer a solicitação.

  • O serviço de token de segurança pode atender às expectativas do solicitante em relação ao material de chave.

Duas partes vitais da construção de um token são determinar com qual chave assinar o token e com qual chave criptografar a chave compartilhada. O token precisa ser assinado para que, quando o cliente apresentar o token para o serviço de destino, esse serviço possa determinar que o token foi emitido por um serviço de token de segurança em que confia. O material de chave precisa ser criptografado de forma que o serviço de destino possa descriptografar esse material de chave.

Assinar uma declaração SAML envolve a criação de uma instância SigningCredentials. O construtor dessa classe usa o seguinte:

  • Uma SecurityKey para a chave a ser usada para assinar a declaração SAML.

  • Uma cadeia de caracteres que identifica o algoritmo de assinatura a ser usado.

  • Uma cadeia de caracteres que identifica o algoritmo de hash a ser usado.

  • Opcionalmente, um SecurityKeyIdentifier que identifica a chave a ser usada para assinar a declaração.

void AddSigningCredentials(SamlAssertion assertion, SecurityKey signingKey)
{
    SigningCredentials sc = new SigningCredentials(signingKey,
        SecurityAlgorithms.RsaSha1Signature, SecurityAlgorithms.Sha1Digest);
    assertion.SigningCredentials = sc;
}
Sub AddSigningCredentials(ByVal assertion As SamlAssertion, _
    ByVal signingKey As SecurityKey)
    Dim sc As New SigningCredentials(signingKey, _
    SecurityAlgorithms.RsaSha1Signature, SecurityAlgorithms.Sha1Digest)
    assertion.SigningCredentials = sc

End Sub

Criptografar a chave compartilhada envolve pegar o material da chave e criptografá-lo com uma chave que o serviço de destino pode usar para descriptografar a chave compartilhada. Normalmente, usa-se a chave pública do serviço de destino.

byte[] EncryptKey(byte[] plainTextKey, SecurityKey encryptingKey)
{
    return encryptingKey.EncryptKey(SecurityAlgorithms.RsaOaepKeyWrap, plainTextKey);
}
Function EncryptKey(ByVal plainTextKey() As Byte, _
        ByVal encryptingKey As SecurityKey) As Byte()
    Return encryptingKey.EncryptKey(SecurityAlgorithms.RsaOaepKeyWrap, plainTextKey)
End Function

Além disso, é necessário um SecurityKeyIdentifier para a chave criptografada.

SecurityKeyIdentifier GetKeyIdentifierForEncryptedKey(byte[] encryptedKey,
    SecurityToken encryptingToken)
{
    SecurityKeyIdentifier encryptingKeyIdentifier = new SecurityKeyIdentifier(encryptingToken.CreateKeyIdentifierClause<X509ThumbprintKeyIdentifierClause>());
    return new SecurityKeyIdentifier(new EncryptedKeyIdentifierClause(encryptedKey, SecurityAlgorithms.RsaOaepKeyWrap, encryptingKeyIdentifier));
}
Function GetKeyIdentifierForEncryptedKey(ByVal encryptedKey() _
 As Byte, ByVal encryptingToken As SecurityToken) _
    As SecurityKeyIdentifier
    Dim encryptingKeyIdentifier As New SecurityKeyIdentifier( _
        encryptingToken.CreateKeyIdentifierClause(Of X509ThumbprintKeyIdentifierClause)())
    Return New SecurityKeyIdentifier(New EncryptedKeyIdentifierClause( _
        encryptedKey, SecurityAlgorithms.RsaOaepKeyWrap, encryptingKeyIdentifier))
End Function

Esse SecurityKeyIdentifier é, em seguida, usado para criar um SamlSubject como parte do SamlToken.

SamlSubject CreateSamlSubjectForProofKey(SecurityKeyIdentifier proofKeyIdentifier)
{
    List<string> confirmations = new List<string>();

    confirmations.Add("urn:oasis:names:tc:SAML:1.0:cm:holder-of-key");

    return new SamlSubject(null, null, "IssuerName", confirmations, null, proofKeyIdentifier);
}
Function CreateSamlSubjectForProofKey( _
    ByVal proofKeyIdentifier As SecurityKeyIdentifier) As SamlSubject
    Dim confirmations As List(Of String) = New List(Of String)()
    confirmations.Add("urn:oasis:names:tc:SAML:1.0:cm:holder-of-key")
    Return New SamlSubject(Nothing, Nothing, "IssuerName", _
        confirmations, Nothing, proofKeyIdentifier)
End Function

Para obter mais informações, consulte Amostra da Federação.

Como criar mensagens de resposta

Depois que o serviço de token de segurança processa a solicitação de problema e constrói o token a ser emitido juntamente com a chave de prova, a mensagem de resposta precisa ser construída, incluindo pelo menos o token solicitado, o token de prova e as referências de token emitidas. O token emitido normalmente é um SamlSecurityToken criado a partir da SamlAssertion, conforme mostrado no exemplo a seguir.

SecurityToken CreateIssuedToken(SamlAssertion assertion)
{
    return new SamlSecurityToken(assertion);
}
Function CreateIssuedToken(ByVal assertion As SamlAssertion) As SecurityToken
    Return New SamlSecurityToken(assertion)
End Function

No caso em que o serviço de token de segurança fornece o material de chave compartilhada, o token de prova é construído criando um BinarySecretSecurityToken.

BinarySecretSecurityToken CreateProofToken(byte[] proofKey)
{
    return new BinarySecretSecurityToken(proofKey);
}
Function CreateProofToken(ByVal proofKey() As Byte) As BinarySecretSecurityToken
    Return New BinarySecretSecurityToken(proofKey)

End Function

Para obter mais informações sobre como construir o token de prova quando o cliente e o serviço de token de segurança fornecerem material de chave para a chave compartilhada, consulte Amostra da Federação.

As referências de token emitidas são construídas criando-se instâncias da classe SecurityKeyIdentifierClause.

SecurityKeyIdentifierClause CreateTokenReference(SamlSecurityToken token)
{
    return token.CreateKeyIdentifierClause<SamlAssertionKeyIdentifierClause>();
}
Function CreateTokenReference(ByVal token As SamlSecurityToken) _
    As SecurityKeyIdentifierClause
    Return token.CreateKeyIdentifierClause( _
    Of SamlAssertionKeyIdentifierClause)()
End Function

Esses vários valores são serializados na mensagem de resposta retornada ao cliente.

Exemplo

Para obter o código completo de um serviço de token de segurança, consulte Exemplo de Federação.

Confira também