Saltar al contenido

Cómo verificar una firma SAML para el enlace de redireccionamiento HTTP

Solución:

Un mensaje de autenticación SAML es un documento XML con una firma XMLDSig incrustada (envuelta) o una firma de codificación desinflada

Firma XMLDSign envuelta

<samlp:LogoutRequest>
    <...saml message...> 
    <ds:Signature>
         <ds:SignedInfo />
         <ds:SignatureValue /> 
         <ds:KeyInfo /> 
    </ds:Signature> 
</samlp:LogoutRequest>

<ds:SignatureValue> contiene la firma, <ds:SignedInfo> los datos firmados y una referencia al mensaje y <ds:KeyInfo> generalmente contiene el certificado X509 con la identidad del firmante, o una referencia a ese certificado

Codificación desinflada en URL

SAMLRequest=value&RelayState=value&SigAlg=value&Signature=value

Donde cada valor está codificado en URL

SAMLRequest=urlencode(base64(<samlp:LogoutRequest> <...saml message...> </samlp:LogoutRequest>))

Y la firma se realiza en una concatenación del algoritmo de cadena de consulta utilizando el algoritmo SigAlg

Signature = urlencode( base64 ( SigAlg ("SAMLRequest=value&RelayState=value&SigAlg=value")))

Firma digital de mensajes SAML

El mensaje SAML está firmado digitalmente (no encriptado) con la clave privada del emisor (SP) y se puede verificar con la clave pública del SP. Una respuesta SAML debe estar firmada con la clave privada del proveedor de identidad (IdP), y el SP puede verificar el mensaje con la clave pública del IdP.

Si actúa como IdP y desea verificar una solicitud SAML del SP, necesita:

  • Verificar la firma digital: Verifique utilizando la clave pública del SP que la firma coincida con el mensaje firmado para garantizar que la identidad del firmante y el mensaje no se hayan alterado

  • Autoriza la solicitud: Verifique que la identidad del firmante pueda realizar la operación solicitada. Por lo general, debe hacer coincidir el número de serie o el asunto del certificado con una lista preexistente, o verificar que el certificado haya sido emitido por una autoridad certificadora de confianza.

  • Genera la respuesta SAML: Genere un mensaje XML con los datos SAML y fírmelo con su clave privada para enviarlo a SP

La mayoría de los lenguajes de programación admiten firmas XMLDsig, pero en su caso se utiliza el encodin desinfladog que es una característica específica del enlace SAML, por lo que si su biblioteca SAML no lo admite, tienes que verificar la firma manualmente. Estos son más o menos los pasos a seguir según especificación

 //get params from query string 
String samlrequest = getQueryParam("SAMLRequest");
String relaystate = getQueryParam("RelayState");
String sigalg = getQueryParam("SigAlg");
String signature = getQueryParam("Signature");


//The signature
byte signature[] = URLDecoder.decode(Base64.getDecoder().decode(signature ), "UTF-8");

//The signed data. build the following string checking if RelayState is null
//SAMLRequest=samlrequest&RelayState=relaystate&SigAlg=sigalg
byte signedData[] = concat(samlrequest,relaystate,sigalg);

//The signature algorithm could be "SHA1WithRSA" or "SHA1withDSA" depending on sigalg is http://www.w3.org/2000/09/xmldsig#rsa-sha1 or http://www.w3.org/2000/09/xmldsig#dsa-sha1 
String signatureAlgorithm = extractSignatureAlgorithm(sigalg);

//get the public key of the SP. It must be registered before this process
PublicKey publicKey = ...

//Verify the signature
Signature sig = Signature.getInstance(signatureAlgorithm);
sig.initVerify(publicKey);
sig.update(signedData); 
boolean verifies = sig.verify(signature);  

Estoy tratando de usar la respuesta anterior pero no tengo éxito.

Luego, lea la documentación y un poco de tiempo, tengo éxito para validar la firma con Java y la respuesta rápida es:

final String samlRequest = request.getParameter("SAMLRequest");
final String relayState = request.getParameter("RelayState");
final String sigAlg = request.getParameter("SigAlg");
final String signature = request.getParameter("Signature");

FileInputStream fis = new FileInputStream(new File("path-to-service-provider-x509-certificate"));

CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate cert = cf.generateCertificate(fis);

// ps: java.net.URLEncoder;
String query = "SAMLRequest=" + URLEncoder.encode(samlRequest, "UTF-8");
query += "&RelayState=" +URLEncoder.encode(relayState, "UTF-8");
query += "&SigAlg=" + URLEncoder.encode(sigAlg, "UTF-8");

// ps: org.opensaml.xml.util.Base64
byte[] signatureBytes = Base64.decode(signature);

org.apache.xml.security.Init.init();
Signature sig = Signature.getInstance("SHA1withRSA"); // or other alg (i, e: SHA256WithRSA or others)
sig.initVerify(cert.getPublicKey());
sig.update(query.getBytes());
Boolean valid = sig.verify(signatureBytes);

Una firma SAML 2.0 se valida de manera diferente según el enlace (POST o Redirect). Si se utiliza un enlace POST, la firma se valida en SAML XML. Si se utiliza un enlace de redireccionamiento, la cadena de consulta se valida con la firma.

Esta LogoutRequest se envía con un enlace de redireccionamiento. El siguiente código de muestra de C # se copia del componente ITfoxtec.Identity.Saml2 y muestra cómo validar la firma.

var queryString = request.QueryString;
var signatureValue = Convert.FromBase64String(request.Query["Signature"]);

var messageName = "SAMLRequest";
var signatureAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
var signatureValidationCertificate = new X509Certificate2("path-to-service-provider-x509-certificate");

var saml2Sign = new Saml2SignedText(signatureValidationCertificate, signatureAlgorithm);
if (saml2Sign.CheckSignature(Encoding.UTF8.GetBytes(new RawSaml2QueryString(queryString, messageName).SignedQueryString), signatureValue))
{
    // Signature is valid.
}
else
{
    throw new InvalidSignatureException("Signature is invalid.");
}
  • Código copiado de Saml2RedirectBinding
  • RawSaml2QueryString
  • Saml2SignedText
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *