简体   繁体   English

OpenSaml AuthnRequest 签名

[英]OpenSaml AuthnRequest signature

I'm building a SAML 2.0 AuthNRequest.我正在构建一个 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.我设法使用 OpenSaml 添加签名信息,但找不到使用库添加<ds:SignatureValue/><ds:DigestValue/> VALUES 的方法。 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.我可以同时使用 HTTP-POST 绑定和 HTTP-REDIRECT 绑定。 I was trying to use HTTP-POST but if someone can explain how to make a HTTP-REDIRECT signature is accepted as an answer.我试图使用 HTTP-POST,但如果有人可以解释如何制作 HTTP-REDIRECT 签名,则接受作为答案。

The ouput of HTTP-POST looks like: HTTP-POST 的输出如下所示:

    <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:使用构建器创建 AuthnRequest 对象时:

    // 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.getCredentialFromFiles() 从磁盘读取 x509 证书并构建 BasicX509Credential 对象

This is how to sign the XML object这是对 XML 对象进行签名的方法

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! +1 如果您觉得它有用!

With OpenSAML 4.0.使用 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.我得到了这样的东西,它是用 Scala 编写的,但可以非常轻松地转换为 Java 或其他一些 JVM 语言。 SignableXMLObject can be the AuthnRequest created with new AuthnRequestBuilder().buildObject() SignableXMLObject 可以是使用new AuthnRequestBuilder().buildObject()创建的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.还有 OpenSAML 4.0。 you need to trigger initialization like this instead of DefaultBootstrap:您需要像这样触发初始化而不是 DefaultBootstrap:

InitializationService.initialize()

Creating the AuthnRequest without signing, but you can call the signing on it:无需签名即可创建 AuthnRequest,但您可以在其上调用签名:

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需要在将 XML 放入SAMLRequest参数之前对其进行SAMLRequest

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.最后,当您获得 AuthnResponse 时,它​​也可以与库一起解组。 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) SignatureValidator 可用于检查响应签名(例如需要设置身份提供者凭据,这里缩短了一些代码仅供参考)

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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