Ok, I've done some more investigation and realized that my question is really a 
bit deeper than what I originally thought. I apologize in advance for the 
lengthy post. In this large, legacy CXF 2.3 / WSS4J 1.5 based code that I have, 
the intent is to add a SAML Assertion to a message as a signed supporting 
token. The way this worked previously is that the code would dynamically change 
the signature parts from the spring configuration:

from: {Element}{...}Body; STRTransform; {Element}{...}Timestamp; 
{Element}{...}Action; {Element}{...}To; {Element}{...}MessageID; 
{Element}{...}ReplyTo
To: {Element}{...}Body; Token; {Element}{...}Timestamp; {Element}{...}Action; 
{Element}{...}To; {Element}{...}MessageID; {Element}{...}ReplyTo; Assertion

The addReferencesToSign() would then later scan for Assertion, and add the 
appropriate references, like so:

        public void addReferencesToSign(@SuppressWarnings("rawtypes") Vector 
references, WSSecHeader secHeader)
                throws WSSecurityException
        {
            final Vector<Object> unalteredReferences = new Vector<Object>();
            
            try {
                for (int part = 0; part < references.size(); part++) {
                    final WSEncryptionPart encPart = (WSEncryptionPart) 
references.get(part);
                    final String elemName = encPart.getName();
                    if (elemName != null && "Assertion".equals(elemName)) {
                        final Transforms transforms = new Transforms(document);
                        Element ctx = createSTRParameter(document);
                        
transforms.addTransform(STRTransform.implementedTransformURI, ctx);
                        sig.addDocument("#" + this.assertionSecRefUri, 
transforms, this.getDigestAlgo());
                    }
                    else {
                        unalteredReferences.add(encPart);
                    }
                }
            } 

            super.addReferencesToSign(unalteredReferences, secHeader);
        }

Moving on to CXF 2.7 / WSS4J 1.6, I have two problems: Token is no longer a 
keyword you can use in signature parts, and transforms & references are added 
to signatures in a completely different way. I think I've fixed the latter 
problem, with code like this:

        public List<javax.xml.crypto.dsig.Reference> addReferencesToSign(
            @SuppressWarnings("rawtypes") List<WSEncryptionPart> references, 
WSSecHeader secHeader)
                throws WSSecurityException
        {
                List<javax.xml.crypto.dsig.Reference> referenceList = new 
ArrayList<javax.xml.crypto.dsig.Reference>();
                Transform transform = null;
                
            try {
                for (int part = 0; part < references.size(); part++) {
                    final WSEncryptionPart encPart = (WSEncryptionPart) 
references.get(part);

                    final String elemName = encPart.getName();
                    
                    if (elemName != null && "Assertion".equals(elemName)) {
                        Element ctx = createSTRParameter(document);
                        XMLStructure structure = new DOMStructure(ctx);
                        transform = 
signatureFactory.newTransform(STRTransform.TRANSFORM_URI, structure);
                        DigestMethod digestMethod = 
signatureFactory.newDigestMethod(this.getDigestAlgo(), null);
                        javax.xml.crypto.dsig.Reference reference = 
signatureFactory.newReference("#" + this.assertionSecRefUri, 
                                        digestMethod, 
Collections.singletonList(transform), null, null);
                        referenceList.add(reference);
                    }
                }
            } 
            
            referenceList.addAll( super.addReferencesToSign(references, 
secHeader) );
            return referenceList;
        }

Which may or may not work, but at least doesn't throw anything at the moment.  
The removal of Token, on the other hand, is still causing me some trouble. In 
general, I've replaced Token with {Element}{...}BinarySecurityToken, and that's 
worked and everything is happy. In this case, I get an exception that the 
signature can't be done because BinarySecurityToken isn't found:

Caused by: org.apache.ws.security.WSSecurityException: Signature creation 
failed (Cannot setup signature data structure)
        at 
org.apache.ws.security.message.WSSecSignatureBase.addReferencesToSign(WSSecSignatureBase.java:191)
        at 
org.apache.ws.security.message.WSSecSignature.addReferencesToSign(WSSecSignature.java:411)
        at 
gov.faa.swim.ssri.wss.wss4j.saml.SupportingSamlTokenSignedAction$WSSecSamlSupportingTokenSignature.addReferencesToSign(SupportingSamlTokenSignedAction.java:268)
        at 
gov.faa.swim.ssri.wss.wss4j.saml.SupportingSamlTokenSignedAction$WSSecSamlSupportingTokenSignature.build(SupportingSamlTokenSignedAction.java:156)
        at 
gov.faa.swim.ssri.wss.wss4j.saml.SupportingSamlTokenSignedAction.execute(SupportingSamlTokenSignedAction.java:110)
        ... 47 more
Caused by: org.apache.ws.security.WSSecurityException: General security error 
(WSEncryptBody/WSSignEnvelope: Element to encrypt/sign not found: 
http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd,
 BinarySecurityToken)
        at 
org.apache.ws.security.message.WSSecSignatureBase.addReferencesToSign(WSSecSignatureBase.java:160)

That leads me to believe that Token was a bit smarter keyword in the past, and 
I need to replace it with something smarter in the present to add the SAML 
Assertion as a signed supporting token. Which leads me to my questions:

1) How do I modify the Token in signature parts to end up with the SAML 
Assertion as a signed supporting token in my SOAP message?
2) Is it necessary in CXF 2.7 / WSS4J 1.6 to customize addReferencesToSign() to 
end up with a signed supporting token, or is there an easier / better way to go 
about it?

Thanx,

Stephen W. Chappell

Reply via email to