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 java.io.File;
23  import java.security.cert.X509Certificate;
24  import java.util.ArrayList;
25  import java.util.Collections;
26  import java.util.List;
27  
28  import javax.security.auth.callback.CallbackHandler;
29  import javax.xml.crypto.dom.DOMCryptoContext;
30  import javax.xml.crypto.dom.DOMStructure;
31  import javax.xml.crypto.dsig.XMLSignatureFactory;
32  import javax.xml.crypto.dsig.keyinfo.KeyInfo;
33  import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
34  import javax.xml.crypto.dsig.keyinfo.X509Data;
35  import javax.xml.parsers.DocumentBuilder;
36  import javax.xml.parsers.DocumentBuilderFactory;
37  
38  import org.apache.wss4j.common.WSEncryptionPart;
39  import org.apache.wss4j.common.bsp.BSPRule;
40  import org.apache.wss4j.common.crypto.Crypto;
41  import org.apache.wss4j.common.crypto.CryptoFactory;
42  import org.apache.wss4j.common.crypto.CryptoType;
43  import org.apache.wss4j.common.ext.WSSecurityException;
44  import org.apache.wss4j.common.token.Reference;
45  import org.apache.wss4j.common.token.SecurityTokenReference;
46  import org.apache.wss4j.common.util.SOAPUtil;
47  import org.apache.wss4j.common.util.XMLUtils;
48  import org.apache.wss4j.dom.WSConstants;
49  import org.apache.wss4j.dom.common.CustomHandler;
50  import org.apache.wss4j.dom.common.KeystoreCallbackHandler;
51  
52  import org.apache.wss4j.dom.engine.WSSConfig;
53  import org.apache.wss4j.dom.engine.WSSecurityEngine;
54  import org.apache.wss4j.dom.engine.WSSecurityEngineResult;
55  import org.apache.wss4j.dom.handler.HandlerAction;
56  import org.apache.wss4j.dom.handler.RequestData;
57  import org.apache.wss4j.dom.handler.WSHandlerConstants;
58  import org.apache.wss4j.dom.handler.WSHandlerResult;
59  import org.apache.wss4j.dom.str.STRParser.REFERENCE_TYPE;
60  import org.apache.wss4j.dom.util.WSSecurityUtil;
61  
62  import org.junit.jupiter.api.Test;
63  import org.w3c.dom.Document;
64  import org.w3c.dom.Element;
65  import org.w3c.dom.Node;
66  
67  import static org.junit.jupiter.api.Assertions.assertNotNull;
68  import static org.junit.jupiter.api.Assertions.assertTrue;
69  import static org.junit.jupiter.api.Assertions.fail;
70  
71  
72  /**
73   * A set of test-cases for signing and verifying SOAP requests.
74   */
75  public class SignatureTest {
76      private static final org.slf4j.Logger LOG =
77          org.slf4j.LoggerFactory.getLogger(SignatureTest.class);
78  
79      private WSSecurityEngine secEngine = new WSSecurityEngine();
80      private CallbackHandler callbackHandler = new KeystoreCallbackHandler();
81      private Crypto crypto;
82  
83      public SignatureTest() throws Exception {
84          WSSConfig.init();
85          crypto = CryptoFactory.getInstance();
86      }
87  
88      /**
89       * The test uses the Issuer Serial key identifier type.
90       * <p/>
91       *
92       * @throws Exception Thrown when there is any problem in signing or verification
93       */
94      @Test
95      public void testX509SignatureIS() throws Exception {
96          Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
97          WSSecHeader secHeader = new WSSecHeader(doc);
98          secHeader.insertSecurityHeader();
99  
100         WSSecSignature builder = new WSSecSignature(secHeader);
101         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
102         builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
103         LOG.info("Before Signing IS....");
104 
105         Document signedDoc = builder.build(crypto);
106 
107         if (LOG.isDebugEnabled()) {
108             LOG.debug("Signed message with IssuerSerial key identifier:");
109             String outputString =
110                 XMLUtils.prettyDocumentToString(signedDoc);
111             LOG.debug(outputString);
112         }
113         LOG.info("After Signing IS....");
114         WSHandlerResult results = verify(signedDoc);
115 
116         WSSecurityEngineResult actionResult =
117             results.getActionResults().get(WSConstants.SIGN).get(0);
118         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE));
119         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE));
120         REFERENCE_TYPE referenceType =
121             (REFERENCE_TYPE)actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE);
122         assertTrue(referenceType == REFERENCE_TYPE.ISSUER_SERIAL);
123     }
124 
125     @Test
126     public void testX509SignatureISAttached() throws Exception {
127         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
128         WSSecHeader secHeader = new WSSecHeader(doc);
129         secHeader.insertSecurityHeader();
130 
131         WSSecSignature builder = new WSSecSignature(secHeader);
132         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
133         builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
134         builder.setIncludeSignatureToken(true);
135         LOG.info("Before Signing IS....");
136 
137         Document signedDoc = builder.build(crypto);
138 
139         if (LOG.isDebugEnabled()) {
140             LOG.debug("Signed message with IssuerSerial key identifier:");
141             String outputString =
142                 XMLUtils.prettyDocumentToString(signedDoc);
143             LOG.debug(outputString);
144         }
145         LOG.info("After Signing IS....");
146         WSHandlerResult results = verify(signedDoc);
147 
148         WSSecurityEngineResult actionResult =
149             results.getActionResults().get(WSConstants.SIGN).get(0);
150         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE));
151         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE));
152         REFERENCE_TYPE referenceType =
153             (REFERENCE_TYPE)actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE);
154         assertTrue(referenceType == REFERENCE_TYPE.ISSUER_SERIAL);
155     }
156 
157 
158     /**
159      * Test that signs (twice) and verifies a WS-Security envelope.
160      * <p/>
161      *
162      * @throws Exception Thrown when there is any problem in signing or verification
163      */
164     @Test
165     public void testDoubleX509SignatureIS() throws Exception {
166         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
167         WSSecHeader secHeader = new WSSecHeader(doc);
168         secHeader.insertSecurityHeader();
169 
170         WSSecSignature builder = new WSSecSignature(secHeader);
171         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
172 
173         builder.build(crypto);
174         Document signedDoc1 = builder.build(crypto);
175         verify(signedDoc1);
176     }
177 
178     /**
179      * Test that signs and verifies a WS-Security envelope
180      * <p/>
181      *
182      * @throws Exception Thrown when there is any problem in signing or verification
183      */
184     @Test
185     public void testIssuerSerialSignature() throws Exception {
186         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
187         WSSecHeader secHeader = new WSSecHeader(doc);
188         secHeader.insertSecurityHeader();
189 
190         WSSecSignature builder = new WSSecSignature(secHeader);
191         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
192         LOG.info("Before Signing....");
193         Document signedDoc = builder.build(crypto);
194 
195         if (LOG.isDebugEnabled()) {
196             LOG.debug("After Signing....");
197             String outputString =
198                 XMLUtils.prettyDocumentToString(signedDoc);
199             LOG.debug(outputString);
200         }
201 
202         verify(signedDoc);
203     }
204 
205     /**
206      * Test that signs and verifies a WS-Security envelope
207      * <p/>
208      *
209      * @throws Exception Thrown when there is any problem in signing or verification
210      */
211     @Test
212     public void testSignatureInclusiveC14N() throws Exception {
213         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
214         WSSecHeader secHeader = new WSSecHeader(doc);
215         secHeader.insertSecurityHeader();
216 
217         WSSecSignature builder = new WSSecSignature(secHeader);
218         builder.setSigCanonicalization(WSConstants.C14N_OMIT_COMMENTS);
219         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
220         LOG.info("Before Signing....");
221         Document signedDoc = builder.build(crypto);
222 
223         if (LOG.isDebugEnabled()) {
224             LOG.debug("After Signing....");
225             String outputString =
226                 XMLUtils.prettyDocumentToString(signedDoc);
227             LOG.debug(outputString);
228         }
229 
230         WSSecurityEngine newEngine = new WSSecurityEngine();
231         try {
232             newEngine.processSecurityHeader(doc, null, null, crypto);
233             fail("Failure expected on a bad c14n algorithm");
234         } catch (WSSecurityException ex) {
235             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
236         }
237 
238         RequestData data = new RequestData();
239         data.setSigVerCrypto(crypto);
240         List<BSPRule> ignoredRules = new ArrayList<>();
241         ignoredRules.add(BSPRule.R5404);
242         ignoredRules.add(BSPRule.R5406);
243         data.setIgnoredBSPRules(ignoredRules);
244         newEngine.processSecurityHeader(doc, data);
245     }
246 
247     /**
248      * Test that signs and verifies a WS-Security envelope
249      * <p/>
250      *
251      * @throws Exception Thrown when there is any problem in signing or verification
252      */
253     @Test
254     public void testSignatureInclusivePrefixes() throws Exception {
255         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
256         WSSecHeader secHeader = new WSSecHeader(doc);
257         secHeader.insertSecurityHeader();
258 
259         WSSecSignature builder = new WSSecSignature(secHeader);
260         builder.setAddInclusivePrefixes(true);
261         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
262         LOG.info("Before Signing....");
263         Document signedDoc = builder.build(crypto);
264 
265         if (LOG.isDebugEnabled()) {
266             LOG.debug("After Signing....");
267             String outputString =
268                 XMLUtils.prettyDocumentToString(signedDoc);
269             LOG.debug(outputString);
270         }
271 
272         verify(signedDoc);
273     }
274 
275     /**
276      * Test that signs and verifies a WS-Security envelope
277      * <p/>
278      *
279      * @throws Exception Thrown when there is any problem in signing or verification
280      */
281     @Test
282     public void testBSTSignature() throws Exception {
283         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
284         WSSecHeader secHeader = new WSSecHeader(doc);
285         secHeader.insertSecurityHeader();
286 
287         WSSecSignature builder = new WSSecSignature(secHeader);
288         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
289         builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
290         LOG.info("Before Signing....");
291         Document signedDoc = builder.build(crypto);
292 
293         if (LOG.isDebugEnabled()) {
294             LOG.debug("After Signing....");
295             String outputString =
296                 XMLUtils.prettyDocumentToString(signedDoc);
297             LOG.debug(outputString);
298         }
299 
300         WSHandlerResult results = verify(signedDoc);
301 
302         WSSecurityEngineResult actionResult =
303             results.getActionResults().get(WSConstants.SIGN).get(0);
304         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE));
305         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE));
306         REFERENCE_TYPE referenceType =
307             (REFERENCE_TYPE)actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE);
308         assertTrue(referenceType == REFERENCE_TYPE.DIRECT_REF);
309     }
310 
311     /**
312      * Test that signs and verifies a WS-Security envelope
313      * <p/>
314      *
315      * @throws Exception Thrown when there is any problem in signing or verification
316      */
317     @Test
318     public void testBSTPKIPathSignature() throws Exception {
319         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
320         WSSecHeader secHeader = new WSSecHeader(doc);
321         secHeader.insertSecurityHeader();
322 
323         WSSecSignature builder = new WSSecSignature(secHeader);
324         builder.setUserInfo("wss40", "security");
325         builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
326         builder.setUseSingleCertificate(false);
327         LOG.info("Before Signing....");
328 
329         Crypto pkiCrypto = CryptoFactory.getInstance("wss40.properties");
330         Document signedDoc = builder.build(pkiCrypto);
331 
332         if (LOG.isDebugEnabled()) {
333             LOG.debug("After PKI Signing....");
334             String outputString =
335                 XMLUtils.prettyDocumentToString(signedDoc);
336             LOG.debug(outputString);
337         }
338 
339         secEngine.processSecurityHeader(doc, null, callbackHandler, pkiCrypto, null);
340     }
341 
342     /**
343      * Test that signs and verifies a WS-Security envelope
344      * <p/>
345      *
346      * @throws Exception Thrown when there is any problem in signing or verification
347      */
348     @Test
349     public void testX509Signature() throws Exception {
350         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
351         WSSecHeader secHeader = new WSSecHeader(doc);
352         secHeader.insertSecurityHeader();
353 
354         WSSecSignature builder = new WSSecSignature(secHeader);
355         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
356         builder.setKeyIdentifierType(WSConstants.X509_KEY_IDENTIFIER);
357         LOG.info("Before Signing....");
358 
359         Document signedDoc = builder.build(crypto);
360 
361         if (LOG.isDebugEnabled()) {
362             LOG.debug("After Signing....");
363             String outputString =
364                 XMLUtils.prettyDocumentToString(signedDoc);
365             LOG.debug(outputString);
366         }
367 
368         WSSecurityEngine newEngine = new WSSecurityEngine();
369         WSHandlerResult results =
370             newEngine.processSecurityHeader(doc, null, null, crypto);
371 
372         WSSecurityEngineResult actionResult =
373             results.getActionResults().get(WSConstants.SIGN).get(0);
374         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE));
375         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE));
376         REFERENCE_TYPE referenceType =
377             (REFERENCE_TYPE)actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE);
378         assertTrue(referenceType == REFERENCE_TYPE.KEY_IDENTIFIER);
379     }
380 
381     /**
382      * Test that signs and verifies a WS-Security envelope.
383      * The test uses the ThumbprintSHA1 key identifier type.
384      * <p/>
385      *
386      * @throws Exception Thrown when there is any problem in signing or verification
387      */
388     @Test
389     public void testX509SignatureThumb() throws Exception {
390         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
391         WSSecHeader secHeader = new WSSecHeader(doc);
392         secHeader.insertSecurityHeader();
393 
394         WSSecSignature builder = new WSSecSignature(secHeader);
395         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
396         builder.setKeyIdentifierType(WSConstants.THUMBPRINT_IDENTIFIER);
397         LOG.info("Before Signing ThumbprintSHA1....");
398 
399         Document signedDoc = builder.build(crypto);
400 
401         if (LOG.isDebugEnabled()) {
402             LOG.debug("Signed message with ThumbprintSHA1 key identifier:");
403             String outputString =
404                 XMLUtils.prettyDocumentToString(signedDoc);
405             LOG.debug(outputString);
406         }
407         LOG.info("After Signing ThumbprintSHA1....");
408 
409         WSHandlerResult results = verify(signedDoc);
410 
411         WSSecurityEngineResult actionResult =
412             results.getActionResults().get(WSConstants.SIGN).get(0);
413         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE));
414         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE));
415         REFERENCE_TYPE referenceType =
416             (REFERENCE_TYPE)actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE);
417         assertTrue(referenceType == REFERENCE_TYPE.THUMBPRINT_SHA1);
418     }
419 
420     @Test
421     public void testX509SignatureThumbAttached() throws Exception {
422         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
423         WSSecHeader secHeader = new WSSecHeader(doc);
424         secHeader.insertSecurityHeader();
425 
426         WSSecSignature builder = new WSSecSignature(secHeader);
427         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
428         builder.setKeyIdentifierType(WSConstants.THUMBPRINT_IDENTIFIER);
429         builder.setIncludeSignatureToken(true);
430         LOG.info("Before Signing ThumbprintSHA1....");
431 
432         Document signedDoc = builder.build(crypto);
433 
434         if (LOG.isDebugEnabled()) {
435             LOG.debug("Signed message with ThumbprintSHA1 key identifier:");
436             String outputString =
437                 XMLUtils.prettyDocumentToString(signedDoc);
438             LOG.debug(outputString);
439         }
440         LOG.info("After Signing ThumbprintSHA1....");
441 
442         WSHandlerResult results = verify(signedDoc);
443 
444         WSSecurityEngineResult actionResult =
445             results.getActionResults().get(WSConstants.SIGN).get(0);
446         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE));
447         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE));
448         REFERENCE_TYPE referenceType =
449             (REFERENCE_TYPE)actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE);
450         assertTrue(referenceType == REFERENCE_TYPE.THUMBPRINT_SHA1);
451     }
452 
453     /**
454      * Test that signs (twice) and verifies a WS-Security envelope.
455      * The test uses the ThumbprintSHA1 key identifier type.
456      * <p/>
457      *
458      * @throws Exception Thrown when there is any problem in signing or verification
459      */
460     @Test
461     public void testDoubleX509SignatureThumb() throws Exception {
462         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
463         WSSecHeader secHeader = new WSSecHeader(doc);
464         secHeader.insertSecurityHeader();
465 
466         WSSecSignature builder = new WSSecSignature(secHeader);
467         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
468         builder.setKeyIdentifierType(WSConstants.THUMBPRINT_IDENTIFIER);
469 
470         builder.build(crypto);
471         Document signedDoc1 = builder.build(crypto);
472         verify(signedDoc1);
473     }
474 
475 
476     /**
477      * Test that signs and verifies a Timestamp. The request is then modified so that the
478      * Timestamp has a default (WSU) namespace inserted. The signature validation should still
479      * pass due to c14n (see WSS-181).
480      *
481      * @throws Exception Thrown when there is any problem in signing or verification
482      */
483     @Test
484     public void testValidModifiedSignature() throws Exception {
485         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
486         WSSecHeader secHeader = new WSSecHeader(doc);
487         secHeader.insertSecurityHeader();
488 
489         WSSecSignature builder = new WSSecSignature(secHeader);
490         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
491         LOG.info("Before Signing....");
492 
493         WSSecTimestamp timestamp = new WSSecTimestamp(secHeader);
494         timestamp.setTimeToLive(300);
495         timestamp.build();
496 
497         WSEncryptionPart encP =
498             new WSEncryptionPart(
499                 "Timestamp",
500                 WSConstants.WSU_NS,
501                 "");
502         builder.getParts().add(encP);
503 
504         Document signedDoc = builder.build(crypto);
505         Element secHeaderElement = secHeader.getSecurityHeaderElement();
506         Node timestampNode =
507             secHeaderElement.getElementsByTagNameNS(WSConstants.WSU_NS, "Timestamp").item(0);
508         ((Element)timestampNode).setAttributeNS(
509             WSConstants.XMLNS_NS, "xmlns", WSConstants.WSU_NS
510         );
511 
512         if (LOG.isDebugEnabled()) {
513             LOG.debug("After Signing....");
514             String outputString =
515                 XMLUtils.prettyDocumentToString(signedDoc);
516             LOG.debug(outputString);
517         }
518 
519         verify(signedDoc);
520     }
521 
522     /**
523      * Sign using a different digest algorithm (SHA-256).
524      * <p/>
525      *
526      * @throws Exception Thrown when there is any problem in signing or verification
527      */
528     @Test
529     public void testX509SignatureSha256() throws Exception {
530         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
531         WSSecHeader secHeader = new WSSecHeader(doc);
532         secHeader.insertSecurityHeader();
533 
534         WSSecSignature builder = new WSSecSignature(secHeader);
535         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
536         builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
537         builder.setSignatureAlgorithm("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
538         builder.setDigestAlgo("http://www.w3.org/2001/04/xmlenc#sha256");
539         LOG.info("Before Signing IS....");
540 
541         Document signedDoc = builder.build(crypto);
542 
543         String outputString = XMLUtils.prettyDocumentToString(signedDoc);
544         LOG.debug(outputString);
545         assertTrue(outputString.contains(WSConstants.RSA_SHA256));
546 
547         verify(signedDoc);
548     }
549 
550     @Test
551     public void testX509SignatureSha512() throws Exception {
552         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
553         WSSecHeader secHeader = new WSSecHeader(doc);
554         secHeader.insertSecurityHeader();
555 
556         WSSecSignature builder = new WSSecSignature(secHeader);
557         builder.setUserInfo("wss40", "security");
558         builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
559         builder.setSignatureAlgorithm(WSConstants.RSA_SHA512);
560         builder.setDigestAlgo("http://www.w3.org/2001/04/xmlenc#sha256");
561         LOG.info("Before Signing IS....");
562 
563         Crypto wssCrypto = CryptoFactory.getInstance("wss40.properties");
564         Document signedDoc = builder.build(wssCrypto);
565 
566         String outputString = XMLUtils.prettyDocumentToString(signedDoc);
567         LOG.debug(outputString);
568         assertTrue(outputString.contains(WSConstants.RSA_SHA512));
569 
570         LOG.info("After Signing IS....");
571         secEngine.processSecurityHeader(doc, null, null, wssCrypto);
572     }
573 
574     /**
575      * A test for "SignatureAction does not set DigestAlgorithm on WSSecSignature instance"
576      */
577     @Test
578     public void
579     testWSS170() throws Exception {
580         final WSSConfig cfg = WSSConfig.getNewInstance();
581         final RequestData reqData = new RequestData();
582         reqData.setWssConfig(cfg);
583         reqData.setUsername("16c73ab6-b892-458f-abf5-2f875f74882e");
584         java.util.Map<String, Object> config = new java.util.TreeMap<>();
585         config.put(WSHandlerConstants.SIG_PROP_FILE, "crypto.properties");
586         config.put("password", "security");
587         config.put(
588             WSHandlerConstants.SIG_ALGO,
589             "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
590         );
591         config.put(
592             WSHandlerConstants.SIG_DIGEST_ALGO,
593             "http://www.w3.org/2001/04/xmlenc#sha256"
594         );
595         reqData.setMsgContext(config);
596 
597         final Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
598         CustomHandler handler = new CustomHandler();
599         HandlerAction action = new HandlerAction(WSConstants.SIGN);
600         handler.send(
601             doc,
602             reqData,
603             Collections.singletonList(action),
604             true
605         );
606         String outputString =
607             XMLUtils.prettyDocumentToString(doc);
608         if (LOG.isDebugEnabled()) {
609             LOG.debug("Signed message:");
610             LOG.debug(outputString);
611         }
612         assertTrue(
613                 outputString.contains("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256")
614         );
615         assertTrue(
616                 outputString.contains("http://www.w3.org/2001/04/xmlenc#sha256")
617         );
618 
619         verify(doc);
620     }
621 
622     /**
623      * This is a test for WSS-234 -
624      * "When a document contains a comment as its first child element,
625      * wss4j will not find the SOAP body."
626      */
627     @Test
628     public void testWSS234() throws Exception {
629         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
630         WSSecHeader secHeader = new WSSecHeader(doc);
631         secHeader.insertSecurityHeader();
632 
633         WSSecSignature builder = new WSSecSignature(secHeader);
634         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
635         LOG.info("Before Signing....");
636         Document signedDoc = builder.build(crypto);
637 
638         // Add a comment node as the first node element
639         Node firstChild = signedDoc.getFirstChild();
640         Node newNode = signedDoc.removeChild(firstChild);
641         Node commentNode = signedDoc.createComment("This is a comment");
642         signedDoc.appendChild(commentNode);
643         signedDoc.appendChild(newNode);
644 
645         if (LOG.isDebugEnabled()) {
646             LOG.debug("After Signing....");
647             String outputString =
648                 XMLUtils.prettyDocumentToString(signedDoc);
649             LOG.debug(outputString);
650         }
651 
652         verify(signedDoc);
653     }
654 
655     /**
656      * Test that signs and verifies a Timestamp. The Signature element is appended to the security
657      * header, and so appears after the Timestamp element.
658      */
659     @Test
660     public void testSignedTimestamp() throws Exception {
661         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
662         WSSecHeader secHeader = new WSSecHeader(doc);
663         secHeader.insertSecurityHeader();
664 
665         WSSecTimestamp timestamp = new WSSecTimestamp(secHeader);
666         timestamp.setTimeToLive(300);
667         timestamp.build();
668 
669         WSSecSignature builder = new WSSecSignature(secHeader);
670         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
671 
672         WSEncryptionPart encP =
673             new WSEncryptionPart(
674                 "Timestamp",
675                 WSConstants.WSU_NS,
676                 "");
677         builder.getParts().add(encP);
678 
679         builder.prepare(crypto);
680 
681         List<javax.xml.crypto.dsig.Reference> referenceList =
682             builder.addReferencesToSign(builder.getParts());
683 
684         builder.computeSignature(referenceList, false, null);
685 
686         if (LOG.isDebugEnabled()) {
687             LOG.debug("After Signing....");
688             String outputString =
689                 XMLUtils.prettyDocumentToString(doc);
690             LOG.debug(outputString);
691         }
692 
693         verify(doc);
694     }
695 
696     /**
697      * This is a test for WSS-283 - "ClassCastException when signing message with existing
698      * WSSE header containing Text as first child":
699      *
700      * https://issues.apache.org/jira/browse/WSS-283
701      */
702     @Test
703     public void testWSS283() throws Exception {
704         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
705         WSSecHeader secHeader = new WSSecHeader(doc);
706         Element secHeaderElement = secHeader.insertSecurityHeader();
707 
708         WSSecSignature builder = new WSSecSignature(secHeader);
709         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
710         builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
711 
712         Node textNode = doc.createTextNode("This is a text node");
713         secHeaderElement.appendChild(textNode);
714         Document signedDoc = builder.build(crypto);
715 
716         if (LOG.isDebugEnabled()) {
717             LOG.debug("Signed message with text node:");
718             String outputString =
719                 XMLUtils.prettyDocumentToString(signedDoc);
720             LOG.debug(outputString);
721         }
722 
723         verify(signedDoc);
724     }
725 
726     /**
727      * Create a signature that uses a custom SecurityTokenReference.
728      */
729     @Test
730     public void testCustomSTR() throws Exception {
731         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
732         WSSecHeader secHeader = new WSSecHeader(doc);
733         secHeader.insertSecurityHeader();
734 
735         WSSecSignature builder = new WSSecSignature(secHeader);
736         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
737         builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
738         LOG.info("Before Signing IS....");
739 
740         SecurityTokenReference secRef = new SecurityTokenReference(doc);
741         Reference ref = new Reference(doc);
742         ref.setURI("custom-uri");
743         secRef.setReference(ref);
744         builder.setSecurityTokenReference(secRef);
745 
746         Document signedDoc = builder.build(crypto);
747 
748         if (LOG.isDebugEnabled()) {
749             String outputString =
750                 XMLUtils.prettyDocumentToString(signedDoc);
751             LOG.debug(outputString);
752         }
753     }
754 
755     /**
756      * The test uses the Issuer Serial key identifier type.
757      * <p/>
758      *
759      * @throws Exception Thrown when there is any problem in signing or verification
760      */
761     @Test
762     public void testX509SignatureDefaultPassword() throws Exception {
763         Crypto passwordCrypto = CryptoFactory.getInstance("alice.properties");
764 
765         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
766         WSSecHeader secHeader = new WSSecHeader(doc);
767         secHeader.insertSecurityHeader();
768 
769         WSSecSignature builder = new WSSecSignature(secHeader);
770         builder.setUserInfo(passwordCrypto.getDefaultX509Identifier(), null);
771         builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
772         LOG.info("Before Signing IS....");
773         Document signedDoc = builder.build(passwordCrypto);
774 
775         if (LOG.isDebugEnabled()) {
776             LOG.debug("Signed message with IssuerSerial key identifier:");
777             String outputString =
778                 XMLUtils.prettyDocumentToString(signedDoc);
779             LOG.debug(outputString);
780         }
781         LOG.info("After Signing IS....");
782         WSSecurityEngine newEngine = new WSSecurityEngine();
783         newEngine.processSecurityHeader(doc, null, null, passwordCrypto);
784     }
785 
786     /**
787      * A test for "There is an issue with the position of the <Timestamp> element in the
788      * <Security> header when using WSS4J calling .NET Web Services with WS-Security."
789      */
790     @Test
791     public void
792     testWSS231() throws Exception {
793         final WSSConfig cfg = WSSConfig.getNewInstance();
794         final RequestData reqData = new RequestData();
795         reqData.setWssConfig(cfg);
796         reqData.setUsername("16c73ab6-b892-458f-abf5-2f875f74882e");
797 
798         java.util.Map<String, Object> config = new java.util.TreeMap<>();
799         config.put(WSHandlerConstants.SIG_PROP_FILE, "crypto.properties");
800         config.put("password", "security");
801         config.put(
802             WSHandlerConstants.SIGNATURE_PARTS, "{}{" + WSConstants.WSU_NS + "}Timestamp"
803         );
804         reqData.setMsgContext(config);
805 
806         final Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
807         CustomHandler handler = new CustomHandler();
808         List<HandlerAction> actions = new ArrayList<>();
809         actions.add(new HandlerAction(WSConstants.SIGN));
810         actions.add(new HandlerAction(WSConstants.TS));
811         handler.send(
812             doc,
813             reqData,
814             actions,
815             true
816         );
817         String outputString =
818             XMLUtils.prettyDocumentToString(doc);
819         if (LOG.isDebugEnabled()) {
820             LOG.debug("Signed message:");
821             LOG.debug(outputString);
822         }
823 
824         WSHandlerResult results = verify(doc);
825 
826         List<Integer> receivedActions = new ArrayList<>();
827         receivedActions.add(WSConstants.SIGN);
828         receivedActions.add(WSConstants.TS);
829         assertTrue(handler.checkResults(results.getResults(), receivedActions));
830     }
831 
832     @Test
833     public void
834     testSignatureEncryptTimestampOrder() throws Exception {
835         final WSSConfig cfg = WSSConfig.getNewInstance();
836         final RequestData reqData = new RequestData();
837         reqData.setWssConfig(cfg);
838         reqData.setUsername("16c73ab6-b892-458f-abf5-2f875f74882e");
839 
840         java.util.Map<String, Object> config = new java.util.TreeMap<>();
841         config.put(WSHandlerConstants.SIG_PROP_FILE, "crypto.properties");
842         config.put(WSHandlerConstants.ENC_PROP_FILE, "crypto.properties");
843         config.put("password", "security");
844         config.put(
845             WSHandlerConstants.SIGNATURE_PARTS, "{}{" + WSConstants.WSU_NS + "}Timestamp"
846         );
847         reqData.setMsgContext(config);
848 
849         final Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
850         CustomHandler handler = new CustomHandler();
851         List<HandlerAction> actions = new ArrayList<>();
852         actions.add(new HandlerAction(WSConstants.SIGN));
853         actions.add(new HandlerAction(WSConstants.ENCR));
854         actions.add(new HandlerAction(WSConstants.TS));
855         handler.send(
856             doc,
857             reqData,
858             actions,
859             true
860         );
861         String outputString =
862             XMLUtils.prettyDocumentToString(doc);
863         if (LOG.isDebugEnabled()) {
864             LOG.debug("Signed message:");
865             LOG.debug(outputString);
866         }
867 
868         secEngine.processSecurityHeader(doc, null, callbackHandler, crypto);
869     }
870 
871     @Test
872     public void
873     testEncryptSignatureTimestampOrder() throws Exception {
874         final WSSConfig cfg = WSSConfig.getNewInstance();
875         final RequestData reqData = new RequestData();
876         reqData.setWssConfig(cfg);
877         reqData.setUsername("16c73ab6-b892-458f-abf5-2f875f74882e");
878 
879         java.util.Map<String, Object> config = new java.util.TreeMap<>();
880         config.put(WSHandlerConstants.SIG_PROP_FILE, "crypto.properties");
881         config.put(WSHandlerConstants.ENC_PROP_FILE, "crypto.properties");
882         config.put("password", "security");
883         config.put(
884             WSHandlerConstants.SIGNATURE_PARTS, "{}{" + WSConstants.WSU_NS + "}Timestamp"
885         );
886         reqData.setMsgContext(config);
887 
888         final Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
889         CustomHandler handler = new CustomHandler();
890         List<HandlerAction> actions = new ArrayList<>();
891         actions.add(new HandlerAction(WSConstants.ENCR));
892         actions.add(new HandlerAction(WSConstants.SIGN));
893         actions.add(new HandlerAction(WSConstants.TS));
894         handler.send(
895             doc,
896             reqData,
897             actions,
898             true
899         );
900         String outputString =
901             XMLUtils.prettyDocumentToString(doc);
902         if (LOG.isDebugEnabled()) {
903             LOG.debug("Signed message:");
904             LOG.debug(outputString);
905         }
906 
907         secEngine.processSecurityHeader(doc, null, callbackHandler, crypto);
908     }
909 
910     @Test
911     public void testWSHandlerSignatureCanonicalization() throws Exception {
912         final WSSConfig cfg = WSSConfig.getNewInstance();
913         final RequestData reqData = new RequestData();
914         reqData.setWssConfig(cfg);
915         reqData.setUsername("16c73ab6-b892-458f-abf5-2f875f74882e");
916 
917         java.util.Map<String, Object> config = new java.util.TreeMap<>();
918         config.put(WSHandlerConstants.SIG_PROP_FILE, "crypto.properties");
919         config.put(WSHandlerConstants.SIG_C14N_ALGO, WSConstants.C14N_WITH_COMMENTS);
920         config.put("password", "security");
921         reqData.setMsgContext(config);
922 
923         final Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
924         CustomHandler handler = new CustomHandler();
925         HandlerAction action = new HandlerAction(WSConstants.SIGN);
926         handler.send(
927             doc,
928             reqData,
929             Collections.singletonList(action),
930             true
931         );
932         String outputString =
933             XMLUtils.prettyDocumentToString(doc);
934         if (LOG.isDebugEnabled()) {
935             LOG.debug("Signed message:");
936             LOG.debug(outputString);
937         }
938 
939         RequestData data = new RequestData();
940         data.setWssConfig(WSSConfig.getNewInstance());
941         data.setSigVerCrypto(crypto);
942 
943         List<BSPRule> disabledRules = new ArrayList<>();
944         disabledRules.add(BSPRule.R5404);
945         disabledRules.add(BSPRule.R5406);
946         data.setIgnoredBSPRules(disabledRules);
947 
948         WSSecurityEngine newSecEngine = new WSSecurityEngine();
949         WSHandlerResult results =
950             newSecEngine.processSecurityHeader(doc, data);
951         assertTrue(handler.checkResults(results.getResults(),
952                                         Collections.singletonList(WSConstants.SIGN)));
953     }
954 
955     // See WSS-540
956     @Test
957     public void testLoadSignaturePropertiesFromFileSystem() throws Exception {
958         final WSSConfig cfg = WSSConfig.getNewInstance();
959         final RequestData reqData = new RequestData();
960         reqData.setWssConfig(cfg);
961         reqData.setUsername("16c73ab6-b892-458f-abf5-2f875f74882e");
962 
963         java.util.Map<String, Object> config = new java.util.TreeMap<>();
964 
965         String basedir = System.getProperty("basedir");
966         if (basedir == null) {
967             basedir = new File(".").getCanonicalPath();
968         }
969         File propsFile = new File(basedir + "/src/test/resources/crypto.properties");
970 
971         config.put(WSHandlerConstants.SIG_PROP_FILE, propsFile.getPath());
972         config.put("password", "security");
973         reqData.setMsgContext(config);
974 
975         final Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
976         CustomHandler handler = new CustomHandler();
977         HandlerAction action = new HandlerAction(WSConstants.SIGN);
978         handler.send(
979             doc,
980             reqData,
981             Collections.singletonList(action),
982             true
983         );
984         String outputString =
985             XMLUtils.prettyDocumentToString(doc);
986         if (LOG.isDebugEnabled()) {
987             LOG.debug("Signed message:");
988             LOG.debug(outputString);
989         }
990 
991         RequestData data = new RequestData();
992         data.setWssConfig(WSSConfig.getNewInstance());
993         data.setSigVerCrypto(crypto);
994 
995         WSSecurityEngine newSecEngine = new WSSecurityEngine();
996         WSHandlerResult results =
997             newSecEngine.processSecurityHeader(doc, data);
998         assertTrue(handler.checkResults(results.getResults(),
999                                         Collections.singletonList(WSConstants.SIGN)));
1000     }
1001 
1002     @Test
1003     public void testCommentInSOAPBody() throws Exception {
1004         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
1005         WSSecHeader secHeader = new WSSecHeader(doc);
1006         secHeader.insertSecurityHeader();
1007 
1008         WSSecSignature builder = new WSSecSignature(secHeader);
1009         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
1010         LOG.info("Before Signing....");
1011         Document signedDoc = builder.build(crypto);
1012 
1013         // Add a comment node
1014         Element body = WSSecurityUtil.findBodyElement(signedDoc);
1015         Node commentNode = signedDoc.createComment("This is a comment");
1016         body.getFirstChild().appendChild(commentNode);
1017 
1018         if (LOG.isDebugEnabled()) {
1019             String outputString =
1020                 XMLUtils.prettyDocumentToString(signedDoc);
1021             LOG.debug(outputString);
1022         }
1023 
1024         verify(signedDoc);
1025     }
1026 
1027     @Test
1028     public void testCustomKeyInfoElementCreation() throws Exception {
1029         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
1030         WSSecHeader secHeader = new WSSecHeader(doc);
1031         secHeader.insertSecurityHeader();
1032 
1033         // Create the KeyInfo
1034         DocumentBuilderFactory docBuilderFactory =
1035             DocumentBuilderFactory.newInstance();
1036         docBuilderFactory.setNamespaceAware(true);
1037         DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
1038         Document keyInfoDoc = docBuilder.newDocument();
1039 
1040         CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
1041         cryptoType.setAlias("16c73ab6-b892-458f-abf5-2f875f74882e");
1042         X509Certificate[] certs = crypto.getX509Certificates(cryptoType);
1043 
1044         KeyInfoFactory keyInfoFactory =
1045             XMLSignatureFactory.getInstance("DOM", "ApacheXMLDSig").getKeyInfoFactory();
1046 
1047         // X.509
1048         X509Data x509Data = keyInfoFactory.newX509Data(Collections.singletonList(certs[0]));
1049         KeyInfo keyInfo = keyInfoFactory.newKeyInfo(Collections.singletonList(x509Data), null);
1050 
1051         // Marshal the KeyInfo to DOM
1052         Element parent = keyInfoDoc.createElement("temp");
1053         DOMCryptoContext cryptoContext = new DOMCryptoContext() { };
1054         cryptoContext.putNamespacePrefix(WSConstants.SIG_NS, WSConstants.SIG_PREFIX);
1055         keyInfo.marshal(new DOMStructure(parent), cryptoContext);
1056 
1057         Element keyInfoElement = (Element)parent.getFirstChild();
1058 
1059         WSSecSignature builder = new WSSecSignature(secHeader);
1060         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
1061         builder.setCustomKeyInfoElement(keyInfoElement);
1062         LOG.info("Before Signing IS....");
1063 
1064         Document signedDoc = builder.build(crypto);
1065 
1066         if (LOG.isDebugEnabled()) {
1067             String outputString =
1068                 XMLUtils.prettyDocumentToString(signedDoc);
1069             LOG.debug(outputString);
1070         }
1071 
1072         assertNotNull(signedDoc);
1073     }
1074 
1075     /**
1076      * Verifies the soap envelope.
1077      * This method verifies all the signature generated.
1078      *
1079      * @param doc soap document
1080      * @throws Exception Thrown when there is a problem in verification
1081      */
1082     private WSHandlerResult verify(Document doc) throws Exception {
1083         return secEngine.processSecurityHeader(doc, null, null, crypto);
1084     }
1085 
1086 }