You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@cxf.apache.org by "Tomas Vanhala (JIRA)" <ji...@apache.org> on 2019/01/18 13:22:00 UTC

[jira] [Comment Edited] (CXF-7941) SamlValidator does not work with chain trust

    [ https://issues.apache.org/jira/browse/CXF-7941?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16746271#comment-16746271 ] 

Tomas Vanhala edited comment on CXF-7941 at 1/18/19 1:21 PM:
-------------------------------------------------------------

Thank you very much for confirming that chain trust should work. This prompted us to look closer at how we are creating the SOAP request messages in our internal testing.

We discovered that by changing the SAML request slightly, we were able to get WSS4J chain trust to work.

I am including three sample requests:
 * request-real-sanitised.xml
 * request-test-broken-sanitised.xml
 * request-test-working-sanitised.xml

All requests have the X.509 certificate as the value of wsse:BinarySecurityToken.

All requests sign the SAML Assertion.

The crucial difference between request-test-broken-sanitised.xml and request-test-working-sanitised.xml seems to be in the signature that is used to sign the SAML Assertion:
 * in request-test-broken-sanitised.xml, inside ds:KeyInfo there is the RSA public key
 * in request-test-working-sanitised.xml, inside ds:KeyInfo there is the the certificate

For the processing of request-test-broken-sanitised.xml, I have attached a stack trace leading to verifyTrust.

Does this confirm that there is not a problem in CXF/WSS4J ?

 

However, we are still not fully comfortable with our situation.

*The real request* (request-real-sanitised.xml) is produced by a partner organisation. It does not contain the certificate multiple times. The certificate appears once, as the value of wsse:BinarySecurityToken. In dsig:KeyInfo, the certificate is referenced by wsse:SecurityTokenReference. There is only one signature, which signs the elements: wsu:Timestamp, saml:Assertion, wsse:BinarySecurityToken.

*The test requests* are created by ourselves, using CXF. Our implementation generates two signatures:
 * The first signature signs the element saml2:Assertion. The signature contains a 2nd copy of the X.509 certificate.
 * The second signature signs the elements wsu:Timestamp, wsse:SecurityTokenReference, wsse:BinarySecurityToken. The signature contains a reference to the certificate in wsse:BinarySecurityToken.

The code that does this is as follows:
{code:java}
    static class SAMLCBHandler implements CallbackHandler {

        private final String issuer;
        private final String subjectName;
        private final String alias;
        private final String role;
        private Properties cryptoProps;

        public SAMLCBHandler(Properties cryptoProps, String issuer, String subjectName, String alias, String role) {
            this.cryptoProps = cryptoProps;
            this.issuer = issuer;
            this.subjectName = subjectName;
            this.alias = alias;
            this.role = role;
        }

        @Override
        public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {

            for (Callback cb: callbacks) {

                SAMLCallback scb = (SAMLCallback) cb;
                scb.setSamlVersion(Version.SAML_20);
                scb.setIssuer(issuer);

                SubjectBean subj = new SubjectBean();

                subj.setSubjectName(subjectName);
                subj.setSubjectConfirmationMethod(SAML2Constants.CONF_SENDER_VOUCHES);

                scb.setSubject(subj);

                List<AttributeStatementBean> asd = new ArrayList<>();
                AttributeBean roleBean = new AttributeBean("role", "role", Collections.singletonList((Object) role));
                ArrayList<AttributeBean> x = new ArrayList<AttributeBean>();
                x.add(roleBean);
                asd.add(new AttributeStatementBean(subj, x));

                scb.setAttributeStatementData(asd);
                scb.setSignAssertion(true);
            }
        }
{code}
Is it possible to modify the callback handler to build a request that bears more resemblance to the real requests?


was (Author: tomasv):
Thank you very much for confirming that chain trust should work. This prompted us to look closer at how we are creating the SOAP request messages in our internal testing.

We discovered that by changing the SAML request slightly, we were able to get WSS4J chain trust to work.

I am including three sample requests:
 * request-real-sanitised.xml
 * request-test-broken-sanitised.xml
 * request-test-working-sanitised.xml

All requests have the X.509 certificate as the value of wsse:BinarySecurityToken.

All requests sign the SAML Assertion.

The crucial difference between request-test-broken-sanitised.xml and request-test-working-sanitised.xml seems to be in the signature that is used to sign the SAML Assertion:
 * in request-test-broken-sanitised.xml, inside ds:KeyInfo there is the RSA public key
 * in request-test-working-sanitised.xml, inside ds:KeyInfo there is the the certificate

For the processing of request-test-broken-sanitised.xml, I have attached a stack trace leading to verifyTrust.

Does this confirm that there is not a problem in CXF/WSS4J ?

 

However, we are still not fully comfortable with our situation.

*The real request* (request-real-sanitised.xml) is produced by a partner organisation. It does not contain the certificate multiple times. The certificate appears once, as the value of wsse:BinarySecurityToken. In dsig:KeyInfo, the certificate is referenced by wsse:SecurityTokenReference. There is only one signature, which signs the elements: wsu:Timestamp, saml:Assertion, wsse:BinarySecurityToken.

*The test requests* are created by ourselves, using CXF. Our implementation generates two signatures:
 * the first signature signs the element saml2:Assertion
 * the second signature signs the elements wsu:Timestamp, wsse:SecurityTokenReference, wsse:BinarySecurityToken

The code that does this is as follows:
{code:java}
    static class SAMLCBHandler implements CallbackHandler {

        private final String issuer;
        private final String subjectName;
        private final String alias;
        private final String role;
        private Properties cryptoProps;

        public SAMLCBHandler(Properties cryptoProps, String issuer, String subjectName, String alias, String role) {
            this.cryptoProps = cryptoProps;
            this.issuer = issuer;
            this.subjectName = subjectName;
            this.alias = alias;
            this.role = role;
        }

        @Override
        public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {

            for (Callback cb: callbacks) {

                SAMLCallback scb = (SAMLCallback) cb;
                scb.setSamlVersion(Version.SAML_20);
                scb.setIssuer(issuer);

                SubjectBean subj = new SubjectBean();

                subj.setSubjectName(subjectName);
                subj.setSubjectConfirmationMethod(SAML2Constants.CONF_SENDER_VOUCHES);

                scb.setSubject(subj);

                List<AttributeStatementBean> asd = new ArrayList<>();
                AttributeBean roleBean = new AttributeBean("role", "role", Collections.singletonList((Object) role));
                ArrayList<AttributeBean> x = new ArrayList<AttributeBean>();
                x.add(roleBean);
                asd.add(new AttributeStatementBean(subj, x));

                scb.setAttributeStatementData(asd);
                scb.setSignAssertion(true);
            }
        }
{code}
Is it possible to modify the callback handler to build a request that bears more resemblance to the real requests?

> SamlValidator does not work with chain trust
> --------------------------------------------
>
>                 Key: CXF-7941
>                 URL: https://issues.apache.org/jira/browse/CXF-7941
>             Project: CXF
>          Issue Type: Bug
>          Components: WS-* Components
>    Affects Versions: 3.2.7
>            Reporter: Tomas Vanhala
>            Priority: Major
>         Attachments: cxf7941.zip, request-real-sanitised.xml, request-test-broken-sanitised.xml, request-test-working-sanitised.xml, stacktrace-request-test-broken.txt
>
>
> As explained here [http://coheigea.blogspot.com/2012/08/subject-dn-certificate-constraint.html,] WSS4J supports specifying constraints on the subject DN of the certificate used for signature validation.
> We have successfully applied "direct trust" when receiving SOAP requests containing a signed SAML token.
> We attempted to migrate to "chain trust" by removing the certificate used to sign the requests from the Merlin trust store, and setting an appropriate Subject DN Cert Constraint.
> It did not work. Our analysis is that WSS4J's SamlValidator is not able to handle a scenario where the certificate used to sign the requests is not in the trust store. The problem seems to be in the method findPublicKeyInKeyStore() of Merlin.java.
> We were able to make chain trust (and the Subject DN Cert Constraint) work by including the needed PKI code in a customised SamlValidator, but we would rather not go this route.
> Please fix chain trust in WSS4J SAML validation.



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)