简体   繁体   中英

OpenSaml AuthnRequest signature

I'm building a SAML 2.0 AuthNRequest. I managed to add signature informations using OpenSaml but i can't find a way to add <ds:SignatureValue/> and <ds:DigestValue/> VALUES using the library. Here is the code:

    public String buildAuthnRequest()  {
        QName qname = new javax.xml.namespace.QName(SSO_METDATA_QNAME);
        IssuerBuilder issuerBuilder = new IssuerBuilder();
        Issuer issuer = issuerBuilder.buildObject("urn:oasis:names:tc:SAML:2.0:assertion", "Issuer", "samlp");
        issuer.setValue(issuer.getValue());
        DateTime issueInstant = new DateTime();
        AuthnRequestBuilder authnRequestBuilder = new AuthnRequestBuilder();
        AuthnRequest authnRequest = authnRequestBuilder.buildObject("urn:oasis:names:tc:SAML:2.0:protocol","AuthnRequest", "samlp");
        authnRequest.setAssertionConsumerServiceURL("http://test.com");
//      Signature sign = null;
//      sign.setSignatureAlgorithm("SHA256");
//      Credential credential = null;
//      sign.setSigningCredential(credential);
//      authnRequest.setSignature(sign);
        NameIDPolicyBuilder policy = new NameIDPolicyBuilder();
        NameIDPolicy pol = policy.buildObject();
        RequestedAuthnContextBuilder contextBuild = new RequestedAuthnContextBuilder();
        RequestedAuthnContext context = contextBuild.buildObject();
        authnRequest.setRequestedAuthnContext(context);
        authnRequest.setNameIDPolicy(pol);
        authnRequest.setForceAuthn(new Boolean(false));
        authnRequest.setIsPassive(new Boolean(false));
        authnRequest.setIssueInstant(issueInstant);
        authnRequest.setProtocolBinding("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST");
        authnRequest.setAssertionConsumerServiceURL(issuer.getElementQName().getNamespaceURI());
        authnRequest.setProviderName("RGI");
        authnRequest.setIssuer(issuer);
        authnRequest.setID(UUID.randomUUID().toString());
        authnRequest.setVersion(SAMLVersion.VERSION_20);
        SignatureBuilder signBuilder = new SignatureBuilder();
        Signature sign = signBuilder.buildObject();
        sign.setSchemaLocation("http://www.w3.org/2000/09/xmldsig#");
        sign.setSignatureAlgorithm("http://www.w3.org/2000/09/xmldsig#rsa-sha1");
        sign.setCanonicalizationAlgorithm("http://www.w3.org/2001/10/xml-exc-c14n#");
        KeyInfoBuilder keyBuilder = new KeyInfoBuilder();
        KeyInfo key = keyBuilder.buildObject();
        key.setID(UUID.randomUUID().toString());
        sign.setKeyInfo(key);

        authnRequest.setSignature(sign);

//      RequestedAuthnContextBuilder requestContext = new RequestedAuthnContextBuilder();
//      RequestedAuthnContext rx = requestContext.buildObject(qname);
//      authne
//      rx.setComparison(arg0);
//      authnRequest.setRequestedAuthnContext(arg0);

        Logger.info("AUTHNREQUEST: "+authnRequest.toString());

        Marshaller marshaller = Configuration.getMarshallerFactory().getMarshaller(authnRequest);
        /* Encoding the compressed message */
        String encodedRequestMessage = null;
        String redirectionUrl = null;
        try {
            Element authDOM = marshaller.marshall(authnRequest);
            StringWriter rspWrt = new StringWriter();
            XMLHelper.writeNode(authDOM, rspWrt);
            String requestMessage = rspWrt.toString();
            utils.saveToFile("authmnRequest.xml", requestMessage);
            Deflater deflater = new Deflater(Deflater.DEFLATED, true);
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            DeflaterOutputStream deflaterOutputStream = new DeflaterOutputStream(byteArrayOutputStream, deflater);
            deflaterOutputStream.write(requestMessage.getBytes());
            deflaterOutputStream.close();
            encodedRequestMessage = Base64.encodeBytes(byteArrayOutputStream.toByteArray(), Base64.DONT_BREAK_LINES);
            String encodedAuthnRequest = URLEncoder.encode(encodedRequestMessage,"UTF-8").trim();
            String identitypProviderUrl = SignInUrl;
            redirectionUrl = identitypProviderUrl + "?SAMLRequest="+ encodedRequestMessage;
            Logger.info("RedirectionUrl: "+redirectionUrl);
            return redirectionUrl;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (MarshallingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return redirectionUrl;

I can use both HTTP-POST binding and HTTP-REDIRECT binding. I was trying to use HTTP-POST but if someone can explain how to make a HTTP-REDIRECT signature is accepted as an answer.

The ouput of HTTP-POST looks like:

    <samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="pfx41d8ef22-e612-8c50-9960-1b16f15741b3" Version="2.0" ProviderName="SP test" IssueInstant="2014-07-16T23:52:45Z" Destination="http://idp.example.com/SSOService.php" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" AssertionConsumerServiceURL="http://sp.example.com/demo1/index.php?acs">
  <saml:Issuer>http://sp.example.com/demo1/metadata.php</saml:Issuer>
  <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
    <ds:SignedInfo>
      <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
      <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
      <ds:Reference URI="#pfx41d8ef22-e612-8c50-9960-1b16f15741b3">
        <ds:Transforms>
          <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
          <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
        </ds:Transforms>
        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
        <ds:DigestValue>yJN6cXUwQxTmMEsPesBP2NkqYFI=</ds:DigestValue>
      </ds:Reference>
    </ds:SignedInfo>
    <ds:SignatureValue>g5eM9yPnKsmmE/Kh2qS7nfK8HoF6yHrAdNQxh70kh8pRI4KaNbYNOL9sF8F57Yd+jO6iNga8nnbwhbATKGXIZOJJSugXGAMRyZsj/rqngwTJk5KmujbqouR1SLFsbo7Iuwze933EgefBbAE4JRI7V2aD9YgmB3socPqAi2Qf97E=</ds:SignatureValue>
    <ds:KeyInfo>
      <ds:X509Data>
        <ds:X509Certificate>MIICajCCAdOgAwIBAgIBADANBgkqhkiG9w0BAQQFADBSMQswCQYDVQQGEwJ1czETMBEGA1UECAwKQ2FsaWZvcm5pYTEVMBMGA1UECgwMT25lbG9naW4gSW5jMRcwFQYDVQQDDA5zcC5leGFtcGxlLmNvbTAeFw0xNDA3MTcwMDI5MjdaFw0xNTA3MTcwMDI5MjdaMFIxCzAJBgNVBAYTAnVzMRMwEQYDVQQIDApDYWxpZm9ybmlhMRUwEwYDVQQKDAxPbmVsb2dpbiBJbmMxFzAVBgNVBAMMDnNwLmV4YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7vU/6R/OBA6BKsZH4L2bIQ2cqBO7/aMfPjUPJPSn59d/f0aRqSC58YYrPuQODydUABiCknOn9yV0fEYm4bNvfjroTEd8bDlqo5oAXAUAI8XHPppJNz7pxbhZW0u35q45PJzGM9nCv9bglDQYJLby1ZUdHsSiDIpMbGgf/ZrxqawIDAQABo1AwTjAdBgNVHQ4EFgQU3s2NEpYx7wH6bq7xJFKa46jBDf4wHwYDVR0jBBgwFoAU3s2NEpYx7wH6bq7xJFKa46jBDf4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQCPsNO2FG+zmk5miXEswAs30E14rBJpe/64FBpM1rPzOleexvMgZlr0/smF3P5TWb7H8Fy5kEiByxMjaQmml/nQx6qgVVzdhaTANpIE1ywEzVJlhdvw4hmRuEKYqTaFMLez0sRL79LUeDxPWw7Mj9FkpRYT+kAGiFomHop1nErV6Q==</ds:X509Certificate>
      </ds:X509Data>
    </ds:KeyInfo>
  </ds:Signature>
  <samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" AllowCreate="true"/>
  <samlp:RequestedAuthnContext Comparison="exact">
    <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
  </samlp:RequestedAuthnContext>
</samlp:AuthnRequest>

My current output is:

<?xml version="1.0" encoding="UTF-8"?>
<samlp:AuthnRequest AssertionConsumerServiceURL="urn:oasis:names:tc:SAML:2.0:assertion" ForceAuthn="false" ID="371fd275-271c-4e4e-a94e-858d7f616170" IsPassive="false" IssueInstant="2015-09-08T08:49:12.216Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
ProviderName="RGI" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
    <samlp:Issuer xmlns:samlp="urn:oasis:names:tc:SAML:2.0:assertion" />
    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:SignedInfo>
            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
            <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
            <ds:Reference URI="#371fd275-271c-4e4e-a94e-858d7f616170">
                <ds:Transforms>
                    <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
                    <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></ds:Transforms>
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
                <ds:DigestValue/></ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue/>
        <ds:KeyInfo Id="86ff0678-998d-4c97-bd1f-efdb9640de80" /></ds:Signature>
    <saml2p:NameIDPolicy xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" />
    <saml2p:RequestedAuthnContext xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" />
</samlp:AuthnRequest>

Thanks in advance

I solved it time ago, so i put the response here for someone's else need.

When creating the AuthnRequest object with the builder:

    // Add signature to request
    SignatureBuilder signFactory = new SignatureBuilder();
    Signature signature = signFactory.buildObject(Signature.DEFAULT_ELEMENT_NAME);
            signature.setCanonicalizationAlgorithm(getIdpSignature().getCanonicalizationAlgorithm());
            signature.setSignatureAlgorithm(getIdpSignature().getSignatureAlgorithm());
            signature.setSigningCredential(this.getCredentialFromFiles(SP_PRIVATEKEY,SP_CERTIFICATE));
// set signature
request.setSignature(signature);

The method this.getCredentialFromFiles() read x509 certificate from disk and build BasicX509Credential object

This is how to sign the XML object

private void signRequest(SignableXMLObject obj) {
        Credential credential = this.getCredential(SP_PRIVATEKEY, SP_CERTIFICATE);
        Signature signature = (Signature) Configuration.getBuilderFactory().getBuilder(Signature.DEFAULT_ELEMENT_NAME)
                .buildObject(Signature.DEFAULT_ELEMENT_NAME);
        signature.setSigningCredential(credential);
        signature.setCanonicalizationAlgorithm(getIdpSignature().getCanonicalizationAlgorithm());
        signature.setSignatureAlgorithm(getIdpSignature().getSignatureAlgorithm());
        SecurityConfiguration secConfig = Configuration.getGlobalSecurityConfiguration();
        try {
            SecurityHelper.prepareSignatureParams(signature, credential, secConfig, null);
            obj.setSignature(signature);
            Configuration.getMarshallerFactory().getMarshaller(obj).marshall(obj);
            Signer.signObject(signature);
        } catch (Exception e) {

        }
    }

And then sign the request:

this.signRequest(request);

+1 if you found it userful!

With OpenSAML 4.0. I got something like this, it's written in Scala, but can be converted to Java or some other JVM language you're using quite painlessly. SignableXMLObject can be the AuthnRequest created with new AuthnRequestBuilder().buildObject()

def signRequest(obj: SignableXMLObject, key: PrivateKey, certificate: X509Certificate): Unit = {
  val credential  = new BasicX509Credential(certificate, key)
  val signature = new SignatureBuilder().buildObject()
  signature.setSigningCredential(credential)
  signature.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1)
  signature.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS)
  obj.setSignature(signature)
  XMLObjectProviderRegistrySupport.getMarshallerFactory.getMarshaller(obj).marshall(obj)
  Signer.signObject(signature)
}

Also with OpenSAML 4.0. you need to trigger initialization like this instead of DefaultBootstrap:

InitializationService.initialize()

Creating the AuthnRequest without signing, but you can call the signing on it:

val uid          = "a" + UUID.randomUUID().toString
val authnRequest = new AuthnRequestBuilder().buildObject()
authnRequest.setIssueInstant(Instant.now())
authnRequest.setID(uid)
authnRequest.setAssertionConsumerServiceIndex(0)
authnRequest.setAttributeConsumingServiceIndex(0)
authnRequest.setVersion(SAMLVersion.VERSION_20)
authnRequest.setDestination(identityProviderUrl)

val authIssuer = new IssuerBuilder().buildObject()
authIssuer.setValue(issuer)
authnRequest.setIssuer(authIssuer)

val nameIDPolicy = new NameIDPolicyBuilder().buildObject()
nameIDPolicy.setAllowCreate(false)
nameIDPolicy.setFormat(NameIDType.PERSISTENT)
authnRequest.setNameIDPolicy(nameIDPolicy)

val marshaller = XMLObjectProviderRegistrySupport.getMarshallerFactory.getMarshaller(authnRequest)
marshaller.marshall(authnRequest)

Need to deflate the XML before putting it in SAMLRequest parameter

val byteArrayOutputStream = new ByteArrayOutputStream
val deflater              = new Deflater(Deflater.DEFLATED, true)
val deflaterOutputStream  = new DeflaterOutputStream(byteArrayOutputStream, deflater)
stream = Option(deflaterOutputStream)
deflaterOutputStream.write(request.getBytes)
deflaterOutputStream.close()

And lastly when you get the AuthnResponse it can be unmarshalled with the libraries as well. SignatureValidator can be used to check the response signature (for instance need to have identity provider credential set up, shortened some code here just for reference)

val base64DecodedResponse  = Base64.getDecoder.decode(responseEncoded)
val responseString         = new String(base64DecodedResponse)
val is                     = new ByteArrayInputStream(base64DecodedResponse)
val documentBuilderFactory = DocumentBuilderFactory.newInstance
documentBuilderFactory.setNamespaceAware(true)
val docBuilder     = documentBuilderFactory.newDocumentBuilder
val document       = docBuilder.parse(is)
val element        = document.getDocumentElement
val unmarshaller   = XMLObjectProviderRegistrySupport.getUnmarshallerFactory.getUnmarshaller(element)
val responseXmlObj = unmarshaller.unmarshall(element)
val assertion = responseXmlObj.asInstanceOf[Response].getAssertions.asScala.head
SignatureValidator.validate(assertion.getSignature, identityProviderCredential)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM