Использование OpenSAML для создания и подписания ответа (на Java), но возникают проблемы с проверкой подписи

Я могу создать SAMLResponse с помощью OpenSAML, но в качестве проверки работоспособности я хотел проверить подпись. Получатель хочет, чтобы было подписано Утверждение, но не Ответ, что выглядит вполне нормально:

<?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

В чем дело? Есть ли что-то, что мне здесь не хватает?


person Andrew    schedule 05.10.2016    source источник
comment
Есть ли в исходном SAMLResponse разрывы строк? Если да, то какие символы разрыва строки? Для меня в большинстве случаев это связано с тем, что символы разрыва строки не сохраняются как есть между этапами обработки, что в данном случае является маршаллингом.   -  person Thuan    schedule 06.10.2016


Ответы (1)


Решил это. Утверждению требуется значение идентификатора, отличное от идентификатора ответа. Мне просто нужно было добавить следующую строку кода, и это сработало.

assertion.setID("1111111112");
person Andrew    schedule 06.10.2016