java - OpenSaml AuthnRequest 签名

标签 java single-sign-on saml saml-2.0 opensaml

我正在构建一个 SAML 2.0 AuthNRequest。
我设法使用 OpenSaml 添加了签名信息,但我找不到添加 <ds:SignatureValue/> 的方法和 <ds:DigestValue/>使用图书馆的值(value)。
这是代码:

    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;

我可以同时使用 HTTP-POST 绑定(bind)和 HTTP-REDIRECT 绑定(bind)。我试图使用 HTTP-POST 但如果有人可以解释如何使 HTTP-REDIRECT 签名被接受为答案。

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>

我目前的输出是:
<?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>

提前致谢

最佳答案

我前段时间解决了,所以我把回复放在这里以满足其他人的需要。

使用构建器创建 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);

this.getCredentialFromFiles() 方法从磁盘读取 x509 证书并构建 BasicX509Credential 对象

这是对 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) {

        }
    }

然后签署请求:
this.signRequest(request);

+1,如果你觉得它有用!

关于java - OpenSaml AuthnRequest 签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32454322/

相关文章:

java - 回文忽略空格和标点符号

java - 使用 Spring Security 委托(delegate)/转发 Kerberos 票证

azure - 尝试使用另一个 Azure 租户的 guest Azure AD 帐户通过 SSO 登录 Office 加载项

saml - 是否有 SAML 2.0 加密断言的标准格式

java - 在 Java 中编写和追加大文件的最佳方法是什么

java - 在饼图切片中间绘制带三角形的饼图

java - 如何从基于 java 的服务获取声音

tomcat - 如何为 SAML SP 元数据使用 Tomcat SSL 证书

Java XML 验证 : Unable to resolve definitions from local XSD files

grails - Spring Security SAML示例