Procedimiento para crear un servicio de token de seguridad

Un servicio de token de seguridad implementa el protocolo definido en la especificación de WS-Trust. Este protocolo define formatos de mensaje y patrones de intercambio de mensajes para emitir, renovar, cancelar y validar tokens de seguridad. Un servicio de token de seguridad determinado proporciona uno o más de estas funciones. Este tema aborda el escenario común: implementación de la emisión de token.

Emitir tokens

WS-Trust define los formatos de mensaje, basándose en el elemento de esquema del lenguaje de definición de esquemas XML (XSD) RequestSecurityToken y en el elemento de esquema XSD RequestSecurityTokenResponse para realizar la emisión del token. Además, define los URI (Uniform Resource Identifier) de acción. El URI de acción asociado al mensaje RequestSecurityToken es http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue. El URI de acción asociado al mensaje RequestSecurityTokenResponse es http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue.

Estructura de mensaje de solicitud

La estructura del mensaje de solicitud de problema está normalmente compuesta de los elementos siguientes:

  • Un URI de tipo de solicitud con un valor http://schemas.xmlsoap.org/ws/2005/02/trust/Issue.

  • Un URI del tipo de token. Para los tokens de lenguaje de marcado de aserción de seguridad (SAML) 1.1, el valor de este URI es http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1.

  • Un valor de tamaño clave que indica el número de bits en la clave que se va asociar al token emitido.

  • Un tipo URI clave. Para las claves simétricas, el valor de este URI es http://schemas.xmlsoap.org/ws/2005/02/trust/SymmetricKey.

Además, un par de otros elementos podrían estar presentes:

  • Material clave proporcionado por el cliente.

  • Información de ámbito que indica el servicio de destino con el que se utilizará el token emitido.

El servicio de token de seguridad utiliza la información en el mensaje de solicitud del problema cuando construye el mensaje de respuesta del problema.

Estructura del mensaje de respuesta

La estructura del mensaje de respuesta del problema está normalmente compuesta de los elementos siguientes;

  • El token de seguridad emitido, por ejemplo, una aserción SAML 1.1.

  • Un token de prueba asociado al token de seguridad. Para las claves simétricas, éste es a menudo una forma cifrada del material clave.

  • Hace referencia al token de seguridad emitido. Normalmente, el servicio del token de seguridad devuelve una referencia que se puede utilizar cuando el token emitido aparece en un mensaje subsiguiente enviado por el cliente y otro que se puede utilizar cuando el token no se encuentra presente en mensajes subsiguientes.

Además, un par de otros elementos podrían estar presentes:

  • Material clave proporcionado por el servicio del token de seguridad.

  • El algoritmo necesario para calcular la clave compartida.

  • Información de duración del token emitido.

Procesar los mensajes de solicitud

El servicio del token de seguridad procesa la solicitud del problema examinando las varias partes del mensaje de solicitud y asegurándose de que puede emitir un token que satisfaga la solicitud. El servicio del token de seguridad debe determinar lo siguiente antes de construir el token que se va a emitir:

  • La solicitud realmente es una solicitud para un token que se va a emitir.

  • El servicio del token de seguridad soporta el tipo de token solicitado.

  • El solicitante está autorizado para realizar la solicitud.

  • El servicio del token de seguridad puede satisfacer las expectativas del solicitante con respecto al material clave.

Dos partes vitales de la construcción de un token determinan con qué clave se firmará el token y con qué clave se cifrará la clave compartida. El token debe ser firmado para que cuando el cliente presenta el token al servicio de destino, ese servicio pueda determinar que el token fue emitido por un servicio del token de seguridad en el que confía. El material clave debe cifrarse de manera que el servicio de destino pueda descifrar ese material de clave.

La firma de una aserción SAML implica la creación de una instancia SigningCredentials. El constructor para esta clase toma lo siguiente:

  • SecurityKey para que la clave lo utilice para firmar la aserción SAML.

  • Una cadena que identifica el algoritmo de firma a utilizar.

  • Una cadena que identifica el algoritmo de resumen a utilizar.

  • Opcionalmente, SecurityKeyIdentifier que identifica la clave a utilizar para firmar la aserción.

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

El cifrado de la clave compartida implica tomar el material clave y cifrarlo con una clave que el servicio de destino pueda utilizar para descifrar la clave compartida. Normalmente, se utiliza la clave pública del servicio 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

Además, se necesita SecurityKeyIdentifier para la clave cifrada.

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

SecurityKeyIdentifier se utiliza a continuación para crear un SamlSubject como parte del 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 obtener más información, consulte ejemplo de federación.

Crear los mensajes de respuesta

Cuando el servicio de token de seguridad procesa la solicitud del problema y construye el token que se va a emitir junto con la clave de prueba, el mensaje de respuesta necesita ser construido, incluyendo como mínimo el token solicitado, el token de prueba y las referencias del token emitido. El token emitido es normalmente SamlSecurityToken creado a partir de SamlAssertion, como se muestra en el ejemplo siguiente.

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

En el caso donde el servicio del token de seguridad proporciona el material de la clave compartida, el token de prueba se construye creando BinarySecretSecurityToken.

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

End Function

Para obtener más información sobre cómo construir el token de prueba cuando el cliente y el servicio de token de seguridad proporcionan el material clave para la clave compartida, consulte ejemplo de federación.

Las referencias del token emitido se construyen creando instancias de la clase SecurityKeyIdentifierClause.

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

Estos valores diferentes se serializan a continuación en el mensaje de respuesta devuelto al cliente.

Ejemplo

Para obtener código completo para un servicio de token de seguridad, consulte ejemplo de federación.

Consulte también