You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ws.apache.org by co...@apache.org on 2017/12/04 12:18:19 UTC

svn commit: r1817085 - in /webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src: main/java/org/apache/wss4j/dom/action/ main/java/org/apache/wss4j/dom/message/ main/java/org/apache/wss4j/dom/saml/ test/java/org/apache/wss4j/dom/common/ test/java/...

Author: coheigea
Date: Mon Dec  4 12:18:19 2017
New Revision: 1817085

URL: http://svn.apache.org/viewvc?rev=1817085&view=rev
Log:
WSS-619 - Support adding a custom KeyInfo Element for Signature

(cherry picked from commit 1bb5e7d4b98a52a38c0cf885ab0449b98d8d966b)

Modified:
    webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/action/SAMLTokenSignedAction.java
    webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/action/SignatureAction.java
    webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/WSSecSignature.java
    webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/saml/WSSecSignatureSAML.java
    webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/test/java/org/apache/wss4j/dom/common/AbstractSAMLCallbackHandler.java
    webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/test/java/org/apache/wss4j/dom/saml/SignedSamlTokenHOKTest.java

Modified: webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/action/SAMLTokenSignedAction.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/action/SAMLTokenSignedAction.java?rev=1817085&r1=1817084&r2=1817085&view=diff
==============================================================================
--- webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/action/SAMLTokenSignedAction.java (original)
+++ webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/action/SAMLTokenSignedAction.java Mon Dec  4 12:18:19 2017
@@ -115,6 +115,9 @@ public class SAMLTokenSignedAction imple
         if (signatureToken.getC14nAlgorithm() != null) {
             wsSign.setSigCanonicalization(signatureToken.getC14nAlgorithm());
         }
+        if (signatureToken.getKeyInfoElement() != null) {
+            wsSign.setCustomKeyInfoElement(signatureToken.getKeyInfoElement());
+        }
 
         if (signatureToken.getParts().size() > 0) {
             wsSign.getParts().addAll(signatureToken.getParts());

Modified: webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/action/SignatureAction.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/action/SignatureAction.java?rev=1817085&r1=1817084&r2=1817085&view=diff
==============================================================================
--- webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/action/SignatureAction.java (original)
+++ webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/action/SignatureAction.java Mon Dec  4 12:18:19 2017
@@ -96,6 +96,9 @@ public class SignatureAction implements
         if (signatureToken.getSha1Value() != null) {
             wsSign.setEncrKeySha1value(signatureToken.getSha1Value());
         }
+        if (signatureToken.getKeyInfoElement() != null) {
+            wsSign.setCustomKeyInfoElement(signatureToken.getKeyInfoElement());
+        }
 
         wsSign.setAttachmentCallbackHandler(reqData.getAttachmentCallbackHandler());
         wsSign.setStoreBytesInAttachment(reqData.isStoreBytesInAttachment());

Modified: webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/WSSecSignature.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/WSSecSignature.java?rev=1817085&r1=1817084&r2=1817085&view=diff
==============================================================================
--- webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/WSSecSignature.java (original)
+++ webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/WSSecSignature.java Mon Dec  4 12:18:19 2017
@@ -23,6 +23,8 @@ import java.security.NoSuchProviderExcep
 import java.security.Provider;
 import java.security.cert.CertificateEncodingException;
 import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 import javax.xml.crypto.MarshalException;
@@ -110,6 +112,7 @@ public class WSSecSignature extends WSSe
     private boolean bstAddedToSecurityHeader;
     private boolean includeSignatureToken;
     private boolean addInclusivePrefixes = true;
+    private Element customKeyInfoElement;
 
     public WSSecSignature() {
         this(null);
@@ -184,7 +187,7 @@ public class WSSecSignature extends WSSe
         }
 
         keyInfoUri = getIdAllocator().createSecureId("KI-", keyInfo);
-        if (!useCustomSecRef) {
+        if (!useCustomSecRef && customKeyInfoElement == null) {
             secRef = new SecurityTokenReference(doc);
             strUri = getIdAllocator().createSecureId("STR-", secRef);
             secRef.addWSSENamespace();
@@ -322,9 +325,7 @@ public class WSSecSignature extends WSSe
                     KeyInfoFactory keyInfoFactory = signatureFactory.getKeyInfoFactory();
                     KeyValue keyValue = keyInfoFactory.newKeyValue(publicKey);
                     keyInfo =
-                        keyInfoFactory.newKeyInfo(
-                            java.util.Collections.singletonList(keyValue), keyInfoUri
-                        );
+                        keyInfoFactory.newKeyInfo(Collections.singletonList(keyValue), keyInfoUri);
                 } catch (java.security.KeyException ex) {
                     LOG.error("", ex);
                     throw new WSSecurityException(
@@ -338,16 +339,28 @@ public class WSSecSignature extends WSSe
         }
 
         if (keyIdentifierType != WSConstants.KEY_VALUE) {
+            marshalKeyInfo(wsDocInfo);
+        }
+    }
+
+    protected void marshalKeyInfo(WSDocInfo wsDocInfo) throws WSSecurityException {
+        List<XMLStructure> kiChildren = null;
+        if (customKeyInfoElement == null) {
             XMLStructure structure = new DOMStructure(secRef.getElement());
             wsDocInfo.addTokenElement(secRef.getElement(), false);
-            KeyInfoFactory keyInfoFactory = signatureFactory.getKeyInfoFactory();
-            keyInfo =
-                keyInfoFactory.newKeyInfo(
-                    java.util.Collections.singletonList(structure), keyInfoUri
-                );
+            kiChildren = Collections.singletonList(structure);
+        } else {
+            Node kiChild = customKeyInfoElement.getFirstChild();
+            kiChildren = new ArrayList<>();
+            while (kiChild != null) {
+                kiChildren.add(new DOMStructure(kiChild));
+                kiChild = kiChild.getNextSibling();
+            }
         }
-    }
 
+        KeyInfoFactory keyInfoFactory = signatureFactory.getKeyInfoFactory();
+        keyInfo = keyInfoFactory.newKeyInfo(kiChildren, keyInfoUri);
+    }
 
     /**
      * Builds a signed soap envelope.
@@ -905,4 +918,11 @@ public class WSSecSignature extends WSSe
         this.addInclusivePrefixes = addInclusivePrefixes;
     }
 
+    public void setCustomKeyInfoElement(Element keyInfoElement) {
+        this.customKeyInfoElement = keyInfoElement;
+    }
+
+    public Element getCustomKeyInfoElement() {
+        return customKeyInfoElement;
+    }
 }

Modified: webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/saml/WSSecSignatureSAML.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/saml/WSSecSignatureSAML.java?rev=1817085&r1=1817084&r2=1817085&view=diff
==============================================================================
--- webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/saml/WSSecSignatureSAML.java (original)
+++ webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/main/java/org/apache/wss4j/dom/saml/WSSecSignatureSAML.java Mon Dec  4 12:18:19 2017
@@ -23,13 +23,10 @@ import java.security.PublicKey;
 import java.security.cert.X509Certificate;
 import java.util.List;
 
-import javax.xml.crypto.XMLStructure;
-import javax.xml.crypto.dom.DOMStructure;
 import javax.xml.crypto.dsig.SignatureMethod;
 import javax.xml.crypto.dsig.SignedInfo;
 import javax.xml.crypto.dsig.XMLSignContext;
 import javax.xml.crypto.dsig.dom.DOMSignContext;
-import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
 import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
 import javax.xml.crypto.dsig.spec.ExcC14NParameterSpec;
 
@@ -385,81 +382,77 @@ public class WSSecSignatureSAML extends
         Document doc, SecurityTokenReference secRef, X509Certificate cert,
         Crypto crypto, SamlAssertionWrapper samlAssertion
     ) throws WSSecurityException {
-        if (senderVouches) {
-            switch (keyIdentifierType) {
-            case WSConstants.BST_DIRECT_REFERENCE:
+        if (getCustomKeyInfoElement() == null) {
+            if (senderVouches) {
+                switch (keyIdentifierType) {
+                case WSConstants.BST_DIRECT_REFERENCE:
+                    Reference ref = new Reference(doc);
+                    ref.setURI("#" + certUri);
+                    BinarySecurity binarySecurity = new X509Security(doc);
+                    ((X509Security) binarySecurity).setX509Certificate(cert);
+                    binarySecurity.setID(certUri);
+                    bstToken = binarySecurity.getElement();
+                    wsDocInfo.addTokenElement(bstToken, false);
+                    ref.setValueType(binarySecurity.getValueType());
+                    secRef.setReference(ref);
+                    break;
+
+                case WSConstants.X509_KEY_IDENTIFIER :
+                    secRef.setKeyIdentifier(cert);
+                    break;
+
+                case WSConstants.SKI_KEY_IDENTIFIER:
+                    secRef.setKeyIdentifierSKI(cert, crypto);
+                    break;
+
+                case WSConstants.THUMBPRINT_IDENTIFIER:
+                    secRef.setKeyIdentifierThumb(cert);
+                    break;
+
+                case WSConstants.ISSUER_SERIAL:
+                    final String issuer = cert.getIssuerDN().getName();
+                    final java.math.BigInteger serialNumber = cert.getSerialNumber();
+                    final DOMX509IssuerSerial domIssuerSerial =
+                            new DOMX509IssuerSerial(doc, issuer, serialNumber);
+                    final DOMX509Data domX509Data = new DOMX509Data(doc, domIssuerSerial);
+                    secRef.setUnknownElement(domX509Data.getElement());
+                    break;
+
+                default:
+                    throw new WSSecurityException(
+                        WSSecurityException.ErrorCode.FAILURE, "unsupportedKeyId"
+                    );
+                }
+            } else if (useDirectReferenceToAssertion) {
                 Reference ref = new Reference(doc);
-                ref.setURI("#" + certUri);
-                BinarySecurity binarySecurity = new X509Security(doc);
-                ((X509Security) binarySecurity).setX509Certificate(cert);
-                binarySecurity.setID(certUri);
-                bstToken = binarySecurity.getElement();
-                wsDocInfo.addTokenElement(bstToken, false);
-                ref.setValueType(binarySecurity.getValueType());
+                ref.setURI("#" + samlAssertion.getId());
+                if (samlAssertion.getSaml1() != null) {
+                    ref.setValueType(WSConstants.WSS_SAML_KI_VALUE_TYPE);
+                    secRef.addTokenType(WSConstants.WSS_SAML_TOKEN_TYPE);
+                } else if (samlAssertion.getSaml2() != null) {
+                    secRef.addTokenType(WSConstants.WSS_SAML2_TOKEN_TYPE);
+                }
                 secRef.setReference(ref);
-                break;
-
-            case WSConstants.X509_KEY_IDENTIFIER :
-                secRef.setKeyIdentifier(cert);
-                break;
-
-            case WSConstants.SKI_KEY_IDENTIFIER:
-                secRef.setKeyIdentifierSKI(cert, crypto);
-                break;
-
-            case WSConstants.THUMBPRINT_IDENTIFIER:
-                secRef.setKeyIdentifierThumb(cert);
-                break;
-
-            case WSConstants.ISSUER_SERIAL:
-                final String issuer = cert.getIssuerDN().getName();
-                final java.math.BigInteger serialNumber = cert.getSerialNumber();
-                final DOMX509IssuerSerial domIssuerSerial =
-                        new DOMX509IssuerSerial(document, issuer, serialNumber);
-                final DOMX509Data domX509Data = new DOMX509Data(document, domIssuerSerial);
-                secRef.setUnknownElement(domX509Data.getElement());
-                break;
-
-            default:
-                throw new WSSecurityException(
-                    WSSecurityException.ErrorCode.FAILURE, "unsupportedKeyId"
+            } else {
+                Element keyId = doc.createElementNS(WSConstants.WSSE_NS, "wsse:KeyIdentifier");
+                String valueType = null;
+                if (samlAssertion.getSaml1() != null) {
+                    valueType = WSConstants.WSS_SAML_KI_VALUE_TYPE;
+                    secRef.addTokenType(WSConstants.WSS_SAML_TOKEN_TYPE);
+                } else if (samlAssertion.getSaml2() != null) {
+                    valueType = WSConstants.WSS_SAML2_KI_VALUE_TYPE;
+                    secRef.addTokenType(WSConstants.WSS_SAML2_TOKEN_TYPE);
+                }
+                keyId.setAttributeNS(
+                    null, "ValueType", valueType
                 );
+                keyId.appendChild(doc.createTextNode(samlAssertion.getId()));
+                Element elem = secRef.getElement();
+                elem.appendChild(keyId);
             }
-        } else if (useDirectReferenceToAssertion) {
-            Reference ref = new Reference(doc);
-            ref.setURI("#" + samlAssertion.getId());
-            if (samlAssertion.getSaml1() != null) {
-                ref.setValueType(WSConstants.WSS_SAML_KI_VALUE_TYPE);
-                secRef.addTokenType(WSConstants.WSS_SAML_TOKEN_TYPE);
-            } else if (samlAssertion.getSaml2() != null) {
-                secRef.addTokenType(WSConstants.WSS_SAML2_TOKEN_TYPE);
-            }
-            secRef.setReference(ref);
-        } else {
-            Element keyId = doc.createElementNS(WSConstants.WSSE_NS, "wsse:KeyIdentifier");
-            String valueType = null;
-            if (samlAssertion.getSaml1() != null) {
-                valueType = WSConstants.WSS_SAML_KI_VALUE_TYPE;
-                secRef.addTokenType(WSConstants.WSS_SAML_TOKEN_TYPE);
-            } else if (samlAssertion.getSaml2() != null) {
-                valueType = WSConstants.WSS_SAML2_KI_VALUE_TYPE;
-                secRef.addTokenType(WSConstants.WSS_SAML2_TOKEN_TYPE);
-            }
-            keyId.setAttributeNS(
-                null, "ValueType", valueType
-            );
-            keyId.appendChild(doc.createTextNode(samlAssertion.getId()));
-            Element elem = secRef.getElement();
-            elem.appendChild(keyId);
-        }
-        XMLStructure structure = new DOMStructure(secRef.getElement());
-        wsDocInfo.addTokenElement(secRef.getElement(), false);
-
-        KeyInfoFactory keyInfoFactory = signatureFactory.getKeyInfoFactory();
-        keyInfo =
-            keyInfoFactory.newKeyInfo(
-                java.util.Collections.singletonList(structure), keyInfoUri
-            );
+        }
+
+        marshalKeyInfo(wsDocInfo);
     }
 
     /**

Modified: webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/test/java/org/apache/wss4j/dom/common/AbstractSAMLCallbackHandler.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/test/java/org/apache/wss4j/dom/common/AbstractSAMLCallbackHandler.java?rev=1817085&r1=1817084&r2=1817085&view=diff
==============================================================================
--- webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/test/java/org/apache/wss4j/dom/common/AbstractSAMLCallbackHandler.java (original)
+++ webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/test/java/org/apache/wss4j/dom/common/AbstractSAMLCallbackHandler.java Mon Dec  4 12:18:19 2017
@@ -80,6 +80,7 @@ public abstract class AbstractSAMLCallba
     private String issuerName;
     private String issuerPassword;
     private Element assertionAdviceElement;
+    private Element keyInfoElement;
 
     public void setSubjectConfirmationData(SubjectConfirmationDataBean subjectConfirmationData) {
         this.subjectConfirmationData = subjectConfirmationData;
@@ -137,7 +138,7 @@ public abstract class AbstractSAMLCallba
     public void setCustomAttributeValues(List<Object> customAttributeValues) {
         this.customAttributeValues = customAttributeValues;
     }
-    
+
     public DateTime getAuthenticationInstant() {
         return authenticationInstant;
     }
@@ -201,7 +202,9 @@ public abstract class AbstractSAMLCallba
 
     protected KeyInfoBean createKeyInfo() throws Exception {
         KeyInfoBean keyInfo = new KeyInfoBean();
-        if (statement == Statement.AUTHN) {
+        if (keyInfoElement != null) {
+            keyInfo.setElement(keyInfoElement);
+        } else if (statement == Statement.AUTHN) {
             keyInfo.setCertificate(certs[0]);
             keyInfo.setCertIdentifer(certIdentifier);
         } else if (statement == Statement.ATTR) {
@@ -221,16 +224,16 @@ public abstract class AbstractSAMLCallba
             Element encryptedKeyElement = encrKey.getEncryptedKeyElement();
 
             // Append the EncryptedKey to a KeyInfo element
-            Element keyInfoElement =
+            Element kiElement =
                 doc.createElementNS(
                     WSConstants.SIG_NS, WSConstants.SIG_PREFIX + ":" + WSConstants.KEYINFO_LN
                 );
-            keyInfoElement.setAttributeNS(
+            kiElement.setAttributeNS(
                 WSConstants.XMLNS_NS, "xmlns:" + WSConstants.SIG_PREFIX, WSConstants.SIG_NS
             );
-            keyInfoElement.appendChild(encryptedKeyElement);
+            kiElement.appendChild(encryptedKeyElement);
 
-            keyInfo.setElement(keyInfoElement);
+            keyInfo.setElement(kiElement);
         }
         return keyInfo;
     }
@@ -266,4 +269,12 @@ public abstract class AbstractSAMLCallba
     public void setAssertionAdviceElement(Element assertionAdviceElement) {
         this.assertionAdviceElement = assertionAdviceElement;
     }
+
+    public Element getKeyInfoElement() {
+        return keyInfoElement;
+    }
+
+    public void setKeyInfoElement(Element keyInfoElement) {
+        this.keyInfoElement = keyInfoElement;
+    }
 }

Modified: webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/test/java/org/apache/wss4j/dom/saml/SignedSamlTokenHOKTest.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/test/java/org/apache/wss4j/dom/saml/SignedSamlTokenHOKTest.java?rev=1817085&r1=1817084&r2=1817085&view=diff
==============================================================================
--- webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/test/java/org/apache/wss4j/dom/saml/SignedSamlTokenHOKTest.java (original)
+++ webservices/wss4j/branches/2_1_x-fixes/ws-security-dom/src/test/java/org/apache/wss4j/dom/saml/SignedSamlTokenHOKTest.java Mon Dec  4 12:18:19 2017
@@ -30,7 +30,9 @@ import org.apache.wss4j.dom.common.Secur
 import org.apache.wss4j.dom.engine.WSSConfig;
 import org.apache.wss4j.dom.engine.WSSecurityEngine;
 import org.apache.wss4j.dom.engine.WSSecurityEngineResult;
+import org.apache.wss4j.dom.handler.RequestData;
 import org.apache.wss4j.dom.handler.WSHandlerResult;
+import org.apache.wss4j.common.bsp.BSPRule;
 import org.apache.wss4j.common.crypto.Crypto;
 import org.apache.wss4j.common.crypto.CryptoFactory;
 import org.apache.wss4j.common.crypto.CryptoType;
@@ -43,15 +45,29 @@ import org.apache.wss4j.common.saml.buil
 import org.apache.wss4j.common.util.Loader;
 import org.apache.wss4j.common.util.XMLUtils;
 import org.apache.wss4j.dom.message.WSSecHeader;
+import org.apache.wss4j.dom.util.WSSecurityUtil;
 import org.junit.Test;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
 import javax.security.auth.callback.CallbackHandler;
+import javax.xml.crypto.XMLStructure;
+import javax.xml.crypto.dom.DOMCryptoContext;
+import javax.xml.crypto.dom.DOMStructure;
+import javax.xml.crypto.dsig.XMLSignatureFactory;
+import javax.xml.crypto.dsig.keyinfo.KeyInfo;
+import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
+import javax.xml.crypto.dsig.keyinfo.KeyValue;
+import javax.xml.crypto.dsig.keyinfo.X509Data;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
 
 import java.io.InputStream;
 import java.security.KeyStore;
 import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -674,6 +690,106 @@ public class SignedSamlTokenHOKTest exte
         final List<WSDataRef> refs =
             (List<WSDataRef>) actionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
         assertTrue(refs.size() == 1);
+
+        WSDataRef wsDataRef = refs.get(0);
+        String xpath = wsDataRef.getXpath();
+        assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Body", xpath);
+    }
+
+    // Add both the X509Data and KeyValue for both the Subject + Signature KeyInfo
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testX509DataAndKeyValue() throws Exception {
+        SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
+        callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
+        callbackHandler.setConfirmationMethod(SAML2Constants.CONF_HOLDER_KEY);
+        callbackHandler.setIssuer("www.example.com");
+
+        // Create the KeyInfo
+        DocumentBuilderFactory docBuilderFactory =
+            DocumentBuilderFactory.newInstance();
+        docBuilderFactory.setNamespaceAware(true);
+        DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
+        Document keyInfoDoc = docBuilder.newDocument();
+
+        Crypto crypto = CryptoFactory.getInstance("wss40.properties");
+        CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
+        cryptoType.setAlias("wss40");
+        X509Certificate[] certs = crypto.getX509Certificates(cryptoType);
+        java.security.PublicKey publicKey = certs[0].getPublicKey();
+
+        KeyInfoFactory keyInfoFactory =
+            XMLSignatureFactory.getInstance("DOM", "ApacheXMLDSig").getKeyInfoFactory();
+
+        // X.509
+        X509Data x509Data = keyInfoFactory.newX509Data(Collections.singletonList(certs[0]));
+
+        // KeyValue
+        KeyValue keyValue = keyInfoFactory.newKeyValue(publicKey);
+        List<XMLStructure> keyInfoContent = Arrays.asList(x509Data, keyValue);
+        KeyInfo keyInfo = keyInfoFactory.newKeyInfo(keyInfoContent, null);
+
+        // Marshal the KeyInfo to DOM
+        Element parent = keyInfoDoc.createElement("temp");
+        DOMCryptoContext cryptoContext = new DOMCryptoContext() { };
+        cryptoContext.putNamespacePrefix(WSConstants.SIG_NS, WSConstants.SIG_PREFIX);
+        keyInfo.marshal(new DOMStructure(parent), cryptoContext);
+
+        Element keyInfoElement = (Element)parent.getFirstChild();
+
+        callbackHandler.setKeyInfoElement(keyInfoElement);
+
+        SAMLCallback samlCallback = new SAMLCallback();
+        SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
+        SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
+
+        samlAssertion.signAssertion("wss40_server", "security", issuerCrypto, false);
+
+        Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
+        WSSecHeader secHeader = new WSSecHeader(doc);
+        secHeader.insertSecurityHeader();
+
+        WSSecSignatureSAML wsSign = new WSSecSignatureSAML();
+        wsSign.setUserInfo("wss40", "security");
+        wsSign.setCustomKeyInfoElement(keyInfoElement);
+
+        Document signedDoc =
+            wsSign.build(doc, userCrypto, samlAssertion, null, null, null, secHeader);
+
+        String outputString =
+            XMLUtils.prettyDocumentToString(signedDoc);
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Signed SAML 2 Authn Assertion (key holder):");
+            LOG.debug(outputString);
+        }
+
+        RequestData data = new RequestData();
+        data.setSigVerCrypto(userCrypto);
+
+        List<BSPRule> ignoredRules = new ArrayList<>();
+        ignoredRules.add(BSPRule.R5417);
+        ignoredRules.add(BSPRule.R5402);
+        data.setIgnoredBSPRules(ignoredRules);
+
+        Element securityHeader = WSSecurityUtil.getSecurityHeader(signedDoc, null);
+        WSHandlerResult results =
+            secEngine.processSecurityHeader(securityHeader, data);
+
+        // Test we processed a SAML assertion
+        WSSecurityEngineResult actionResult =
+            results.getActionResults().get(WSConstants.ST_SIGNED).get(0);
+        SamlAssertionWrapper receivedSamlAssertion =
+            (SamlAssertionWrapper) actionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
+        assertTrue(receivedSamlAssertion != null);
+        assertTrue(receivedSamlAssertion.isSigned());
+
+        // Test we processed a signature (SOAP body)
+        actionResult = results.getActionResults().get(WSConstants.SIGN).get(0);
+        assertTrue(actionResult != null);
+        assertFalse(actionResult.isEmpty());
+        final List<WSDataRef> refs =
+            (List<WSDataRef>) actionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
+        assertTrue(refs.size() == 1);
 
         WSDataRef wsDataRef = refs.get(0);
         String xpath = wsDataRef.getXpath();