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.message;
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.SOAPConstants;
26  import org.apache.wss4j.dom.WSDataRef;
27  import org.apache.wss4j.dom.WSConstants;
28  import org.apache.wss4j.dom.common.CustomHandler;
29  import org.apache.wss4j.dom.common.SAML1CallbackHandler;
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.HandlerAction;
35  import org.apache.wss4j.dom.handler.RequestData;
36  import org.apache.wss4j.dom.handler.WSHandlerConstants;
37  import org.apache.wss4j.dom.handler.WSHandlerResult;
38  import org.apache.wss4j.common.crypto.Crypto;
39  import org.apache.wss4j.common.crypto.CryptoFactory;
40  import org.apache.wss4j.common.crypto.Merlin;
41  import org.apache.wss4j.common.ext.WSSecurityException;
42  import org.apache.wss4j.common.saml.SAMLCallback;
43  import org.apache.wss4j.common.saml.SAMLUtil;
44  import org.apache.wss4j.common.saml.builder.SAML1Constants;
45  import org.apache.wss4j.common.util.Loader;
46  import org.apache.wss4j.common.util.XMLUtils;
47  import org.apache.wss4j.dom.saml.SignedSamlTokenHOKTest;
48  import org.apache.wss4j.dom.saml.WSSecSignatureSAML;
49  import org.apache.wss4j.dom.util.WSSecurityUtil;
50  
51  import org.junit.jupiter.api.Test;
52  import org.w3c.dom.Document;
53  import org.w3c.dom.Element;
54  
55  import java.io.InputStream;
56  import java.security.KeyStore;
57  import java.util.ArrayList;
58  import java.util.List;
59  
60  import javax.xml.namespace.QName;
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  import static org.junit.jupiter.api.Assertions.fail;
67  
68  /**
69   * This is some unit tests for signing using signature parts. Note that the "soapMsg" below
70   * has a custom header added.
71   */
72  public class SignaturePartsTest {
73      private static final org.slf4j.Logger LOG =
74          org.slf4j.LoggerFactory.getLogger(SignaturePartsTest.class);
75      private static final String SOAPMSG = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
76              "<soapenv:Envelope xmlns:foo=\"urn:foo.bar\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" +
77              "   <soapenv:Header>" +
78              "       <foo:foobar>baz</foo:foobar>" +
79              "   </soapenv:Header>" +
80              "   <soapenv:Body>" +
81              "      <ns1:testMethod xmlns:ns1=\"http://axis/service/security/test6/LogTestService8\"></ns1:testMethod>" +
82              "   </soapenv:Body>" +
83              "</soapenv:Envelope>";
84      private static final String SOAPMSG_MULTIPLE = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
85          "<soapenv:Envelope xmlns:foo=\"urn:foo.bar\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" +
86          "   <soapenv:Header>" +
87          "       <foo:foobar>baz</foo:foobar>" +
88          "   </soapenv:Header>" +
89          "   <soapenv:Body>" +
90          "      <ns1:testMethod xmlns:ns1=\"http://axis/service/security/test6/LogTestService8\">asf1</ns1:testMethod>" +
91          "      <ns1:testMethod xmlns:ns1=\"http://axis/service/security/test6/LogTestService8\">asf2</ns1:testMethod>" +
92          "   </soapenv:Body>" +
93          "</soapenv:Envelope>";
94  
95      private WSSecurityEngine secEngine = new WSSecurityEngine();
96      private Crypto crypto;
97  
98      public SignaturePartsTest() throws Exception {
99          WSSConfig.init();
100         crypto = CryptoFactory.getInstance();
101     }
102 
103     /**
104      * Test signing a custom SOAP header
105      */
106     @SuppressWarnings("unchecked")
107     @Test
108     public void testSOAPHeader() throws Exception {
109         Document doc = SOAPUtil.toSOAPPart(SOAPMSG);
110         WSSecHeader secHeader = new WSSecHeader(doc);
111         secHeader.insertSecurityHeader();
112 
113         WSSecSignature sign = new WSSecSignature(secHeader);
114         sign.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
115         sign.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
116 
117         WSEncryptionPart encP =
118             new WSEncryptionPart(
119                 "foobar",
120                 "urn:foo.bar",
121                 "");
122         sign.getParts().add(encP);
123 
124         Document signedDoc = sign.build(crypto);
125 
126         if (LOG.isDebugEnabled()) {
127             String outputString =
128                 XMLUtils.prettyDocumentToString(signedDoc);
129             LOG.debug(outputString);
130         }
131 
132         WSHandlerResult results = verify(signedDoc);
133 
134         WSSecurityEngineResult actionResult =
135             results.getActionResults().get(WSConstants.SIGN).get(0);
136         assertNotNull(actionResult);
137         assertFalse(actionResult.isEmpty());
138         final List<WSDataRef> refs =
139             (List<WSDataRef>) actionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
140 
141         WSDataRef wsDataRef = refs.get(0);
142         String xpath = wsDataRef.getXpath();
143         assertEquals("/soapenv:Envelope/soapenv:Header/foo:foobar", xpath);
144         assertEquals(WSConstants.RSA_SHA1, wsDataRef.getAlgorithm());
145         assertNotNull(wsDataRef.getDigestValue());
146         assertTrue(wsDataRef.getDigestValue().length > 0);
147         QName expectedQName = new QName("urn:foo.bar", "foobar");
148         assertEquals(expectedQName, wsDataRef.getName());
149 
150         assertEquals(WSConstants.SHA1, wsDataRef.getDigestAlgorithm());
151 
152         String sigMethod = (String)actionResult.get(WSSecurityEngineResult.TAG_SIGNATURE_METHOD);
153         assertEquals(WSConstants.RSA_SHA1, sigMethod);
154 
155         String c14nMethod =
156             (String)actionResult.get(WSSecurityEngineResult.TAG_CANONICALIZATION_METHOD);
157         assertEquals(WSConstants.C14N_EXCL_OMIT_COMMENTS, c14nMethod);
158 
159         List<String> transformAlgorithms = wsDataRef.getTransformAlgorithms();
160         assertTrue(transformAlgorithms.size() == 1);
161         assertTrue(WSConstants.C14N_EXCL_OMIT_COMMENTS.equals(transformAlgorithms.get(0)));
162     }
163 
164     @Test
165     public void testOptionalSOAPHeaderPresent() throws Exception {
166         Document doc = SOAPUtil.toSOAPPart(SOAPMSG);
167         WSSecHeader secHeader = new WSSecHeader(doc);
168         secHeader.insertSecurityHeader();
169 
170         WSSecSignature sign = new WSSecSignature(secHeader);
171         sign.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
172         sign.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
173 
174         WSEncryptionPart encP =
175             new WSEncryptionPart(
176                 "foobar",
177                 "urn:foo.bar",
178                 "");
179         encP.setRequired(false);
180         sign.getParts().add(encP);
181         String soapNamespace = WSSecurityUtil.getSOAPNamespace(doc.getDocumentElement());
182         encP =
183             new WSEncryptionPart(
184                 WSConstants.ELEM_BODY,
185                 soapNamespace,
186                 "Content"
187             );
188         sign.getParts().add(encP);
189 
190         Document signedDoc = sign.build(crypto);
191 
192         if (LOG.isDebugEnabled()) {
193             String outputString =
194                 XMLUtils.prettyDocumentToString(signedDoc);
195             LOG.debug(outputString);
196         }
197 
198         verify(signedDoc);
199     }
200 
201     @Test
202     public void testOptionalSOAPHeaderNotPresent() throws Exception {
203         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
204         WSSecHeader secHeader = new WSSecHeader(doc);
205         secHeader.insertSecurityHeader();
206 
207         WSSecSignature sign = new WSSecSignature(secHeader);
208         sign.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
209         sign.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
210 
211         WSEncryptionPart encP =
212             new WSEncryptionPart(
213                 "foobar",
214                 "urn:foo.bar",
215                 "");
216         encP.setRequired(false);
217         sign.getParts().add(encP);
218         String soapNamespace = WSSecurityUtil.getSOAPNamespace(doc.getDocumentElement());
219         encP =
220             new WSEncryptionPart(
221                 WSConstants.ELEM_BODY,
222                 soapNamespace,
223                 "Content"
224             );
225         sign.getParts().add(encP);
226 
227         Document signedDoc = sign.build(crypto);
228 
229         if (LOG.isDebugEnabled()) {
230             String outputString =
231                 XMLUtils.prettyDocumentToString(signedDoc);
232             LOG.debug(outputString);
233         }
234 
235         verify(signedDoc);
236     }
237 
238     @Test
239     public void testRequiredSOAPHeaderNotPresent() throws Exception {
240         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
241         WSSecHeader secHeader = new WSSecHeader(doc);
242         secHeader.insertSecurityHeader();
243 
244         WSSecSignature sign = new WSSecSignature(secHeader);
245         sign.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
246         sign.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
247 
248         WSEncryptionPart encP =
249             new WSEncryptionPart(
250                 "foobar",
251                 "urn:foo.bar",
252                 "");
253         sign.getParts().add(encP);
254         String soapNamespace = WSSecurityUtil.getSOAPNamespace(doc.getDocumentElement());
255         encP =
256             new WSEncryptionPart(
257                 WSConstants.ELEM_BODY,
258                 soapNamespace,
259                 "Content"
260             );
261         sign.getParts().add(encP);
262 
263         try {
264             sign.build(crypto);
265             fail("Failure expected on not signing a required element");
266         } catch (WSSecurityException ex) {
267             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILED_SIGNATURE);
268         }
269     }
270 
271     /**
272      * Test signing of a header through a STR Dereference Transform
273      */
274     @SuppressWarnings("unchecked")
275     @Test
276     public void testSOAPHeaderSTRTransform() throws Exception {
277         // Construct issuer and user crypto instances
278         Crypto issuerCrypto = new Merlin();
279         KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
280         ClassLoader loader = Loader.getClassLoader(SignedSamlTokenHOKTest.class);
281         InputStream input = Merlin.loadInputStream(loader, "keys/wss40_server.jks");
282         keyStore.load(input, "security".toCharArray());
283         input.close();
284         ((Merlin)issuerCrypto).setKeyStore(keyStore);
285 
286         Crypto userCrypto = CryptoFactory.getInstance("wss40.properties");
287 
288         SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
289         callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
290         callbackHandler.setConfirmationMethod(SAML1Constants.CONF_HOLDER_KEY);
291 
292         SAMLCallback samlCallback = new SAMLCallback();
293         SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
294 
295         samlCallback.setIssuer("www.example.com");
296 
297         SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
298         samlAssertion.signAssertion("wss40_server", "security", issuerCrypto, false);
299 
300         Document doc = SOAPUtil.toSOAPPart(SOAPMSG);
301         WSSecHeader secHeader = new WSSecHeader(doc);
302         secHeader.insertSecurityHeader();
303 
304         WSSecSignatureSAML wsSign = new WSSecSignatureSAML(secHeader);
305         wsSign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
306         wsSign.setUserInfo("wss40", "security");
307 
308         WSEncryptionPart encP =
309             new WSEncryptionPart("STRTransform", "", "Element");
310         wsSign.getParts().add(encP);
311 
312         //
313         // set up for keyHolder
314         //
315         Document signedDoc = wsSign.build(userCrypto, samlAssertion, null, null, null);
316 
317         if (LOG.isDebugEnabled()) {
318             LOG.debug("Signed SAML message (key holder):");
319             String outputString =
320                 XMLUtils.prettyDocumentToString(signedDoc);
321             LOG.debug(outputString);
322         }
323 
324         // Construct trust crypto instance
325         Crypto trustCrypto = new Merlin();
326         KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
327         input = Merlin.loadInputStream(loader, "keys/wss40CA.jks");
328         trustStore.load(input, "security".toCharArray());
329         input.close();
330         ((Merlin)trustCrypto).setTrustStore(trustStore);
331 
332         WSHandlerResult results =
333             secEngine.processSecurityHeader(doc, null, null, trustCrypto);
334         WSSecurityEngineResult stUnsignedActionResult =
335             results.getActionResults().get(WSConstants.ST_SIGNED).get(0);
336         SamlAssertionWrapper receivedSamlAssertion =
337             (SamlAssertionWrapper) stUnsignedActionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
338         assertNotNull(receivedSamlAssertion);
339         assertTrue(receivedSamlAssertion.isSigned());
340 
341         WSSecurityEngineResult signActionResult =
342             results.getActionResults().get(WSConstants.SIGN).get(0);
343         assertNotNull(signActionResult);
344         assertFalse(signActionResult.isEmpty());
345         final List<WSDataRef> refs =
346             (List<WSDataRef>) signActionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
347 
348         WSDataRef wsDataRef = refs.get(0);
349         String xpath = wsDataRef.getXpath();
350         assertEquals("/soapenv:Envelope/soapenv:Header/wsse:Security/saml1:Assertion", xpath);
351     }
352 
353     /**
354      * Test signing a custom SOAP header with a bad localname
355      */
356     @Test
357     public void testBadLocalname() throws Exception {
358         Document doc = SOAPUtil.toSOAPPart(SOAPMSG);
359         WSSecHeader secHeader = new WSSecHeader(doc);
360         secHeader.insertSecurityHeader();
361 
362         WSSecSignature sign = new WSSecSignature(secHeader);
363         sign.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
364         sign.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
365 
366         WSEncryptionPart encP =
367             new WSEncryptionPart(
368                 "foobar2",
369                 "urn:foo.bar",
370                 "");
371         sign.getParts().add(encP);
372 
373         try {
374             sign.build(crypto);
375             fail("Failure expected on a bad localname");
376         } catch (WSSecurityException ex) {
377             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILED_SIGNATURE);
378         }
379     }
380 
381     /**
382      * Test signing a custom SOAP header with a bad namespace
383      */
384     @Test
385     public void testBadNamespace() throws Exception {
386         Document doc = SOAPUtil.toSOAPPart(SOAPMSG);
387         WSSecHeader secHeader = new WSSecHeader(doc);
388         secHeader.insertSecurityHeader();
389 
390         WSSecSignature sign = new WSSecSignature(secHeader);
391         sign.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
392         sign.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
393 
394         WSEncryptionPart encP =
395             new WSEncryptionPart(
396                 "foobar",
397                 "urn:foo.bar2",
398                 "");
399         sign.getParts().add(encP);
400 
401         try {
402             sign.build(crypto);
403             fail("Failure expected on a bad namespace");
404         } catch (WSSecurityException ex) {
405             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILED_SIGNATURE);
406         }
407     }
408 
409     /**
410      * Test signing a custom SOAP header and the SOAP body
411      */
412     @Test
413     public void testSOAPHeaderAndBody() throws Exception {
414         Document doc = SOAPUtil.toSOAPPart(SOAPMSG);
415         WSSecHeader secHeader = new WSSecHeader(doc);
416         secHeader.insertSecurityHeader();
417 
418         WSSecSignature sign = new WSSecSignature(secHeader);
419         sign.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
420         sign.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
421 
422         SOAPConstants soapConstants =
423             WSSecurityUtil.getSOAPConstants(doc.getDocumentElement());
424 
425         WSEncryptionPart encP =
426             new WSEncryptionPart(
427                 soapConstants.getBodyQName().getLocalPart(),    // define the body
428                 soapConstants.getEnvelopeURI(),
429                 "");
430         sign.getParts().add(encP);
431         WSEncryptionPart encP2 =
432             new WSEncryptionPart(
433                 "foobar",
434                 "urn:foo.bar",
435                 "");
436         sign.getParts().add(encP2);
437 
438         Document signedDoc = sign.build(crypto);
439 
440         if (LOG.isDebugEnabled()) {
441             String outputString =
442                 XMLUtils.prettyDocumentToString(signedDoc);
443             LOG.debug(outputString);
444         }
445 
446         WSHandlerResult results = verify(signedDoc);
447 
448         QName fooName = new QName("urn:foo.bar", "foobar");
449         QName bodyName = new QName(soapConstants.getEnvelopeURI(), "Body");
450         QName headerName = new QName(soapConstants.getEnvelopeURI(), "Header");
451 
452         WSSecurityEngineResult actionResult =
453             results.getActionResults().get(WSConstants.SIGN).get(0);
454         assertNotNull(actionResult);
455         assertFalse(actionResult.isEmpty());
456 
457         @SuppressWarnings("unchecked")
458         final List<WSDataRef> refs =
459             (List<WSDataRef>) actionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
460         assertTrue(refs != null && !refs.isEmpty());
461 
462         boolean foundFoo = false;
463         boolean foundBody = false;
464         boolean foundHeader = false;
465         for (WSDataRef ref : refs) {
466             if (fooName.equals(ref.getName())) {
467                 foundFoo = true;
468             } else if (bodyName.equals(ref.getName())) {
469                 foundBody = true;
470             } else if (headerName.equals(ref.getName())) {
471                 foundHeader = true;
472             }
473         }
474         assertTrue(foundFoo && foundBody);
475         assertFalse(foundHeader);
476     }
477 
478 
479     /**
480      * Test getting a DOM Element from WSEncryptionPart directly
481      */
482     @Test
483     public void testSignaturePartDOMElement() throws Exception {
484         Document doc = SOAPUtil.toSOAPPart(SOAPMSG);
485         WSSecHeader secHeader = new WSSecHeader(doc);
486         secHeader.insertSecurityHeader();
487 
488         WSSecSignature sign = new WSSecSignature(secHeader);
489         sign.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
490         sign.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
491 
492         SOAPConstants soapConstants =
493             WSSecurityUtil.getSOAPConstants(doc.getDocumentElement());
494 
495         // Give wrong names to make sure it's picking up the element
496         WSEncryptionPart encP =
497             new WSEncryptionPart(
498                 "Incorrect Localname",
499                 "Incorrect N/S",
500                 "");
501         Element bodyElement = WSSecurityUtil.findBodyElement(doc);
502         assertTrue(bodyElement != null && "Body".equals(bodyElement.getLocalName()));
503         encP.setElement(bodyElement);
504         sign.getParts().add(encP);
505 
506         Document signedDoc = sign.build(crypto);
507 
508         if (LOG.isDebugEnabled()) {
509             String outputString =
510                 XMLUtils.prettyDocumentToString(signedDoc);
511             LOG.debug(outputString);
512         }
513 
514         WSHandlerResult results = verify(signedDoc);
515 
516         WSSecurityEngineResult actionResult =
517             results.getActionResults().get(WSConstants.SIGN).get(0);
518         assertNotNull(actionResult);
519         assertFalse(actionResult.isEmpty());
520         @SuppressWarnings("unchecked")
521         final List<WSDataRef> refs =
522             (List<WSDataRef>) actionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
523 
524         WSDataRef wsDataRef = refs.get(0);
525         QName bodyName = new QName(soapConstants.getEnvelopeURI(), "Body");
526         assertEquals(bodyName, wsDataRef.getName());
527     }
528 
529     /**
530      * Test signing two SOAP Body elements with the same QName.
531      */
532     @Test
533     public void testMultipleElements() throws Exception {
534         Document doc = SOAPUtil.toSOAPPart(SOAPMSG_MULTIPLE);
535         WSSecHeader secHeader = new WSSecHeader(doc);
536         secHeader.insertSecurityHeader();
537 
538         WSSecSignature sign = new WSSecSignature(secHeader);
539         sign.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
540         sign.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
541 
542         WSEncryptionPart encP =
543             new WSEncryptionPart(
544                 "testMethod",
545                 "http://axis/service/security/test6/LogTestService8",
546                 "");
547         sign.getParts().add(encP);
548 
549         Document signedDoc = sign.build(crypto);
550 
551         String outputString =
552             XMLUtils.prettyDocumentToString(signedDoc);
553         if (LOG.isDebugEnabled()) {
554             LOG.debug(outputString);
555         }
556 
557         verify(signedDoc);
558     }
559 
560     @Test
561     public void testSignedKeyInfo() throws Exception {
562         Document doc = SOAPUtil.toSOAPPart(SOAPMSG);
563         WSSecHeader secHeader = new WSSecHeader(doc);
564         secHeader.insertSecurityHeader();
565 
566         WSSecSignature sign = new WSSecSignature(secHeader);
567         sign.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
568         sign.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
569 
570         WSEncryptionPart encP =
571             new WSEncryptionPart(
572                 "KeyInfo",
573                 WSConstants.SIG_NS,
574                 "");
575         sign.getParts().add(encP);
576 
577         Document signedDoc = sign.build(crypto);
578 
579         if (LOG.isDebugEnabled()) {
580             String outputString =
581                 XMLUtils.prettyDocumentToString(signedDoc);
582             LOG.debug(outputString);
583         }
584 
585         WSHandlerResult results = verify(signedDoc);
586 
587         verifySignedKeyInfoResults(results);
588     }
589 
590     @Test
591     public void testSignedKeyInfoAction() throws Exception {
592         final WSSConfig cfg = WSSConfig.getNewInstance();
593         final RequestData reqData = new RequestData();
594         reqData.setWssConfig(cfg);
595         reqData.setUsername("16c73ab6-b892-458f-abf5-2f875f74882e");
596 
597         java.util.Map<String, Object> config = new java.util.TreeMap<>();
598         config.put(WSHandlerConstants.SIG_PROP_FILE, "crypto.properties");
599         config.put("password", "security");
600         config.put(
601             WSHandlerConstants.SIGNATURE_PARTS, "{}{" + WSConstants.SIG_NS + "}KeyInfo"
602         );
603         reqData.setMsgContext(config);
604 
605         final Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
606         CustomHandler handler = new CustomHandler();
607         List<HandlerAction> actions = new ArrayList<>();
608         actions.add(new HandlerAction(WSConstants.SIGN));
609         handler.send(
610             doc,
611             reqData,
612             actions,
613             true
614         );
615         String outputString =
616             XMLUtils.prettyDocumentToString(doc);
617         if (LOG.isDebugEnabled()) {
618             LOG.debug("Signed message:");
619             LOG.debug(outputString);
620         }
621 
622         WSHandlerResult results = verify(doc);
623 
624         List<Integer> receivedActions = new ArrayList<>();
625         receivedActions.add(WSConstants.SIGN);
626         assertTrue(handler.checkResults(results.getResults(), receivedActions));
627 
628         verifySignedKeyInfoResults(results);
629     }
630 
631     private void verifySignedKeyInfoResults(WSHandlerResult results) {
632 
633         WSSecurityEngineResult actionResult =
634                 results.getActionResults().get(WSConstants.SIGN).get(0);
635         assertNotNull(actionResult);
636         assertFalse(actionResult.isEmpty());
637         final List<WSDataRef> refs =
638                 (List<WSDataRef>) actionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
639 
640         WSDataRef wsDataRef = refs.get(0);
641         String xpath = wsDataRef.getXpath();
642         assertTrue(xpath.matches("/(soapenv|SOAP-ENV):Envelope/(soapenv|SOAP-ENV):Header/wsse:Security/ds:Signature/ds:KeyInfo"));
643         assertEquals(WSConstants.RSA_SHA1, wsDataRef.getAlgorithm());
644         assertNotNull(wsDataRef.getDigestValue());
645         assertTrue(wsDataRef.getDigestValue().length > 0);
646         QName expectedQName = new QName(WSConstants.SIG_NS, "KeyInfo");
647         assertEquals(expectedQName, wsDataRef.getName());
648 
649         assertEquals(WSConstants.SHA1, wsDataRef.getDigestAlgorithm());
650 
651         String sigMethod = (String)actionResult.get(WSSecurityEngineResult.TAG_SIGNATURE_METHOD);
652         assertEquals(WSConstants.RSA_SHA1, sigMethod);
653 
654         String c14nMethod =
655                 (String)actionResult.get(WSSecurityEngineResult.TAG_CANONICALIZATION_METHOD);
656         assertEquals(WSConstants.C14N_EXCL_OMIT_COMMENTS, c14nMethod);
657 
658         List<String> transformAlgorithms = wsDataRef.getTransformAlgorithms();
659         assertTrue(transformAlgorithms.size() == 1);
660         assertTrue(WSConstants.C14N_EXCL_OMIT_COMMENTS.equals(transformAlgorithms.get(0)));
661     }
662 
663     /**
664      * Verifies the soap envelope
665      * <p/>
666      *
667      * @param doc
668      * @throws Exception Thrown when there is a problem in verification
669      */
670     private WSHandlerResult verify(Document doc) throws Exception {
671         WSHandlerResult results =
672             secEngine.processSecurityHeader(doc, null, null, crypto);
673         if (LOG.isDebugEnabled()) {
674             LOG.debug("Verfied and decrypted message:");
675             String outputString =
676                 XMLUtils.prettyDocumentToString(doc);
677             LOG.debug(outputString);
678         }
679         return results;
680     }
681 
682 }