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