1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.ws.security.saml;
21  
22  import org.apache.ws.security.WSConstants;
23  import org.apache.ws.security.WSDataRef;
24  import org.apache.ws.security.WSEncryptionPart;
25  import org.apache.ws.security.WSSConfig;
26  import org.apache.ws.security.WSSecurityEngine;
27  import org.apache.ws.security.WSSecurityEngineResult;
28  import org.apache.ws.security.common.KeystoreCallbackHandler;
29  import org.apache.ws.security.common.SAML1CallbackHandler;
30  import org.apache.ws.security.common.SAML2CallbackHandler;
31  import org.apache.ws.security.common.SOAPUtil;
32  import org.apache.ws.security.components.crypto.Crypto;
33  import org.apache.ws.security.components.crypto.CryptoFactory;
34  import org.apache.ws.security.components.crypto.Merlin;
35  import org.apache.ws.security.message.WSSecEncrypt;
36  import org.apache.ws.security.message.WSSecHeader;
37  import org.apache.ws.security.saml.ext.AssertionWrapper;
38  import org.apache.ws.security.saml.ext.SAMLParms;
39  import org.apache.ws.security.saml.ext.builder.SAML1Constants;
40  import org.apache.ws.security.saml.ext.builder.SAML2Constants;
41  import org.apache.ws.security.util.Loader;
42  import org.apache.ws.security.util.WSSecurityUtil;
43  
44  import org.w3c.dom.Document;
45  import org.w3c.dom.Element;
46  import org.w3c.dom.Node;
47  
48  import java.io.InputStream;
49  import java.security.KeyStore;
50  import java.util.List;
51  import java.util.ArrayList;
52  
53  import javax.security.auth.callback.CallbackHandler;
54  
55  /**
56   * Some tests for how SAML tokens are referenced.
57   */
58  public class SamlReferenceTest extends org.junit.Assert {
59      private static final org.apache.commons.logging.Log LOG = 
60          org.apache.commons.logging.LogFactory.getLog(SamlReferenceTest.class);
61      private WSSecurityEngine secEngine = new WSSecurityEngine();
62      private CallbackHandler callbackHandler = new KeystoreCallbackHandler();
63      private Crypto crypto = CryptoFactory.getInstance("crypto.properties");
64      private Crypto trustCrypto = null;
65      private Crypto issuerCrypto = null;
66      private Crypto userCrypto = CryptoFactory.getInstance("wss40.properties");
67      
68      public SamlReferenceTest() throws Exception {
69          WSSConfig.init();
70          // Load the issuer keystore
71          issuerCrypto = new Merlin();
72          KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
73          ClassLoader loader = Loader.getClassLoader(SignedSamlTokenHOKTest.class);
74          InputStream input = Merlin.loadInputStream(loader, "keys/wss40_server.jks");
75          keyStore.load(input, "security".toCharArray());
76          ((Merlin)issuerCrypto).setKeyStore(keyStore);
77          
78          // Load the server truststore
79          trustCrypto = new Merlin();
80          KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
81          input = Merlin.loadInputStream(loader, "keys/wss40CA.jks");
82          trustStore.load(input, "security".toCharArray());
83          ((Merlin)trustCrypto).setTrustStore(trustStore);
84      }
85      
86      /**
87       * Test that creates, sends and processes an signed SAML 1.1 sender-vouches assertion,
88       * where the SecurityTokenReference that points to the SAML Assertion uses a KeyIdentifier,
89       * and not a direct reference.
90       */
91      @org.junit.Test
92      @SuppressWarnings("unchecked")
93      public void testSAML1SVKeyIdentifier() throws Exception {
94          SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
95          callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
96          callbackHandler.setConfirmationMethod(SAML1Constants.CONF_SENDER_VOUCHES);
97          callbackHandler.setIssuer("www.example.com");
98          
99          SAMLParms samlParms = new SAMLParms();
100         samlParms.setCallbackHandler(callbackHandler);
101         AssertionWrapper assertion = new AssertionWrapper(samlParms);
102         
103         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
104         WSSecHeader secHeader = new WSSecHeader();
105         secHeader.insertSecurityHeader(doc);
106         
107         WSSecSignatureSAML wsSign = new WSSecSignatureSAML();
108         wsSign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
109         Document signedDoc = 
110             wsSign.build(
111                 doc, null, assertion, crypto, "16c73ab6-b892-458f-abf5-2f875f74882e", 
112                 "security", secHeader
113             );
114 
115         String outputString = 
116             org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
117         if (LOG.isDebugEnabled()) {
118             LOG.debug("Signed SAML message Key Identifier (sender vouches):");
119             LOG.debug(outputString);
120         }
121         assertTrue(outputString.contains(WSConstants.WSS_SAML_KI_VALUE_TYPE));
122         assertTrue(outputString.contains(WSConstants.WSS_SAML_TOKEN_TYPE));
123         
124         List<WSSecurityEngineResult> results = verify(signedDoc, crypto, null);
125         WSSecurityEngineResult actionResult =
126             WSSecurityUtil.fetchActionResult(results, WSConstants.ST_UNSIGNED);
127         AssertionWrapper receivedAssertion = 
128             (AssertionWrapper) actionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
129         assertTrue(receivedAssertion != null);
130         
131         // Test we processed a signature (SAML assertion + SOAP body)
132         actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.SIGN);
133         assertTrue(actionResult != null);
134         assertFalse(actionResult.isEmpty());
135         final List<WSDataRef> refs =
136             (List<WSDataRef>) actionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
137         assertTrue(refs.size() == 2);
138         
139         WSDataRef wsDataRef = (WSDataRef)refs.get(0);
140         String xpath = wsDataRef.getXpath();
141         assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Body", xpath);
142         
143         wsDataRef = (WSDataRef)refs.get(1);
144         xpath = wsDataRef.getXpath();
145         assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/saml1:Assertion", xpath);
146     }
147     
148     /**
149      * Test that creates, sends and processes an signed SAML 1.1 sender-vouches assertion,
150      * where the SecurityTokenReference that points to the SAML Assertion uses a direct reference,
151      * and not a KeyIdentifier. This method is not spec compliant and is included to make sure
152      * we can process third-party Assertions referenced in this way.
153      */
154     @org.junit.Test
155     @SuppressWarnings("unchecked")
156     public void testSAML1SVDirectReference() throws Exception {
157         SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
158         callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
159         callbackHandler.setConfirmationMethod(SAML1Constants.CONF_SENDER_VOUCHES);
160         callbackHandler.setIssuer("www.example.com");
161         
162         SAMLParms samlParms = new SAMLParms();
163         samlParms.setCallbackHandler(callbackHandler);
164         AssertionWrapper assertion = new AssertionWrapper(samlParms);
165         
166         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
167         WSSecHeader secHeader = new WSSecHeader();
168         secHeader.insertSecurityHeader(doc);
169         
170         WSSecSignatureSAML wsSign = new WSSecSignatureSAML();
171         wsSign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
172         wsSign.setUseDirectReferenceToAssertion(true);
173         Document signedDoc = 
174             wsSign.build(
175                 doc, null, assertion, crypto, "16c73ab6-b892-458f-abf5-2f875f74882e", 
176                 "security", secHeader
177             );
178 
179         String outputString = 
180             org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
181         if (LOG.isDebugEnabled()) {
182             LOG.debug("Signed SAML message Direct Reference (sender vouches):");
183             LOG.debug(outputString);
184         }
185         assertTrue(outputString.contains(WSConstants.WSS_SAML_KI_VALUE_TYPE));
186         assertTrue(outputString.contains(WSConstants.WSS_SAML_TOKEN_TYPE));
187         
188         List<WSSecurityEngineResult> results = verify(signedDoc, crypto, null);
189         WSSecurityEngineResult actionResult =
190             WSSecurityUtil.fetchActionResult(results, WSConstants.ST_UNSIGNED);
191         AssertionWrapper receivedAssertion = 
192             (AssertionWrapper) actionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
193         assertTrue(receivedAssertion != null);
194         
195         // Test we processed a signature (SAML assertion + SOAP body)
196         actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.SIGN);
197         assertTrue(actionResult != null);
198         assertFalse(actionResult.isEmpty());
199         final List<WSDataRef> refs =
200             (List<WSDataRef>) actionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
201         assertTrue(refs.size() == 2);
202         
203         WSDataRef wsDataRef = (WSDataRef)refs.get(0);
204         String xpath = wsDataRef.getXpath();
205         assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Body", xpath);
206         
207         wsDataRef = (WSDataRef)refs.get(1);
208         xpath = wsDataRef.getXpath();
209         assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/saml1:Assertion", xpath);
210     }
211     
212     /**
213      * Test that creates, sends and processes an signed SAML 1.1 holder-of-key assertion,
214      * where the SecurityTokenReference that points to the SAML Assertion uses a KeyIdentifier,
215      * and not a direct reference. This tests that we can process a KeyIdentifier to a SAML
216      * Assertion in the KeyInfo of a Signature.
217      */
218     @org.junit.Test
219     @SuppressWarnings("unchecked")
220     public void testSAML1HOKKeyIdentifier() throws Exception {
221         SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
222         callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
223         callbackHandler.setConfirmationMethod(SAML1Constants.CONF_HOLDER_KEY);
224         callbackHandler.setIssuer("www.example.com");
225         
226         SAMLParms samlParms = new SAMLParms();
227         samlParms.setCallbackHandler(callbackHandler);
228         AssertionWrapper assertion = new AssertionWrapper(samlParms);
229         assertion.signAssertion("wss40_server", "security", issuerCrypto, false);
230 
231         WSSecSignatureSAML wsSign = new WSSecSignatureSAML();
232         wsSign.setUserInfo("wss40", "security");
233         wsSign.setDigestAlgo("http://www.w3.org/2001/04/xmlenc#sha256");
234         wsSign.setSignatureAlgorithm("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
235 
236         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
237         WSSecHeader secHeader = new WSSecHeader();
238         secHeader.insertSecurityHeader(doc);
239 
240         Document signedDoc = 
241             wsSign.build(doc, userCrypto, assertion, null, null, null, secHeader);
242 
243         String outputString = 
244             org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
245         if (LOG.isDebugEnabled()) {
246             LOG.debug("Signed SAML message Key Identifier (holder-of-key):");
247             LOG.debug(outputString);
248         }
249         assertTrue(outputString.contains(WSConstants.WSS_SAML_KI_VALUE_TYPE));
250         assertTrue(outputString.contains(WSConstants.WSS_SAML_TOKEN_TYPE));
251         
252         List<WSSecurityEngineResult> results = verify(signedDoc, trustCrypto, null);
253         WSSecurityEngineResult actionResult =
254             WSSecurityUtil.fetchActionResult(results, WSConstants.ST_SIGNED);
255         AssertionWrapper receivedAssertion = 
256             (AssertionWrapper) actionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
257         assertTrue(receivedAssertion != null);
258         assertTrue(receivedAssertion.isSigned());
259         
260         // Test we processed a signature (SOAP body)
261         actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.SIGN);
262         assertTrue(actionResult != null);
263         assertFalse(actionResult.isEmpty());
264         final List<WSDataRef> refs =
265             (List<WSDataRef>) actionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
266         assertTrue(refs.size() == 1);
267         
268         WSDataRef wsDataRef = (WSDataRef)refs.get(0);
269         String xpath = wsDataRef.getXpath();
270         assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Body", xpath);
271     }
272     
273     /**
274      * Test that creates, sends and processes an signed SAML 1.1 holder-of-key assertion,
275      * where the SecurityTokenReference that points to the SAML Assertion uses a direct reference,
276      * and not a KeyIdentifier. This method is not spec compliant and is included to make sure
277      * we can process third-party Assertions referenced in this way. This tests that we can 
278      * process a Direct Reference to a SAML Assertion in the KeyInfo of a Signature.
279      */
280     @org.junit.Test
281     @SuppressWarnings("unchecked")
282     public void testSAML1HOKDirectReference() throws Exception {
283         SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
284         callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
285         callbackHandler.setConfirmationMethod(SAML1Constants.CONF_HOLDER_KEY);
286         callbackHandler.setIssuer("www.example.com");
287         
288         SAMLParms samlParms = new SAMLParms();
289         samlParms.setCallbackHandler(callbackHandler);
290         AssertionWrapper assertion = new AssertionWrapper(samlParms);
291         assertion.signAssertion("wss40_server", "security", issuerCrypto, false);
292 
293         WSSecSignatureSAML wsSign = new WSSecSignatureSAML();
294         wsSign.setUserInfo("wss40", "security");
295         wsSign.setDigestAlgo("http://www.w3.org/2001/04/xmlenc#sha256");
296         wsSign.setSignatureAlgorithm("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
297         wsSign.setUseDirectReferenceToAssertion(true);
298         wsSign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
299 
300         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
301         WSSecHeader secHeader = new WSSecHeader();
302         secHeader.insertSecurityHeader(doc);
303 
304         Document signedDoc = 
305             wsSign.build(doc, userCrypto, assertion, null, null, null, secHeader);
306 
307         String outputString = 
308             org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
309         if (LOG.isDebugEnabled()) {
310             LOG.debug("Signed SAML message Direct Reference (holder-of-key):");
311             LOG.debug(outputString);
312         }
313         assertTrue(outputString.contains(WSConstants.WSS_SAML_KI_VALUE_TYPE));
314         assertTrue(outputString.contains(WSConstants.WSS_SAML_TOKEN_TYPE));
315         
316         List<WSSecurityEngineResult> results = verify(signedDoc, trustCrypto, null);
317         WSSecurityEngineResult actionResult =
318             WSSecurityUtil.fetchActionResult(results, WSConstants.ST_SIGNED);
319         AssertionWrapper receivedAssertion = 
320             (AssertionWrapper) actionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
321         assertTrue(receivedAssertion != null);
322         assertTrue(receivedAssertion.isSigned());
323         
324         // Test we processed a signature (SOAP body)
325         actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.SIGN);
326         assertTrue(actionResult != null);
327         assertFalse(actionResult.isEmpty());
328         final List<WSDataRef> refs =
329             (List<WSDataRef>) actionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
330         assertTrue(refs.size() == 1);
331         
332         WSDataRef wsDataRef = (WSDataRef)refs.get(0);
333         String xpath = wsDataRef.getXpath();
334         assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Body", xpath);
335     }
336 
337     /**
338      * WS-Security Test Case for WSS-178 - "signature verification failure of signed saml token
339      * due to "The Reference for URI (bst-saml-uri) has no XMLSignatureInput".
340      * 
341      * The problem is that the signature is referring to a SecurityTokenReference via the 
342      * STRTransform, which in turn is referring to the SAML Assertion. The request is putting 
343      * the SAML Assertion below the SecurityTokenReference, and this is causing 
344      * SecurityTokenReference.getTokenElement to fail.
345      */
346     @org.junit.Test
347     public void testAssertionBelowSTR() throws Exception {
348         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
349         WSSecHeader secHeader = new WSSecHeader();
350         secHeader.insertSecurityHeader(doc);
351         
352         SAMLIssuer saml = SAMLIssuerFactory.getInstance("saml_sv.properties");
353         AssertionWrapper assertion = saml.newAssertion();
354         Crypto crypto = CryptoFactory.getInstance("crypto.properties");
355         WSSecSignatureSAML wsSign = new WSSecSignatureSAML();
356         wsSign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
357         Document samlDoc = 
358             wsSign.build(doc, null, assertion, crypto, 
359                 "16c73ab6-b892-458f-abf5-2f875f74882e", "security", secHeader
360             );
361         
362         WSSecEncrypt builder = new WSSecEncrypt();
363         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e");
364         builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
365         Document encryptedDoc = builder.build(samlDoc, crypto, secHeader);
366         
367         //
368         // Remove the assertion its place in the security header and then append it
369         //
370         org.w3c.dom.Element secHeaderElement = secHeader.getSecurityHeader();
371         org.w3c.dom.Node assertionNode = 
372             secHeaderElement.getElementsByTagNameNS(WSConstants.SAML_NS, "Assertion").item(0);
373         secHeaderElement.removeChild(assertionNode);
374         secHeaderElement.appendChild(assertionNode);
375 
376         String outputString = 
377             org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(encryptedDoc);
378         if (LOG.isDebugEnabled()) {
379             LOG.debug("Encrypted message:");
380             LOG.debug(outputString);
381         }
382         assertTrue(outputString.contains(WSConstants.WSS_SAML_KI_VALUE_TYPE));
383         assertTrue(outputString.contains(WSConstants.WSS_SAML_TOKEN_TYPE));
384         
385         verify(encryptedDoc, crypto, crypto);
386     }
387     
388     
389     /**
390      * The body of the SOAP request is encrypted using a secret key, which is in turn encrypted
391      * using the certificate embedded in the SAML assertion and referenced using a Key Identifier.
392      * This tests that we can process a KeyIdentifier to a SAML Assertion in the KeyInfo of an
393      * EncryptedKey.
394      */
395     @org.junit.Test
396     @SuppressWarnings("unchecked")
397     public void testSAML1HOKEKKeyIdentifier() throws Exception {
398         // Create a SAML assertion
399         SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
400         callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
401         callbackHandler.setConfirmationMethod(SAML1Constants.CONF_HOLDER_KEY);
402         callbackHandler.setIssuer("www.example.com");
403         
404         SAMLParms samlParms = new SAMLParms();
405         samlParms.setCallbackHandler(callbackHandler);
406         AssertionWrapper assertion = new AssertionWrapper(samlParms);
407         assertion.signAssertion("wss40_server", "security", issuerCrypto, false);
408 
409         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
410         WSSecHeader secHeader = new WSSecHeader();
411         Node assertionNode = assertion.toDOM(doc);
412         secHeader.insertSecurityHeader(doc);
413         secHeader.getSecurityHeader().appendChild(assertionNode);
414         
415         // Encrypt the SOAP body
416         WSSecEncrypt builder = new WSSecEncrypt();
417         builder.setUserInfo("wss40");
418         builder.setSymmetricEncAlgorithm(WSConstants.TRIPLE_DES);
419         builder.setKeyIdentifierType(WSConstants.CUSTOM_KEY_IDENTIFIER);
420         builder.setCustomEKTokenValueType(WSConstants.WSS_SAML_KI_VALUE_TYPE);
421         builder.setCustomEKTokenId(assertion.getId());
422         builder.prepare(doc, userCrypto);
423         
424         List<WSEncryptionPart> parts = new ArrayList<WSEncryptionPart>();
425         WSEncryptionPart encP = 
426             new WSEncryptionPart(
427                 "add", "http://ws.apache.org/counter/counter_port_type", "Element"
428             );
429         parts.add(encP);
430         Element refElement = builder.encryptForRef(null, parts);
431         builder.addInternalRefElement(refElement);
432         builder.appendToHeader(secHeader);
433 
434         String outputString = 
435             org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
436         if (LOG.isDebugEnabled()) {
437             LOG.debug("Encrypted SAML 1.1 message Key Identifier (holder-of-key):");
438             LOG.debug(outputString);
439         }
440         assertTrue(outputString.contains(WSConstants.WSS_SAML_KI_VALUE_TYPE));
441         assertTrue(outputString.contains(WSConstants.WSS_SAML_TOKEN_TYPE));
442         
443         List<WSSecurityEngineResult> results = verify(doc, trustCrypto, userCrypto);
444         WSSecurityEngineResult actionResult =
445             WSSecurityUtil.fetchActionResult(results, WSConstants.ST_SIGNED);
446         AssertionWrapper receivedAssertion = 
447             (AssertionWrapper) actionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
448         assertTrue(receivedAssertion != null);
449         assertTrue(receivedAssertion.isSigned());
450         
451         // Test we processed an encrypted element
452         actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.ENCR);
453         assertTrue(actionResult != null);
454         assertFalse(actionResult.isEmpty());
455         final List<WSDataRef> refs =
456             (List<WSDataRef>) actionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
457         assertTrue(refs.size() == 1);
458         
459         WSDataRef wsDataRef = (WSDataRef)refs.get(0);
460         String xpath = wsDataRef.getXpath();
461         assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Body/add", xpath);
462         
463     }
464     
465     /**
466      * The body of the SOAP request is encrypted using a secret key, which is in turn encrypted
467      * using the certificate embedded in the SAML assertion and referenced using Direct
468      * Reference. This method is not spec compliant and is included to make sure we can process 
469      * third-party Assertions referenced in this way. This tests that we can process a Direct
470      * Reference to a SAML Assertion in the KeyInfo of an EncryptedKey.
471      */
472     @org.junit.Test
473     @SuppressWarnings("unchecked")
474     public void testSAML1HOKEKDirectReference() throws Exception {
475         // Create a SAML assertion
476         SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
477         callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
478         callbackHandler.setConfirmationMethod(SAML1Constants.CONF_HOLDER_KEY);
479         callbackHandler.setIssuer("www.example.com");
480         
481         SAMLParms samlParms = new SAMLParms();
482         samlParms.setCallbackHandler(callbackHandler);
483         AssertionWrapper assertion = new AssertionWrapper(samlParms);
484         assertion.signAssertion("wss40_server", "security", issuerCrypto, false);
485         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
486         WSSecHeader secHeader = new WSSecHeader();
487         Node assertionNode = assertion.toDOM(doc);
488         secHeader.insertSecurityHeader(doc);
489         secHeader.getSecurityHeader().appendChild(assertionNode);
490         
491         // Encrypt the SOAP body
492         WSSecEncrypt builder = new WSSecEncrypt();
493         builder.setUserInfo("wss40");
494         builder.setSymmetricEncAlgorithm(WSConstants.TRIPLE_DES);
495         builder.setKeyIdentifierType(WSConstants.CUSTOM_SYMM_SIGNING);
496         builder.setCustomEKTokenValueType(WSConstants.WSS_SAML_KI_VALUE_TYPE);
497         builder.setCustomEKTokenId(assertion.getId());
498         builder.prepare(doc, userCrypto);
499         
500         List<WSEncryptionPart> parts = new ArrayList<WSEncryptionPart>();
501         WSEncryptionPart encP = 
502             new WSEncryptionPart(
503                 "add", "http://ws.apache.org/counter/counter_port_type", "Element"
504             );
505         parts.add(encP);
506         Element refElement = builder.encryptForRef(null, parts);
507         builder.addInternalRefElement(refElement);
508         builder.appendToHeader(secHeader);
509 
510         String outputString = 
511             org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
512         if (LOG.isDebugEnabled()) {
513             LOG.debug("Encrypted SAML 1.1 message Direct Reference (holder-of-key):");
514             LOG.debug(outputString);
515         }
516         assertTrue(outputString.contains(WSConstants.WSS_SAML_KI_VALUE_TYPE));
517         assertTrue(outputString.contains(WSConstants.WSS_SAML_TOKEN_TYPE));
518         
519         List<WSSecurityEngineResult> results = verify(doc, trustCrypto, userCrypto);
520         WSSecurityEngineResult actionResult =
521             WSSecurityUtil.fetchActionResult(results, WSConstants.ST_SIGNED);
522         AssertionWrapper receivedAssertion = 
523             (AssertionWrapper) actionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
524         assertTrue(receivedAssertion != null);
525         assertTrue(receivedAssertion.isSigned());
526         
527         // Test we processed an encrypted element
528         actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.ENCR);
529         assertTrue(actionResult != null);
530         assertFalse(actionResult.isEmpty());
531         final List<WSDataRef> refs =
532             (List<WSDataRef>) actionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
533         assertTrue(refs.size() == 1);
534         
535         WSDataRef wsDataRef = (WSDataRef)refs.get(0);
536         String xpath = wsDataRef.getXpath();
537         assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Body/add", xpath);
538     }
539     
540     /**
541      * Test that creates, sends and processes an signed SAML 2 sender-vouches assertion,
542      * where the SecurityTokenReference that points to the SAML Assertion uses a KeyIdentifier,
543      * and not a direct reference.
544      */
545     @org.junit.Test
546     @SuppressWarnings("unchecked")
547     public void testSAML2SVKeyIdentifier() throws Exception {
548         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
549         callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
550         callbackHandler.setConfirmationMethod(SAML2Constants.CONF_SENDER_VOUCHES);
551         callbackHandler.setIssuer("www.example.com");
552         
553         SAMLParms samlParms = new SAMLParms();
554         samlParms.setCallbackHandler(callbackHandler);
555         AssertionWrapper assertion = new AssertionWrapper(samlParms);
556         
557         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
558         WSSecHeader secHeader = new WSSecHeader();
559         secHeader.insertSecurityHeader(doc);
560         
561         WSSecSignatureSAML wsSign = new WSSecSignatureSAML();
562         wsSign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
563         Document signedDoc = 
564             wsSign.build(
565                 doc, null, assertion, crypto, "16c73ab6-b892-458f-abf5-2f875f74882e", 
566                 "security", secHeader
567             );
568 
569         String outputString = 
570             org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
571         if (LOG.isDebugEnabled()) {
572             LOG.debug("Signed SAML2 message Key Identifier (sender vouches):");
573             LOG.debug(outputString);
574         }
575         assertTrue(outputString.contains(WSConstants.WSS_SAML2_KI_VALUE_TYPE));
576         assertTrue(outputString.contains(WSConstants.WSS_SAML2_TOKEN_TYPE));
577         
578         List<WSSecurityEngineResult> results = verify(signedDoc, crypto, null);
579         WSSecurityEngineResult actionResult =
580             WSSecurityUtil.fetchActionResult(results, WSConstants.ST_UNSIGNED);
581         AssertionWrapper receivedAssertion = 
582             (AssertionWrapper) actionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
583         assertTrue(receivedAssertion != null);
584         
585         // Test we processed a signature (SAML assertion + SOAP body)
586         actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.SIGN);
587         assertTrue(actionResult != null);
588         assertFalse(actionResult.isEmpty());
589         final List<WSDataRef> refs =
590             (List<WSDataRef>) actionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
591         assertTrue(refs.size() == 2);
592         
593         WSDataRef wsDataRef = (WSDataRef)refs.get(0);
594         String xpath = wsDataRef.getXpath();
595         assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Body", xpath);
596         
597         wsDataRef = (WSDataRef)refs.get(1);
598         xpath = wsDataRef.getXpath();
599         assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/saml2:Assertion", xpath);
600     }
601     
602     /**
603      * Test that creates, sends and processes an signed SAML 2 sender-vouches assertion,
604      * where the SecurityTokenReference that points to the SAML Assertion uses a direct reference,
605      * and not a KeyIdentifier. Unlike the SAML 1.1 case, this is spec-compliant.
606      */
607     @org.junit.Test
608     @SuppressWarnings("unchecked")
609     public void testSAML2SVDirectReference() throws Exception {
610     	SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
611         callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
612         callbackHandler.setConfirmationMethod(SAML2Constants.CONF_SENDER_VOUCHES);
613         callbackHandler.setIssuer("www.example.com");
614         
615         SAMLParms samlParms = new SAMLParms();
616         samlParms.setCallbackHandler(callbackHandler);
617         AssertionWrapper assertion = new AssertionWrapper(samlParms);
618         
619         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
620         WSSecHeader secHeader = new WSSecHeader();
621         secHeader.insertSecurityHeader(doc);
622         
623         WSSecSignatureSAML wsSign = new WSSecSignatureSAML();
624         wsSign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
625         wsSign.setUseDirectReferenceToAssertion(true);
626         Document signedDoc = 
627             wsSign.build(
628                 doc, null, assertion, crypto, "16c73ab6-b892-458f-abf5-2f875f74882e", 
629                 "security", secHeader
630             );
631 
632         String outputString = 
633             org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
634         if (LOG.isDebugEnabled()) {
635             LOG.debug("Signed SAML2 message Direct Reference (sender vouches):");
636             LOG.debug(outputString);
637         }
638         assertTrue(!outputString.contains(WSConstants.WSS_SAML2_KI_VALUE_TYPE));
639         assertTrue(outputString.contains(WSConstants.WSS_SAML2_TOKEN_TYPE));
640         
641         List<WSSecurityEngineResult> results = verify(signedDoc, crypto, null);
642         WSSecurityEngineResult actionResult =
643             WSSecurityUtil.fetchActionResult(results, WSConstants.ST_UNSIGNED);
644         AssertionWrapper receivedAssertion = 
645             (AssertionWrapper) actionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
646         assertTrue(receivedAssertion != null);
647         
648         // Test we processed a signature (SAML assertion + SOAP body)
649         actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.SIGN);
650         assertTrue(actionResult != null);
651         assertFalse(actionResult.isEmpty());
652         final List<WSDataRef> refs =
653             (List<WSDataRef>) actionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
654         assertTrue(refs.size() == 2);
655         
656         WSDataRef wsDataRef = (WSDataRef)refs.get(0);
657         String xpath = wsDataRef.getXpath();
658         assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Body", xpath);
659         
660         wsDataRef = (WSDataRef)refs.get(1);
661         xpath = wsDataRef.getXpath();
662         assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/saml2:Assertion", xpath);
663     }
664     
665     /**
666      * Test that creates, sends and processes an signed SAML 2 holder-of-key assertion,
667      * where the SecurityTokenReference that points to the SAML Assertion uses a KeyIdentifier,
668      * and not a direct reference. This tests that we can process a KeyIdentifier to a SAML
669      * Assertion in the KeyInfo of a Signature.
670      */
671     @org.junit.Test
672     @SuppressWarnings("unchecked")
673     public void testSAML2HOKKeyIdentifier() throws Exception {
674         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
675         callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
676         callbackHandler.setConfirmationMethod(SAML2Constants.CONF_HOLDER_KEY);
677         callbackHandler.setIssuer("www.example.com");
678         
679         SAMLParms samlParms = new SAMLParms();
680         samlParms.setCallbackHandler(callbackHandler);
681         AssertionWrapper assertion = new AssertionWrapper(samlParms);
682         assertion.signAssertion("wss40_server", "security", issuerCrypto, false);
683 
684         WSSecSignatureSAML wsSign = new WSSecSignatureSAML();
685         wsSign.setUserInfo("wss40", "security");
686         wsSign.setDigestAlgo("http://www.w3.org/2001/04/xmlenc#sha256");
687         wsSign.setSignatureAlgorithm("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
688 
689         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
690         WSSecHeader secHeader = new WSSecHeader();
691         secHeader.insertSecurityHeader(doc);
692 
693         Document signedDoc = 
694             wsSign.build(doc, userCrypto, assertion, null, null, null, secHeader);
695 
696         String outputString = 
697             org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
698         if (LOG.isDebugEnabled()) {
699             LOG.debug("Signed SAML2 message Key Identifier (holder-of-key):");
700             LOG.debug(outputString);
701         }
702         assertTrue(outputString.contains(WSConstants.WSS_SAML2_KI_VALUE_TYPE));
703         assertTrue(outputString.contains(WSConstants.WSS_SAML2_TOKEN_TYPE));
704         
705         List<WSSecurityEngineResult> results = verify(signedDoc, trustCrypto, null);
706         WSSecurityEngineResult actionResult =
707             WSSecurityUtil.fetchActionResult(results, WSConstants.ST_SIGNED);
708         AssertionWrapper receivedAssertion = 
709             (AssertionWrapper) actionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
710         assertTrue(receivedAssertion != null);
711         assertTrue(receivedAssertion.isSigned());
712         
713         // Test we processed a signature (SOAP body)
714         actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.SIGN);
715         assertTrue(actionResult != null);
716         assertFalse(actionResult.isEmpty());
717         final List<WSDataRef> refs =
718             (List<WSDataRef>) actionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
719         assertTrue(refs.size() == 1);
720         
721         WSDataRef wsDataRef = (WSDataRef)refs.get(0);
722         String xpath = wsDataRef.getXpath();
723         assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Body", xpath);
724     }
725     
726     
727     /**
728      * Test that creates, sends and processes an signed SAML 2 holder-of-key assertion,
729      * where the SecurityTokenReference that points to the SAML Assertion uses a direct reference,
730      * and not a KeyIdentifier. Unlike the SAML 1.1 case, this is spec-compliant. This tests that
731      * we can process a Direct Reference to a SAML Assertion in the KeyInfo of a Signature.
732      */
733     @org.junit.Test
734     @SuppressWarnings("unchecked")
735     public void testSAML2HOKDirectReference() throws Exception {
736         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
737         callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
738         callbackHandler.setConfirmationMethod(SAML2Constants.CONF_HOLDER_KEY);
739         callbackHandler.setIssuer("www.example.com");
740         
741         SAMLParms samlParms = new SAMLParms();
742         samlParms.setCallbackHandler(callbackHandler);
743         AssertionWrapper assertion = new AssertionWrapper(samlParms);
744         assertion.signAssertion("wss40_server", "security", issuerCrypto, false);
745 
746         WSSecSignatureSAML wsSign = new WSSecSignatureSAML();
747         wsSign.setUserInfo("wss40", "security");
748         wsSign.setDigestAlgo("http://www.w3.org/2001/04/xmlenc#sha256");
749         wsSign.setSignatureAlgorithm("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
750         wsSign.setUseDirectReferenceToAssertion(true);
751         wsSign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
752 
753         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
754         WSSecHeader secHeader = new WSSecHeader();
755         secHeader.insertSecurityHeader(doc);
756 
757         Document signedDoc = 
758             wsSign.build(doc, userCrypto, assertion, null, null, null, secHeader);
759 
760         String outputString = 
761             org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
762         if (LOG.isDebugEnabled()) {
763             LOG.debug("Signed SAML2 message Direct Reference (holder-of-key):");
764             LOG.debug(outputString);
765         }
766         assertTrue(!outputString.contains(WSConstants.WSS_SAML2_KI_VALUE_TYPE));
767         assertTrue(outputString.contains(WSConstants.WSS_SAML2_TOKEN_TYPE));
768         
769         List<WSSecurityEngineResult> results = verify(signedDoc, trustCrypto, null);
770         WSSecurityEngineResult actionResult =
771             WSSecurityUtil.fetchActionResult(results, WSConstants.ST_SIGNED);
772         AssertionWrapper receivedAssertion = 
773             (AssertionWrapper) actionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
774         assertTrue(receivedAssertion != null);
775         assertTrue(receivedAssertion.isSigned());
776         
777         // Test we processed a signature (SOAP body)
778         actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.SIGN);
779         assertTrue(actionResult != null);
780         assertFalse(actionResult.isEmpty());
781         final List<WSDataRef> refs =
782             (List<WSDataRef>) actionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
783         assertTrue(refs.size() == 1);
784         
785         WSDataRef wsDataRef = (WSDataRef)refs.get(0);
786         String xpath = wsDataRef.getXpath();
787         assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Body", xpath);
788     }
789     
790     /**
791      * The body of the SOAP request is encrypted using a secret key, which is in turn encrypted
792      * using the certificate embedded in the SAML assertion and referenced using a Key Identifier.
793      * This tests that we can process a KeyIdentifier to a SAML Assertion in the KeyInfo of an
794      * EncryptedKey.
795      */
796     @org.junit.Test
797     @SuppressWarnings("unchecked")
798     public void testSAML2HOKEKKeyIdentifier() throws Exception {
799         // Create a SAML assertion
800         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
801         callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
802         callbackHandler.setConfirmationMethod(SAML2Constants.CONF_HOLDER_KEY);
803         callbackHandler.setIssuer("www.example.com");
804         
805         SAMLParms samlParms = new SAMLParms();
806         samlParms.setCallbackHandler(callbackHandler);
807         AssertionWrapper assertion = new AssertionWrapper(samlParms);
808         assertion.signAssertion("wss40_server", "security", issuerCrypto, false);
809 
810         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
811         WSSecHeader secHeader = new WSSecHeader();
812         Node assertionNode = assertion.toDOM(doc);
813         secHeader.insertSecurityHeader(doc);
814         secHeader.getSecurityHeader().appendChild(assertionNode);
815         
816         // Encrypt the SOAP body
817         WSSecEncrypt builder = new WSSecEncrypt();
818         builder.setUserInfo("wss40");
819         builder.setSymmetricEncAlgorithm(WSConstants.TRIPLE_DES);
820         builder.setKeyIdentifierType(WSConstants.CUSTOM_KEY_IDENTIFIER);
821         builder.setCustomEKTokenValueType(WSConstants.WSS_SAML2_KI_VALUE_TYPE);
822         builder.setCustomEKTokenId(assertion.getId());
823         builder.prepare(doc, userCrypto);
824         
825         List<WSEncryptionPart> parts = new ArrayList<WSEncryptionPart>();
826         WSEncryptionPart encP = 
827             new WSEncryptionPart(
828                 "add", "http://ws.apache.org/counter/counter_port_type", "Element"
829             );
830         parts.add(encP);
831         Element refElement = builder.encryptForRef(null, parts);
832         builder.addInternalRefElement(refElement);
833         builder.appendToHeader(secHeader);
834 
835         String outputString = 
836             org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
837         if (LOG.isDebugEnabled()) {
838             LOG.debug("Encrypted SAML 2 message Key Identifier (holder-of-key):");
839             LOG.debug(outputString);
840         }
841         assertTrue(outputString.contains(WSConstants.WSS_SAML2_KI_VALUE_TYPE));
842         assertTrue(outputString.contains(WSConstants.WSS_SAML2_TOKEN_TYPE));
843         
844         List<WSSecurityEngineResult> results = verify(doc, trustCrypto, userCrypto);
845         WSSecurityEngineResult actionResult =
846             WSSecurityUtil.fetchActionResult(results, WSConstants.ST_SIGNED);
847         AssertionWrapper receivedAssertion = 
848             (AssertionWrapper) actionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
849         assertTrue(receivedAssertion != null);
850         assertTrue(receivedAssertion.isSigned());
851         
852         // Test we processed an encrypted element
853         actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.ENCR);
854         assertTrue(actionResult != null);
855         assertFalse(actionResult.isEmpty());
856         final List<WSDataRef> refs =
857             (List<WSDataRef>) actionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
858         assertTrue(refs.size() == 1);
859         
860         WSDataRef wsDataRef = (WSDataRef)refs.get(0);
861         String xpath = wsDataRef.getXpath();
862         assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Body/add", xpath);
863         
864     }
865     
866     /**
867      * The body of the SOAP request is encrypted using a secret key, which is in turn encrypted
868      * using the certificate embedded in the SAML assertion and referenced using Direct
869      * Reference. Unlike the SAML 1.1 case, this is spec-compliant. This tests that we can process
870      * a Direct Reference to a SAML Assertion in the KeyInfo of an EncryptedKey.
871      */
872     @org.junit.Test
873     @SuppressWarnings("unchecked")
874     public void testSAML2HOKEKDirectReference() throws Exception {
875         // Create a SAML assertion
876         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
877         callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
878         callbackHandler.setConfirmationMethod(SAML2Constants.CONF_HOLDER_KEY);
879         callbackHandler.setIssuer("www.example.com");
880         
881         SAMLParms samlParms = new SAMLParms();
882         samlParms.setCallbackHandler(callbackHandler);
883         AssertionWrapper assertion = new AssertionWrapper(samlParms);
884         assertion.signAssertion("wss40_server", "security", issuerCrypto, false);
885 
886         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
887         WSSecHeader secHeader = new WSSecHeader();
888         Node assertionNode = assertion.toDOM(doc);
889         secHeader.insertSecurityHeader(doc);
890         secHeader.getSecurityHeader().appendChild(assertionNode);
891         
892         // Encrypt the SOAP body
893         WSSecEncrypt builder = new WSSecEncrypt();
894         builder.setUserInfo("wss40");
895         builder.setSymmetricEncAlgorithm(WSConstants.TRIPLE_DES);
896         builder.setKeyIdentifierType(WSConstants.CUSTOM_SYMM_SIGNING);
897         builder.setCustomEKTokenValueType(WSConstants.WSS_SAML2_KI_VALUE_TYPE);
898         builder.setCustomEKTokenId(assertion.getId());
899         builder.prepare(doc, userCrypto);
900         
901         List<WSEncryptionPart> parts = new ArrayList<WSEncryptionPart>();
902         WSEncryptionPart encP = 
903             new WSEncryptionPart(
904                 "add", "http://ws.apache.org/counter/counter_port_type", "Element"
905             );
906         parts.add(encP);
907         Element refElement = builder.encryptForRef(null, parts);
908         builder.addInternalRefElement(refElement);
909         builder.appendToHeader(secHeader);
910 
911         String outputString = 
912             org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
913         if (LOG.isDebugEnabled()) {
914             LOG.debug("Encrypted SAML 2 message Direct Reference (holder-of-key):");
915             LOG.debug(outputString);
916         }
917         assertTrue(!outputString.contains(WSConstants.WSS_SAML2_KI_VALUE_TYPE));
918         assertTrue(outputString.contains(WSConstants.WSS_SAML2_TOKEN_TYPE));
919         
920         List<WSSecurityEngineResult> results = verify(doc, trustCrypto, userCrypto);
921         WSSecurityEngineResult actionResult =
922             WSSecurityUtil.fetchActionResult(results, WSConstants.ST_SIGNED);
923         AssertionWrapper receivedAssertion = 
924             (AssertionWrapper) actionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
925         assertTrue(receivedAssertion != null);
926         assertTrue(receivedAssertion.isSigned());
927         
928         // Test we processed an encrypted element
929         actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.ENCR);
930         assertTrue(actionResult != null);
931         assertFalse(actionResult.isEmpty());
932         final List<WSDataRef> refs =
933             (List<WSDataRef>) actionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
934         assertTrue(refs.size() == 1);
935         
936         WSDataRef wsDataRef = (WSDataRef)refs.get(0);
937         String xpath = wsDataRef.getXpath();
938         assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Body/add", xpath);
939         
940     }
941     
942     
943     /**
944      * Verifies the soap envelope
945      * 
946      * @param doc
947      * @throws Exception Thrown when there is a problem in verification
948      */
949     private List<WSSecurityEngineResult> verify(
950         Document doc, Crypto verifyCrypto, Crypto decCrypto
951     ) throws Exception {
952         List<WSSecurityEngineResult> results = 
953             secEngine.processSecurityHeader(doc, null, callbackHandler, verifyCrypto, decCrypto);
954         String outputString = 
955             org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
956         assertTrue(outputString.indexOf("counter_port_type") > 0 ? true : false);
957         return results;
958     }
959     
960 }