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 2011/01/21 15:48:42 UTC

svn commit: r1061829 - in /webservices/wss4j/trunk/src: main/java/org/apache/ws/security/message/WSSecEncryptedKey.java main/java/org/apache/ws/security/saml/WSSecSignatureSAML.java test/java/org/apache/ws/security/saml/SamlReferenceTest.java

Author: coheigea
Date: Fri Jan 21 14:48:41 2011
New Revision: 1061829

URL: http://svn.apache.org/viewvc?rev=1061829&view=rev
Log:
[WSS-146] - Added reference tests for SAML2 tokens

Modified:
    webservices/wss4j/trunk/src/main/java/org/apache/ws/security/message/WSSecEncryptedKey.java
    webservices/wss4j/trunk/src/main/java/org/apache/ws/security/saml/WSSecSignatureSAML.java
    webservices/wss4j/trunk/src/test/java/org/apache/ws/security/saml/SamlReferenceTest.java

Modified: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/message/WSSecEncryptedKey.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/message/WSSecEncryptedKey.java?rev=1061829&r1=1061828&r2=1061829&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/message/WSSecEncryptedKey.java (original)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/message/WSSecEncryptedKey.java Fri Jan 21 14:48:41 2011
@@ -301,26 +301,30 @@ public class WSSecEncryptedKey extends W
             
         case WSConstants.CUSTOM_SYMM_SIGNING :
             Reference refCust = new Reference(document);
-            refCust.setValueType(customEKTokenValueType);
-            refCust.setURI("#" + customEKTokenId);
-            secToken.setReference(refCust);
             if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(customEKTokenValueType)) {
                 secToken.addTokenType(WSConstants.WSS_SAML_TOKEN_TYPE);
+                refCust.setValueType(customEKTokenValueType);
             } else if (WSConstants.WSS_SAML2_KI_VALUE_TYPE.equals(customEKTokenValueType)) {
                 secToken.addTokenType(WSConstants.WSS_SAML2_TOKEN_TYPE);
+            } else {
+                refCust.setValueType(customEKTokenValueType);
             }
+            refCust.setURI("#" + customEKTokenId);
+            secToken.setReference(refCust);
             break;
             
         case WSConstants.CUSTOM_SYMM_SIGNING_DIRECT :
             Reference refCustd = new Reference(document);
-            refCustd.setValueType(customEKTokenValueType);
-            refCustd.setURI(customEKTokenId);
-            secToken.setReference(refCustd);
             if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(customEKTokenValueType)) {
                 secToken.addTokenType(WSConstants.WSS_SAML_TOKEN_TYPE);
+                refCustd.setValueType(customEKTokenValueType);
             } else if (WSConstants.WSS_SAML2_KI_VALUE_TYPE.equals(customEKTokenValueType)) {
                 secToken.addTokenType(WSConstants.WSS_SAML2_TOKEN_TYPE);
+            } else {
+                refCustd.setValueType(customEKTokenValueType);
             }
+            refCustd.setURI(customEKTokenId);
+            secToken.setReference(refCustd);
             break;
             
         case WSConstants.CUSTOM_KEY_IDENTIFIER:

Modified: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/saml/WSSecSignatureSAML.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/saml/WSSecSignatureSAML.java?rev=1061829&r1=1061828&r2=1061829&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/saml/WSSecSignatureSAML.java (original)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/saml/WSSecSignatureSAML.java Fri Jan 21 14:48:41 2011
@@ -335,7 +335,6 @@ public class WSSecSignatureSAML extends 
                         ref.setValueType(WSConstants.WSS_SAML_KI_VALUE_TYPE);
                         secRefSaml.addTokenType(WSConstants.WSS_SAML_TOKEN_TYPE);
                     } else if (assertion.getSaml2() != null) {
-                        ref.setValueType(WSConstants.WSS_SAML2_KI_VALUE_TYPE);
                         secRefSaml.addTokenType(WSConstants.WSS_SAML2_TOKEN_TYPE);
                     }
                     secRefSaml.setReference(ref);
@@ -400,7 +399,6 @@ public class WSSecSignatureSAML extends 
                 ref.setValueType(WSConstants.WSS_SAML_KI_VALUE_TYPE);
                 secRef.addTokenType(WSConstants.WSS_SAML_TOKEN_TYPE);
             } else if (assertion.getSaml2() != null) {
-                ref.setValueType(WSConstants.WSS_SAML2_KI_VALUE_TYPE);
                 secRef.addTokenType(WSConstants.WSS_SAML2_TOKEN_TYPE);
             }
             secRef.setReference(ref);

Modified: webservices/wss4j/trunk/src/test/java/org/apache/ws/security/saml/SamlReferenceTest.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/test/java/org/apache/ws/security/saml/SamlReferenceTest.java?rev=1061829&r1=1061828&r2=1061829&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/test/java/org/apache/ws/security/saml/SamlReferenceTest.java (original)
+++ webservices/wss4j/trunk/src/test/java/org/apache/ws/security/saml/SamlReferenceTest.java Fri Jan 21 14:48:41 2011
@@ -28,6 +28,7 @@ import org.apache.ws.security.WSSecurity
 import org.apache.ws.security.WSSecurityEngineResult;
 import org.apache.ws.security.common.KeystoreCallbackHandler;
 import org.apache.ws.security.common.SAML1CallbackHandler;
+import org.apache.ws.security.common.SAML2CallbackHandler;
 import org.apache.ws.security.common.SOAPUtil;
 import org.apache.ws.security.components.crypto.AbstractCrypto;
 import org.apache.ws.security.components.crypto.Crypto;
@@ -37,6 +38,7 @@ import org.apache.ws.security.message.WS
 import org.apache.ws.security.message.WSSecHeader;
 import org.apache.ws.security.saml.ext.AssertionWrapper;
 import org.apache.ws.security.saml.ext.builder.SAML1Constants;
+import org.apache.ws.security.saml.ext.builder.SAML2Constants;
 import org.apache.ws.security.util.Loader;
 import org.apache.ws.security.util.WSSecurityUtil;
 
@@ -141,7 +143,7 @@ public class SamlReferenceTest extends o
         xpath = wsDataRef.getXpath();
         assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/saml1:Assertion", xpath);
     }
-
+    
     /**
      * Test that creates, sends and processes an signed SAML 1.1 sender-vouches assertion,
      * where the SecurityTokenReference that points to the SAML Assertion uses a direct reference,
@@ -542,6 +544,418 @@ public class SamlReferenceTest extends o
         
     }
     
+    /**
+     * Test that creates, sends and processes an signed SAML 2 sender-vouches assertion,
+     * where the SecurityTokenReference that points to the SAML Assertion uses a KeyIdentifier,
+     * and not a direct reference.
+     */
+    @org.junit.Test
+    @SuppressWarnings("unchecked")
+    public void testSAML2SVKeyIdentifier() throws Exception {
+        SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
+        callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
+        callbackHandler.setConfirmationMethod(SAML2Constants.CONF_SENDER_VOUCHES);
+        SAMLIssuer saml = new SAMLIssuerImpl();
+        saml.setIssuerName("www.example.com");
+        saml.setCallbackHandler(callbackHandler);
+        saml.setSamlVersion("2.0");
+        AssertionWrapper assertion = saml.newAssertion();
+        
+        Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
+        WSSecHeader secHeader = new WSSecHeader();
+        secHeader.insertSecurityHeader(doc);
+        
+        WSSecSignatureSAML wsSign = new WSSecSignatureSAML();
+        Document signedDoc = 
+            wsSign.build(
+                doc, null, assertion, crypto, "16c73ab6-b892-458f-abf5-2f875f74882e", 
+                "security", secHeader
+            );
+
+        String outputString = 
+            org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Signed SAML2 message Key Identifier (sender vouches):");
+            LOG.debug(outputString);
+        }
+        assert outputString.contains(WSConstants.WSS_SAML2_KI_VALUE_TYPE);
+        assert outputString.contains(WSConstants.WSS_SAML2_TOKEN_TYPE);
+        
+        List<WSSecurityEngineResult> results = verify(signedDoc, crypto, null);
+        WSSecurityEngineResult actionResult =
+            WSSecurityUtil.fetchActionResult(results, WSConstants.ST_UNSIGNED);
+        AssertionWrapper receivedAssertion = 
+            (AssertionWrapper) actionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
+        assertTrue(receivedAssertion != null);
+        
+        // Test we processed a signature (SAML assertion + SOAP body)
+        actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.SIGN);
+        assertTrue(actionResult != null);
+        assertFalse(actionResult.isEmpty());
+        final List<WSDataRef> refs =
+            (List<WSDataRef>) actionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
+        assertTrue(refs.size() == 2);
+        
+        WSDataRef wsDataRef = (WSDataRef)refs.get(0);
+        String xpath = wsDataRef.getXpath();
+        assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Body", xpath);
+        
+        wsDataRef = (WSDataRef)refs.get(1);
+        xpath = wsDataRef.getXpath();
+        assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/saml2:Assertion", xpath);
+    }
+    
+    /**
+     * Test that creates, sends and processes an signed SAML 2 sender-vouches assertion,
+     * where the SecurityTokenReference that points to the SAML Assertion uses a direct reference,
+     * and not a KeyIdentifier. Unlike the SAML 1.1 case, this is spec-compliant.
+     */
+    @org.junit.Test
+    @SuppressWarnings("unchecked")
+    public void testSAML2SVDirectReference() throws Exception {
+    	SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
+        callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
+        callbackHandler.setConfirmationMethod(SAML2Constants.CONF_SENDER_VOUCHES);
+        SAMLIssuer saml = new SAMLIssuerImpl();
+        saml.setIssuerName("www.example.com");
+        saml.setCallbackHandler(callbackHandler);
+        saml.setSamlVersion("2.0");
+        AssertionWrapper assertion = saml.newAssertion();
+        
+        Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
+        WSSecHeader secHeader = new WSSecHeader();
+        secHeader.insertSecurityHeader(doc);
+        
+        WSSecSignatureSAML wsSign = new WSSecSignatureSAML();
+        wsSign.setUseDirectReferenceToAssertion(true);
+        Document signedDoc = 
+            wsSign.build(
+                doc, null, assertion, crypto, "16c73ab6-b892-458f-abf5-2f875f74882e", 
+                "security", secHeader
+            );
+
+        String outputString = 
+            org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Signed SAML2 message Direct Reference (sender vouches):");
+            LOG.debug(outputString);
+        }
+        assert !outputString.contains(WSConstants.WSS_SAML2_KI_VALUE_TYPE);
+        assert outputString.contains(WSConstants.WSS_SAML2_TOKEN_TYPE);
+        
+        List<WSSecurityEngineResult> results = verify(signedDoc, crypto, null);
+        WSSecurityEngineResult actionResult =
+            WSSecurityUtil.fetchActionResult(results, WSConstants.ST_UNSIGNED);
+        AssertionWrapper receivedAssertion = 
+            (AssertionWrapper) actionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
+        assertTrue(receivedAssertion != null);
+        
+        // Test we processed a signature (SAML assertion + SOAP body)
+        actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.SIGN);
+        assertTrue(actionResult != null);
+        assertFalse(actionResult.isEmpty());
+        final List<WSDataRef> refs =
+            (List<WSDataRef>) actionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
+        assertTrue(refs.size() == 2);
+        
+        WSDataRef wsDataRef = (WSDataRef)refs.get(0);
+        String xpath = wsDataRef.getXpath();
+        assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Body", xpath);
+        
+        wsDataRef = (WSDataRef)refs.get(1);
+        xpath = wsDataRef.getXpath();
+        assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/saml2:Assertion", xpath);
+    }
+    
+    /**
+     * Test that creates, sends and processes an signed SAML 2 holder-of-key assertion,
+     * where the SecurityTokenReference that points to the SAML Assertion uses a KeyIdentifier,
+     * and not a direct reference. This tests that we can process a KeyIdentifier to a SAML
+     * Assertion in the KeyInfo of a Signature.
+     */
+    @org.junit.Test
+    @SuppressWarnings("unchecked")
+    public void testSAML2HOKKeyIdentifier() throws Exception {
+        SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
+        callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
+        callbackHandler.setConfirmationMethod(SAML2Constants.CONF_HOLDER_KEY);
+        SAMLIssuer saml = new SAMLIssuerImpl();
+        saml.setIssuerName("www.example.com");
+        saml.setIssuerCrypto(issuerCrypto);
+        saml.setIssuerKeyName("wss40_server");
+        saml.setIssuerKeyPassword("security");
+        saml.setSignAssertion(true);
+        saml.setSamlVersion("2.0");
+        saml.setCallbackHandler(callbackHandler);
+        AssertionWrapper assertion = saml.newAssertion();
+
+        WSSecSignatureSAML wsSign = new WSSecSignatureSAML();
+        wsSign.setUserInfo("wss40", "security");
+        wsSign.setDigestAlgo("http://www.w3.org/2001/04/xmlenc#sha256");
+        wsSign.setSignatureAlgorithm("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
+
+        Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
+        WSSecHeader secHeader = new WSSecHeader();
+        secHeader.insertSecurityHeader(doc);
+
+        Document signedDoc = 
+            wsSign.build(doc, userCrypto, assertion, null, null, null, secHeader);
+
+        String outputString = 
+            org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Signed SAML2 message Key Identifier (holder-of-key):");
+            LOG.debug(outputString);
+        }
+        assert outputString.contains(WSConstants.WSS_SAML2_KI_VALUE_TYPE);
+        assert outputString.contains(WSConstants.WSS_SAML2_TOKEN_TYPE);
+        
+        List<WSSecurityEngineResult> results = verify(signedDoc, trustCrypto, null);
+        WSSecurityEngineResult actionResult =
+            WSSecurityUtil.fetchActionResult(results, WSConstants.ST_UNSIGNED);
+        AssertionWrapper receivedAssertion = 
+            (AssertionWrapper) actionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
+        assertTrue(receivedAssertion != null);
+        assert receivedAssertion.isSigned();
+        
+        // Test we processed a signature (SOAP body)
+        actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.SIGN);
+        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 = (WSDataRef)refs.get(0);
+        String xpath = wsDataRef.getXpath();
+        assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Body", xpath);
+    }
+    
+    
+    /**
+     * Test that creates, sends and processes an signed SAML 2 holder-of-key assertion,
+     * where the SecurityTokenReference that points to the SAML Assertion uses a direct reference,
+     * and not a KeyIdentifier. Unlike the SAML 1.1 case, this is spec-compliant. This tests that
+     * we can process a Direct Reference to a SAML Assertion in the KeyInfo of a Signature.
+     */
+    @org.junit.Test
+    @SuppressWarnings("unchecked")
+    public void testSAML2HOKDirectReference() throws Exception {
+        SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
+        callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
+        callbackHandler.setConfirmationMethod(SAML2Constants.CONF_HOLDER_KEY);
+        SAMLIssuer saml = new SAMLIssuerImpl();
+        saml.setIssuerName("www.example.com");
+        saml.setIssuerCrypto(issuerCrypto);
+        saml.setIssuerKeyName("wss40_server");
+        saml.setIssuerKeyPassword("security");
+        saml.setSignAssertion(true);
+        saml.setSamlVersion("2.0");
+        saml.setCallbackHandler(callbackHandler);
+        AssertionWrapper assertion = saml.newAssertion();
+
+        WSSecSignatureSAML wsSign = new WSSecSignatureSAML();
+        wsSign.setUserInfo("wss40", "security");
+        wsSign.setDigestAlgo("http://www.w3.org/2001/04/xmlenc#sha256");
+        wsSign.setSignatureAlgorithm("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
+        wsSign.setUseDirectReferenceToAssertion(true);
+        wsSign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
+
+        Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
+        WSSecHeader secHeader = new WSSecHeader();
+        secHeader.insertSecurityHeader(doc);
+
+        Document signedDoc = 
+            wsSign.build(doc, userCrypto, assertion, null, null, null, secHeader);
+
+        String outputString = 
+            org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Signed SAML2 message Direct Reference (holder-of-key):");
+            LOG.debug(outputString);
+        }
+        assert !outputString.contains(WSConstants.WSS_SAML2_KI_VALUE_TYPE);
+        assert outputString.contains(WSConstants.WSS_SAML2_TOKEN_TYPE);
+        
+        List<WSSecurityEngineResult> results = verify(signedDoc, trustCrypto, null);
+        WSSecurityEngineResult actionResult =
+            WSSecurityUtil.fetchActionResult(results, WSConstants.ST_UNSIGNED);
+        AssertionWrapper receivedAssertion = 
+            (AssertionWrapper) actionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
+        assertTrue(receivedAssertion != null);
+        assert receivedAssertion.isSigned();
+        
+        // Test we processed a signature (SOAP body)
+        actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.SIGN);
+        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 = (WSDataRef)refs.get(0);
+        String xpath = wsDataRef.getXpath();
+        assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Body", xpath);
+    }
+    
+    /**
+     * The body of the SOAP request is encrypted using a secret key, which is in turn encrypted
+     * using the certificate embedded in the SAML assertion and referenced using a Key Identifier.
+     * This tests that we can process a KeyIdentifier to a SAML Assertion in the KeyInfo of an
+     * EncryptedKey.
+     */
+    @org.junit.Test
+    @SuppressWarnings("unchecked")
+    public void testSAML2HOKEKKeyIdentifier() throws Exception {
+        // Create a SAML assertion
+        SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
+        callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
+        callbackHandler.setConfirmationMethod(SAML2Constants.CONF_HOLDER_KEY);
+        SAMLIssuer saml = new SAMLIssuerImpl();
+        saml.setIssuerName("www.example.com");
+        saml.setIssuerCrypto(issuerCrypto);
+        saml.setIssuerKeyName("wss40_server");
+        saml.setIssuerKeyPassword("security");
+        saml.setSignAssertion(true);
+        saml.setSamlVersion("2.0");
+        saml.setCallbackHandler(callbackHandler);;
+        AssertionWrapper assertion = saml.newAssertion();
+
+        Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
+        WSSecHeader secHeader = new WSSecHeader();
+        Node assertionNode = assertion.toDOM(doc);
+        secHeader.insertSecurityHeader(doc);
+        secHeader.getSecurityHeader().appendChild(assertionNode);
+        
+        // Encrypt the SOAP body
+        WSSecEncrypt builder = new WSSecEncrypt();
+        builder.setUserInfo("wss40");
+        builder.setSymmetricEncAlgorithm(WSConstants.TRIPLE_DES);
+        builder.setKeyIdentifierType(WSConstants.CUSTOM_KEY_IDENTIFIER);
+        builder.setCustomEKTokenValueType(WSConstants.WSS_SAML2_KI_VALUE_TYPE);
+        builder.setCustomEKTokenId(assertion.getId());
+        builder.prepare(doc, userCrypto);
+        
+        List<WSEncryptionPart> parts = new ArrayList<WSEncryptionPart>();
+        WSEncryptionPart encP = 
+            new WSEncryptionPart(
+                "add", "http://ws.apache.org/counter/counter_port_type", "Element"
+            );
+        parts.add(encP);
+        Element refElement = builder.encryptForRef(null, parts);
+        builder.addInternalRefElement(refElement);
+        builder.appendToHeader(secHeader);
+
+        String outputString = 
+            org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Encrypted SAML 2 message Key Identifier (holder-of-key):");
+            LOG.debug(outputString);
+        }
+        assert outputString.contains(WSConstants.WSS_SAML2_KI_VALUE_TYPE);
+        assert outputString.contains(WSConstants.WSS_SAML2_TOKEN_TYPE);
+        
+        List<WSSecurityEngineResult> results = verify(doc, trustCrypto, userCrypto);
+        WSSecurityEngineResult actionResult =
+            WSSecurityUtil.fetchActionResult(results, WSConstants.ST_UNSIGNED);
+        AssertionWrapper receivedAssertion = 
+            (AssertionWrapper) actionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
+        assertTrue(receivedAssertion != null);
+        assert receivedAssertion.isSigned();
+        
+        // Test we processed an encrypted element
+        actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.ENCR);
+        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 = (WSDataRef)refs.get(0);
+        String xpath = wsDataRef.getXpath();
+        assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Body/add", xpath);
+        
+    }
+    
+    /**
+     * The body of the SOAP request is encrypted using a secret key, which is in turn encrypted
+     * using the certificate embedded in the SAML assertion and referenced using Direct
+     * Reference. Unlike the SAML 1.1 case, this is spec-compliant. This tests that we can process
+     * a Direct Reference to a SAML Assertion in the KeyInfo of an EncryptedKey.
+     */
+    @org.junit.Test
+    @SuppressWarnings("unchecked")
+    public void testSAML2HOKEKDirectReference() throws Exception {
+        // Create a SAML assertion
+        SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
+        callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
+        callbackHandler.setConfirmationMethod(SAML2Constants.CONF_HOLDER_KEY);
+        SAMLIssuer saml = new SAMLIssuerImpl();
+        saml.setIssuerName("www.example.com");
+        saml.setIssuerCrypto(issuerCrypto);
+        saml.setIssuerKeyName("wss40_server");
+        saml.setIssuerKeyPassword("security");
+        saml.setSignAssertion(true);
+        saml.setSamlVersion("2.0");
+        saml.setCallbackHandler(callbackHandler);;
+        AssertionWrapper assertion = saml.newAssertion();
+
+        Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
+        WSSecHeader secHeader = new WSSecHeader();
+        Node assertionNode = assertion.toDOM(doc);
+        secHeader.insertSecurityHeader(doc);
+        secHeader.getSecurityHeader().appendChild(assertionNode);
+        
+        // Encrypt the SOAP body
+        WSSecEncrypt builder = new WSSecEncrypt();
+        builder.setUserInfo("wss40");
+        builder.setSymmetricEncAlgorithm(WSConstants.TRIPLE_DES);
+        builder.setKeyIdentifierType(WSConstants.CUSTOM_SYMM_SIGNING);
+        builder.setCustomEKTokenValueType(WSConstants.WSS_SAML2_KI_VALUE_TYPE);
+        builder.setCustomEKTokenId(assertion.getId());
+        builder.prepare(doc, userCrypto);
+        
+        List<WSEncryptionPart> parts = new ArrayList<WSEncryptionPart>();
+        WSEncryptionPart encP = 
+            new WSEncryptionPart(
+                "add", "http://ws.apache.org/counter/counter_port_type", "Element"
+            );
+        parts.add(encP);
+        Element refElement = builder.encryptForRef(null, parts);
+        builder.addInternalRefElement(refElement);
+        builder.appendToHeader(secHeader);
+
+        String outputString = 
+            org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Encrypted SAML 2 message Direct Reference (holder-of-key):");
+            LOG.debug(outputString);
+        }
+        assert !outputString.contains(WSConstants.WSS_SAML2_KI_VALUE_TYPE);
+        assert outputString.contains(WSConstants.WSS_SAML2_TOKEN_TYPE);
+        
+        List<WSSecurityEngineResult> results = verify(doc, trustCrypto, userCrypto);
+        WSSecurityEngineResult actionResult =
+            WSSecurityUtil.fetchActionResult(results, WSConstants.ST_UNSIGNED);
+        AssertionWrapper receivedAssertion = 
+            (AssertionWrapper) actionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
+        assertTrue(receivedAssertion != null);
+        assert receivedAssertion.isSigned();
+        
+        // Test we processed an encrypted element
+        actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.ENCR);
+        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 = (WSDataRef)refs.get(0);
+        String xpath = wsDataRef.getXpath();
+        assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Body/add", xpath);
+        
+    }
+    
     
     /**
      * Verifies the soap envelope