【问题标题】:Using OpenSAML to create and sign response (in Java) but having trouble validating the signature使用 OpenSAML 创建和签署响应(在 Java 中)但在验证签名时遇到问题
【发布时间】:2016-10-05 17:26:38
【问题描述】:

我可以使用 OpenSAML 创建 SAMLResponse,但作为健全性检查,我想验证签名。接收者希望对 Assertion 进行签名,而不是对 Response 进行签名,这看起来很好:

<?xml version="1.0" encoding="UTF-8"?>
<saml2p:Response ID="1111111111" Version="2.0"
    xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
    <saml2:Assertion Version="2.0"
        xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
        <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
            <ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"
                    xmlns:ds="http://www.w3.org/2000/09/xmldsig#" />
                <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"
                    xmlns:ds="http://www.w3.org/2000/09/xmldsig#" />
                <ds:Reference URI="" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                    <ds:Transforms xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                        <ds:Transform
                            Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"
                            xmlns:ds="http://www.w3.org/2000/09/xmldsig#" />
                        <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"
                            xmlns:ds="http://www.w3.org/2000/09/xmldsig#" />
                    </ds:Transforms>
                    <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"
                        xmlns:ds="http://www.w3.org/2000/09/xmldsig#" />
                    <ds:DigestValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">H1M/MSp4KUwKryB9c99XvE6PWaU=
                    </ds:DigestValue>
                </ds:Reference>
            </ds:SignedInfo>
            <ds:SignatureValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                npeqj35bPh06G6WcSBzfpaDEqVUzhEOgqARKB6NIowGcAoD6yHpmDYTJ0nXvS31cRFYxqWtCVIrX
                e7abo3mpwfLI7FjpEawP+8IEaMi++b0hN1Xri/bprMNjxB7kldDGJc2WkbdVRAAIknQetxytd9gB
                WGhP97zLyGPVK23orH/JF09bFgoqGPgd/14fuY5ksOJuFfuZD4rsCOxxicYrfMsJDnlUfz8n18Xw
                Jj6vX/0SDoDknMz9h4kh1TU4tus0FvIAPYLNB7QV7Iarpd+5Q9R8mj+NJEviFH/DZlqE/NYrxRNt
                iinOgOnz1x3dtnDr2O/BHIW55mlBFi0L6wJ7ow==
            </ds:SignatureValue>
        </ds:Signature>
    </saml2:Assertion>
</saml2p:Response>

如果我在编组响应之前验证签名,它是有效的:

protected static void testSignature(Credential credential) throws Exception {
    DefaultBootstrap.bootstrap();
    SignatureBuilder builder = new SignatureBuilder();
    Signature signature = builder.buildObject(); 
    signature.setSigningCredential(credential);
    signature.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1);
    signature.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);

    Assertion assertion = new AssertionBuilder().buildObject();
    assertion.setVersion(SAMLVersion.VERSION_20);   
    assertion.setSignature(signature);

    AssertionMarshaller aMarsh = new AssertionMarshaller();
    aMarsh.marshall(assertion);
    Signer.signObject(signature);

    Response response = new ResponseBuilder().buildObject();
    response.setVersion(SAMLVersion.VERSION_20);
    response.setID("1111111111");
    response.getAssertions().add(assertion);

    Signature sig = response.getAssertions().get(0).getSignature();

    SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator();        
    profileValidator.validate(sig);      
    SignatureValidator sigValidator = new SignatureValidator(credential);               
    sigValidator.validate(sig); //valid

}

但是,如果我通过添加以下代码来编组响应,即使我在编组之前设置了签名 ,它也会返回无效:

    ...

    Signature sig = response.getAssertions().get(0).getSignature();

    ResponseMarshaller rMarsh = new ResponseMarshaller();
    Element plain = rMarsh.marshall(response);


    SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator();        
    profileValidator.validate(sig);      
    SignatureValidator sigValidator = new SignatureValidator(credential);               
    sigValidator.validate(sig); //invalid

最后我尝试解组编组的响应,然后读取并验证签名,即使我可以验证响应与编组/解组之前相同,它仍然返回无效。

    ...

    ResponseMarshaller rMarsh = new ResponseMarshaller();
    Element plain = rMarsh.marshall(response);
    String samlResponse1 = XMLHelper.nodeToString(plain);

    UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory();
    Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(plain);
    XMLObject responseXmlObj = unmarshaller.unmarshall(plain);
    Response newResponse = (Response) responseXmlObj;


    plain = rMarsh.marshall(newResponse);
    String samlResponse2 = XMLHelper.nodeToString(plain);
    System.out.println(StringUtils.equals(samlResponse1, samlResponse2));  //true

    Signature sig = newResponse.getAssertions().get(0).getSignature();


    SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator();        
    profileValidator.validate(sig);      
    SignatureValidator sigValidator = new SignatureValidator(credential);               
    sigValidator.validate(sig);  //invalid

发生了什么事?我这里有什么遗漏吗?

【问题讨论】:

  • 原始 SAMLResponse 是否有换行符?如果是,换行符是什么?对我来说,大多数时候是因为换行符在处理步骤之间没有保持原样,在这种情况下是编组。

标签: java saml opensaml


【解决方案1】:

解决了这个问题。断言需要一个不同于响应 ID 的 ID 值。我只需要添加以下代码行就可以了。

assertion.setID("1111111112");

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-09
    • 1970-01-01
    • 2020-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多