1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.ws.security.message;
21  
22  import java.util.ArrayList;
23  import java.util.List;
24  
25  import javax.security.auth.callback.CallbackHandler;
26  
27  import org.apache.ws.security.WSEncryptionPart;
28  import org.apache.ws.security.WSSConfig;
29  import org.apache.ws.security.WSSecurityEngine;
30  import org.apache.ws.security.WSConstants;
31  import org.apache.ws.security.WSSecurityEngineResult;
32  import org.apache.ws.security.WSSecurityException;
33  import org.apache.ws.security.common.CustomHandler;
34  import org.apache.ws.security.common.KeystoreCallbackHandler;
35  import org.apache.ws.security.common.SOAPUtil;
36  import org.apache.ws.security.components.crypto.Crypto;
37  import org.apache.ws.security.components.crypto.CryptoFactory;
38  import org.apache.ws.security.handler.RequestData;
39  import org.apache.ws.security.handler.WSHandlerConstants;
40  import org.apache.ws.security.message.token.Reference;
41  import org.apache.ws.security.message.token.SecurityTokenReference;
42  import org.apache.ws.security.str.STRParser.REFERENCE_TYPE;
43  import org.apache.ws.security.util.WSSecurityUtil;
44  import org.w3c.dom.Document;
45  import org.w3c.dom.Element;
46  import org.w3c.dom.Node;
47  
48  
49  /**
50   * A set of test-cases for signing and verifying SOAP requests.
51   * 
52   * @author Davanum Srinivas (dims@yahoo.com)
53   * @author Werner Dittmann (Werner.Dittmann@siemens.com)
54   */
55  public class SignatureTest extends org.junit.Assert {
56      private static final org.apache.commons.logging.Log LOG = 
57          org.apache.commons.logging.LogFactory.getLog(SignatureTest.class);
58      
59      private WSSecurityEngine secEngine = new WSSecurityEngine();
60      private CallbackHandler callbackHandler = new KeystoreCallbackHandler();
61      private Crypto crypto = null;
62      
63      public SignatureTest() throws Exception {
64          WSSConfig.init();
65          crypto = CryptoFactory.getInstance();
66      }
67  
68      /**
69       * The test uses the Issuer Serial key identifier type.
70       * <p/>
71       * 
72       * @throws java.lang.Exception Thrown when there is any problem in signing or verification
73       */
74      @org.junit.Test
75      public void testX509SignatureIS() throws Exception {
76          WSSecSignature builder = new WSSecSignature();
77          builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
78          builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
79          LOG.info("Before Signing IS....");
80          Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
81          WSSecHeader secHeader = new WSSecHeader();
82          secHeader.insertSecurityHeader(doc);
83          Document signedDoc = builder.build(doc, crypto, secHeader);
84  
85          if (LOG.isDebugEnabled()) {
86              LOG.debug("Signed message with IssuerSerial key identifier:");
87              String outputString = 
88                  org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
89              LOG.debug(outputString);
90          }
91          LOG.info("After Signing IS....");
92          List<WSSecurityEngineResult> results = verify(signedDoc);
93          
94          WSSecurityEngineResult actionResult =
95                  WSSecurityUtil.fetchActionResult(results, WSConstants.SIGN);
96          assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE));
97          assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE));
98          REFERENCE_TYPE referenceType = 
99              (REFERENCE_TYPE)actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE);
100         assertTrue(referenceType == REFERENCE_TYPE.ISSUER_SERIAL);
101     }
102     
103 
104     /**
105      * Test that signs (twice) and verifies a WS-Security envelope.
106      * <p/>
107      * 
108      * @throws java.lang.Exception Thrown when there is any problem in signing or verification
109      */
110     @org.junit.Test
111     public void testDoubleX509SignatureIS() throws Exception {
112         WSSecSignature builder = new WSSecSignature();
113         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
114         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
115         WSSecHeader secHeader = new WSSecHeader();
116         secHeader.insertSecurityHeader(doc);
117         Document signedDoc = builder.build(doc, crypto, secHeader);
118         Document signedDoc1 = builder.build(signedDoc, crypto, secHeader);
119         verify(signedDoc1);
120     }
121     
122     /**
123      * Test that signs and verifies a WS-Security envelope
124      * <p/>
125      * 
126      * @throws java.lang.Exception Thrown when there is any problem in signing or verification
127      */
128     @org.junit.Test
129     public void testIssuerSerialSignature() throws Exception {
130         WSSecSignature builder = new WSSecSignature();
131         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
132         LOG.info("Before Signing....");
133         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
134         WSSecHeader secHeader = new WSSecHeader();
135         secHeader.insertSecurityHeader(doc);
136         Document signedDoc = builder.build(doc, crypto, secHeader);
137 
138         if (LOG.isDebugEnabled()) {
139             LOG.debug("After Signing....");
140             String outputString = 
141                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
142             LOG.debug(outputString);
143         }
144         
145         verify(signedDoc);
146     }
147     
148     /**
149      * Test that signs and verifies a WS-Security envelope
150      * <p/>
151      * 
152      * @throws java.lang.Exception Thrown when there is any problem in signing or verification
153      */
154     @org.junit.Test
155     public void testSignatureInclusiveC14N() throws Exception {
156         WSSecSignature builder = new WSSecSignature();
157         builder.setSigCanonicalization(WSConstants.C14N_OMIT_COMMENTS);
158         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
159         LOG.info("Before Signing....");
160         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
161         WSSecHeader secHeader = new WSSecHeader();
162         secHeader.insertSecurityHeader(doc);
163         Document signedDoc = builder.build(doc, crypto, secHeader);
164 
165         if (LOG.isDebugEnabled()) {
166             LOG.debug("After Signing....");
167             String outputString = 
168                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
169             LOG.debug(outputString);
170         }
171         
172         // Turn off BSP spec compliance
173         WSSecurityEngine newEngine = new WSSecurityEngine();
174         WSSConfig config = WSSConfig.getNewInstance();
175         config.setWsiBSPCompliant(false);
176         newEngine.setWssConfig(config);
177         newEngine.processSecurityHeader(doc, null, null, crypto);
178         
179         // Now turn on BSP spec compliance
180         config.setWsiBSPCompliant(true);
181         newEngine.setWssConfig(config);
182         try {
183             newEngine.processSecurityHeader(doc, null, null, crypto);
184             fail("Failure expected on a bad c14n algorithm");
185         } catch (WSSecurityException ex) {
186             assertTrue(ex.getMessage().contains("bad canonicalization algorithm"));
187         }
188     }
189     
190     /**
191      * Test that signs and verifies a WS-Security envelope
192      * <p/>
193      * 
194      * @throws java.lang.Exception Thrown when there is any problem in signing or verification
195      */
196     @org.junit.Test
197     public void testSignatureInclusivePrefixes() throws Exception {
198         WSSConfig wssConfig = WSSConfig.getNewInstance();
199         wssConfig.setWsiBSPCompliant(true);
200         WSSecSignature builder = new WSSecSignature();
201         builder.setWsConfig(wssConfig);
202         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
203         LOG.info("Before Signing....");
204         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
205         WSSecHeader secHeader = new WSSecHeader();
206         secHeader.insertSecurityHeader(doc);
207         Document signedDoc = builder.build(doc, crypto, secHeader);
208 
209         if (LOG.isDebugEnabled()) {
210             LOG.debug("After Signing....");
211             String outputString = 
212                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
213             LOG.debug(outputString);
214         }
215         
216         verify(signedDoc);
217     }
218     
219     /**
220      * Test that signs and verifies a WS-Security envelope
221      * <p/>
222      * 
223      * @throws java.lang.Exception Thrown when there is any problem in signing or verification
224      */
225     @org.junit.Test
226     public void testBSTSignature() throws Exception {
227         WSSecSignature builder = new WSSecSignature();
228         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
229         builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
230         LOG.info("Before Signing....");
231         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
232         WSSecHeader secHeader = new WSSecHeader();
233         secHeader.insertSecurityHeader(doc);
234         Document signedDoc = builder.build(doc, crypto, secHeader);
235 
236         if (LOG.isDebugEnabled()) {
237             LOG.debug("After Signing....");
238             String outputString = 
239                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
240             LOG.debug(outputString);
241         }
242         
243         List<WSSecurityEngineResult> results = verify(signedDoc);
244         
245         WSSecurityEngineResult actionResult =
246                 WSSecurityUtil.fetchActionResult(results, WSConstants.SIGN);
247         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE));
248         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE));
249         REFERENCE_TYPE referenceType = 
250             (REFERENCE_TYPE)actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE);
251         assertTrue(referenceType == REFERENCE_TYPE.DIRECT_REF);
252     }
253     
254     /**
255      * Test that signs and verifies a WS-Security envelope
256      * <p/>
257      * 
258      * @throws java.lang.Exception Thrown when there is any problem in signing or verification
259      */
260     @org.junit.Test
261     public void testBSTPKIPathSignature() throws Exception {
262         WSSecSignature builder = new WSSecSignature();
263         builder.setUserInfo("wss40", "security");
264         builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
265         builder.setUseSingleCertificate(false);
266         LOG.info("Before Signing....");
267         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
268         WSSecHeader secHeader = new WSSecHeader();
269         secHeader.insertSecurityHeader(doc);
270         
271         Crypto pkiCrypto = CryptoFactory.getInstance("wss40.properties");
272         Document signedDoc = builder.build(doc, pkiCrypto, secHeader);
273 
274         if (LOG.isDebugEnabled()) {
275             LOG.debug("After PKI Signing....");
276             String outputString = 
277                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
278             LOG.debug(outputString);
279         }
280         
281         secEngine.processSecurityHeader(doc, null, callbackHandler, pkiCrypto, null);
282     }
283     
284     /**
285      * Test that signs and verifies a WS-Security envelope
286      * <p/>
287      * 
288      * @throws java.lang.Exception Thrown when there is any problem in signing or verification
289      */
290     @org.junit.Test
291     public void testX509Signature() throws Exception {
292         WSSecSignature builder = new WSSecSignature();
293         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
294         builder.setKeyIdentifierType(WSConstants.X509_KEY_IDENTIFIER);
295         LOG.info("Before Signing....");
296         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
297         WSSecHeader secHeader = new WSSecHeader();
298         secHeader.insertSecurityHeader(doc);
299         Document signedDoc = builder.build(doc, crypto, secHeader);
300 
301         if (LOG.isDebugEnabled()) {
302             LOG.debug("After Signing....");
303             String outputString = 
304                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
305             LOG.debug(outputString);
306         }
307         
308         // Turn off BSP spec compliance
309         WSSecurityEngine newEngine = new WSSecurityEngine();
310         WSSConfig config = WSSConfig.getNewInstance();
311         config.setWsiBSPCompliant(false);
312         newEngine.setWssConfig(config);
313         List<WSSecurityEngineResult> results = newEngine.processSecurityHeader(doc, null, null, crypto);
314         
315         WSSecurityEngineResult actionResult =
316                 WSSecurityUtil.fetchActionResult(results, WSConstants.SIGN);
317         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE));
318         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE));
319         REFERENCE_TYPE referenceType = 
320             (REFERENCE_TYPE)actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE);
321         assertTrue(referenceType == REFERENCE_TYPE.KEY_IDENTIFIER);
322         
323         // Now turn on BSP spec compliance
324         config.setWsiBSPCompliant(true);
325         newEngine.setWssConfig(config);
326         try {
327             newEngine.processSecurityHeader(doc, null, null, crypto);
328             fail("Failure expected on a bad ValueType attribute");
329         } catch (WSSecurityException ex) {
330             // expected
331         }
332     }
333     
334     /**
335      * Test that signs and verifies a WS-Security envelope.
336      * The test uses the ThumbprintSHA1 key identifier type. 
337      * <p/>
338      * 
339      * @throws java.lang.Exception Thrown when there is any problem in signing or verification
340      */
341     @org.junit.Test
342     public void testX509SignatureThumb() throws Exception {
343         WSSecSignature builder = new WSSecSignature();
344         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
345         builder.setKeyIdentifierType(WSConstants.THUMBPRINT_IDENTIFIER);
346         LOG.info("Before Signing ThumbprintSHA1....");
347         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
348         
349         WSSecHeader secHeader = new WSSecHeader();
350         secHeader.insertSecurityHeader(doc);
351 
352         Document signedDoc = builder.build(doc, crypto, secHeader);
353 
354         if (LOG.isDebugEnabled()) {
355             LOG.debug("Signed message with ThumbprintSHA1 key identifier:");
356             String outputString = 
357                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
358             LOG.debug(outputString);
359         }
360         LOG.info("After Signing ThumbprintSHA1....");
361         
362         List<WSSecurityEngineResult> results = verify(signedDoc);
363         
364         WSSecurityEngineResult actionResult =
365                 WSSecurityUtil.fetchActionResult(results, WSConstants.SIGN);
366         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE));
367         assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE));
368         REFERENCE_TYPE referenceType = 
369             (REFERENCE_TYPE)actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE);
370         assertTrue(referenceType == REFERENCE_TYPE.THUMBPRINT_SHA1);
371     }
372 
373     
374     /**
375      * Test that signs (twice) and verifies a WS-Security envelope.
376      * The test uses the ThumbprintSHA1 key identifier type.
377      * <p/>
378      * 
379      * @throws java.lang.Exception Thrown when there is any problem in signing or verification
380      */
381     @org.junit.Test
382     public void testDoubleX509SignatureThumb() throws Exception {
383         WSSecSignature builder = new WSSecSignature();
384         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
385         builder.setKeyIdentifierType(WSConstants.THUMBPRINT_IDENTIFIER);
386         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
387         
388         WSSecHeader secHeader = new WSSecHeader();
389         secHeader.insertSecurityHeader(doc);
390 
391         Document signedDoc = builder.build(doc, crypto, secHeader);
392         Document signedDoc1 = builder.build(signedDoc, crypto, secHeader);
393         verify(signedDoc1);
394     }
395     
396     
397     /**
398      * Test that signs and verifies a Timestamp. The request is then modified so that the
399      * Timestamp has a default (WSU) namespace inserted. The signature validation should still
400      * pass due to c14n (see WSS-181).
401      * 
402      * @throws java.lang.Exception Thrown when there is any problem in signing or verification
403      */
404     @org.junit.Test
405     public void testValidModifiedSignature() throws Exception {
406         WSSecSignature builder = new WSSecSignature();
407         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
408         LOG.info("Before Signing....");
409         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
410         WSSecHeader secHeader = new WSSecHeader();
411         secHeader.insertSecurityHeader(doc);
412         
413         WSSecTimestamp timestamp = new WSSecTimestamp();
414         timestamp.setTimeToLive(300);
415         Document createdDoc = timestamp.build(doc, secHeader);
416         
417         List<WSEncryptionPart> parts = new ArrayList<WSEncryptionPart>();
418         WSEncryptionPart encP =
419             new WSEncryptionPart(
420                 "Timestamp",
421                 WSConstants.WSU_NS,
422                 "");
423         parts.add(encP);
424         builder.setParts(parts);
425         
426         Document signedDoc = builder.build(createdDoc, crypto, secHeader);
427         org.w3c.dom.Element secHeaderElement = secHeader.getSecurityHeader();
428         org.w3c.dom.Node timestampNode = 
429             secHeaderElement.getElementsByTagNameNS(WSConstants.WSU_NS, "Timestamp").item(0);
430         ((org.w3c.dom.Element)timestampNode).setAttributeNS(
431             WSConstants.XMLNS_NS, "xmlns", WSConstants.WSU_NS
432         );
433         
434         if (LOG.isDebugEnabled()) {
435             LOG.debug("After Signing....");
436             String outputString = 
437                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
438             LOG.debug(outputString);
439         }
440         
441         verify(signedDoc);
442     }
443     
444     /**
445      * Sign using a different digest algorithm (SHA-256).
446      * <p/>
447      * 
448      * @throws java.lang.Exception Thrown when there is any problem in signing or verification
449      */
450     @org.junit.Test
451     public void testX509SignatureSha256() throws Exception {
452         WSSecSignature builder = new WSSecSignature();
453         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
454         builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
455         builder.setSignatureAlgorithm("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
456         builder.setDigestAlgo("http://www.w3.org/2001/04/xmlenc#sha256");
457         LOG.info("Before Signing IS....");
458         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
459         WSSecHeader secHeader = new WSSecHeader();
460         secHeader.insertSecurityHeader(doc);
461         Document signedDoc = builder.build(doc, crypto, secHeader);
462 
463         if (LOG.isDebugEnabled()) {
464             LOG.debug("Signed message with IssuerSerial key identifier:");
465             String outputString = 
466                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
467             LOG.debug(outputString);
468         }
469         LOG.info("After Signing IS....");
470         verify(signedDoc);
471     }
472     
473     /**
474      * A test for "SignatureAction does not set DigestAlgorithm on WSSecSignature instance"
475      */
476     @org.junit.Test
477     public void
478     testWSS170() throws Exception {
479         final WSSConfig cfg = WSSConfig.getNewInstance();
480         final int action = WSConstants.SIGN;
481         final RequestData reqData = new RequestData();
482         reqData.setWssConfig(cfg);
483         reqData.setUsername("16c73ab6-b892-458f-abf5-2f875f74882e");
484         java.util.Map<String, Object> config = new java.util.TreeMap<String, Object>();
485         config.put(WSHandlerConstants.SIG_PROP_FILE, "crypto.properties");
486         config.put("password", "security");
487         config.put(
488             WSHandlerConstants.SIG_ALGO, 
489             "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
490         );
491         config.put(
492             WSHandlerConstants.SIG_DIGEST_ALGO, 
493             "http://www.w3.org/2001/04/xmlenc#sha256"
494         );
495         reqData.setMsgContext(config);
496         
497         final java.util.List<Integer> actions = new java.util.ArrayList<Integer>();
498         actions.add(Integer.valueOf(action));
499         final Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
500         CustomHandler handler = new CustomHandler();
501         handler.send(
502             action, 
503             doc, 
504             reqData, 
505             actions,
506             true
507         );
508         String outputString = 
509             org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
510         if (LOG.isDebugEnabled()) {
511             LOG.debug("Signed message:");
512             LOG.debug(outputString);
513         }
514         assertTrue(
515             outputString.indexOf("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256") != -1
516         );
517         assertTrue(
518             outputString.indexOf("http://www.w3.org/2001/04/xmlenc#sha256") != -1
519         );
520         
521         verify(doc);
522     }
523     
524     /**
525      * This is a test for WSS-234 - 
526      * "When a document contains a comment as its first child element, 
527      * wss4j will not find the SOAP body." 
528      */
529     @org.junit.Test
530     public void testWSS234() throws Exception {
531         WSSecSignature builder = new WSSecSignature();
532         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
533         LOG.info("Before Signing....");
534         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
535         WSSecHeader secHeader = new WSSecHeader();
536         secHeader.insertSecurityHeader(doc);
537         Document signedDoc = builder.build(doc, crypto, secHeader);
538         
539         // Add a comment node as the first node element
540         org.w3c.dom.Node firstChild = signedDoc.getFirstChild();
541         org.w3c.dom.Node newNode = signedDoc.removeChild(firstChild);
542         org.w3c.dom.Node commentNode = signedDoc.createComment("This is a comment");
543         signedDoc.appendChild(commentNode);
544         signedDoc.appendChild(newNode);
545 
546         if (LOG.isDebugEnabled()) {
547             LOG.debug("After Signing....");
548             String outputString = 
549                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
550             LOG.debug(outputString);
551         }
552         
553         verify(signedDoc);
554     }
555     
556     /**
557      * Test that signs and verifies a Timestamp. The Signature element is appended to the security
558      * header, and so appears after the Timestamp element.
559      */
560     @org.junit.Test
561     public void testSignedTimestamp() throws Exception {
562         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
563         WSSecHeader secHeader = new WSSecHeader();
564         secHeader.insertSecurityHeader(doc);
565         
566         WSSecTimestamp timestamp = new WSSecTimestamp();
567         timestamp.setTimeToLive(300);
568         Document createdDoc = timestamp.build(doc, secHeader);
569         
570         List<WSEncryptionPart> parts = new ArrayList<WSEncryptionPart>();
571         WSEncryptionPart encP =
572             new WSEncryptionPart(
573                 "Timestamp",
574                 WSConstants.WSU_NS,
575                 "");
576         parts.add(encP);
577         
578         WSSecSignature builder = new WSSecSignature();
579         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
580         builder.setParts(parts);
581         
582         builder.prepare(createdDoc, crypto, secHeader);
583         
584         List<javax.xml.crypto.dsig.Reference> referenceList = 
585             builder.addReferencesToSign(parts, secHeader);
586 
587         builder.computeSignature(referenceList, false, null);
588         
589         if (LOG.isDebugEnabled()) {
590             LOG.debug("After Signing....");
591             String outputString = 
592                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
593             LOG.debug(outputString);
594         }
595         
596         verify(doc);
597     }
598     
599     /**
600      * This is a test for WSS-283 - "ClassCastException when signing message with existing 
601      * WSSE header containing Text as first child":
602      * 
603      * https://issues.apache.org/jira/browse/WSS-283
604      */
605     @org.junit.Test
606     public void testWSS283() throws Exception {
607         WSSecSignature builder = new WSSecSignature();
608         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
609         builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
610         
611         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
612         WSSecHeader secHeader = new WSSecHeader();
613         Element secHeaderElement = secHeader.insertSecurityHeader(doc);
614         Node textNode = doc.createTextNode("This is a text node");
615         secHeaderElement.appendChild(textNode);
616         Document signedDoc = builder.build(doc, crypto, secHeader);
617         
618         if (LOG.isDebugEnabled()) {
619             LOG.debug("Signed message with text node:");
620             String outputString = 
621                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
622             LOG.debug(outputString);
623         }
624         
625         verify(signedDoc);
626     }
627     
628     /**
629      * Create a signature that uses a custom SecurityTokenReference.
630      */
631     @org.junit.Test
632     public void testCustomSTR() throws Exception {
633         WSSecSignature builder = new WSSecSignature();
634         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
635         builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
636         LOG.info("Before Signing IS....");
637         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
638         WSSecHeader secHeader = new WSSecHeader();
639         secHeader.insertSecurityHeader(doc);
640         
641         SecurityTokenReference secRef = new SecurityTokenReference(doc);
642         Reference ref = new Reference(doc);
643         ref.setURI("custom-uri");
644         secRef.setReference(ref);
645         builder.setSecurityTokenReference(secRef);
646         
647         Document signedDoc = builder.build(doc, crypto, secHeader);
648 
649         if (LOG.isDebugEnabled()) {
650             String outputString = 
651                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
652             LOG.debug(outputString);
653         }
654     }
655     
656     /**
657      * The test uses the Issuer Serial key identifier type.
658      * <p/>
659      * 
660      * @throws java.lang.Exception Thrown when there is any problem in signing or verification
661      */
662     @org.junit.Test
663     public void testX509SignatureDefaultPassword() throws Exception {
664         Crypto passwordCrypto = CryptoFactory.getInstance("alice.properties");
665         
666         WSSecSignature builder = new WSSecSignature();
667         builder.setUserInfo(passwordCrypto.getDefaultX509Identifier(), null);
668         builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
669         LOG.info("Before Signing IS....");
670         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
671         WSSecHeader secHeader = new WSSecHeader();
672         secHeader.insertSecurityHeader(doc);
673         Document signedDoc = builder.build(doc, passwordCrypto, secHeader);
674 
675         if (LOG.isDebugEnabled()) {
676             LOG.debug("Signed message with IssuerSerial key identifier:");
677             String outputString = 
678                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
679             LOG.debug(outputString);
680         }
681         LOG.info("After Signing IS....");
682         WSSecurityEngine newEngine = new WSSecurityEngine();
683         newEngine.processSecurityHeader(doc, null, null, passwordCrypto);
684     }
685     
686     /**
687      * A test for "There is an issue with the position of the <Timestamp> element in the
688      * <Security> header when using WSS4J calling .NET Web Services with WS-Security."
689      */
690     @org.junit.Test
691     public void
692     testWSS231() throws Exception {
693         final WSSConfig cfg = WSSConfig.getNewInstance();
694         final int action = WSConstants.SIGN | WSConstants.TS;
695         final RequestData reqData = new RequestData();
696         reqData.setWssConfig(cfg);
697         reqData.setUsername("16c73ab6-b892-458f-abf5-2f875f74882e");
698         
699         java.util.Map<String, Object> config = new java.util.TreeMap<String, Object>();
700         config.put(WSHandlerConstants.SIG_PROP_FILE, "crypto.properties");
701         config.put("password", "security");
702         config.put(
703             WSHandlerConstants.SIGNATURE_PARTS, "{}{" + WSConstants.WSU_NS + "}Timestamp"
704         );
705         reqData.setMsgContext(config);
706         
707         final java.util.List<Integer> actions = new java.util.ArrayList<Integer>();
708         actions.add(Integer.valueOf(WSConstants.SIGN));
709         actions.add(Integer.valueOf(WSConstants.TS));
710         final Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
711         CustomHandler handler = new CustomHandler();
712         handler.send(
713             action, 
714             doc, 
715             reqData, 
716             actions,
717             true
718         );
719         String outputString = 
720             org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
721         if (LOG.isDebugEnabled()) {
722             LOG.debug("Signed message:");
723             LOG.debug(outputString);
724         }
725         
726         List<WSSecurityEngineResult> results = verify(doc);
727         assertTrue(handler.checkResults(results, actions));
728     }
729 
730     /**
731      * Verifies the soap envelope.
732      * This method verifies all the signature generated. 
733      * 
734      * @param env soap envelope
735      * @throws java.lang.Exception Thrown when there is a problem in verification
736      */
737     private List<WSSecurityEngineResult> verify(Document doc) throws Exception {
738         return secEngine.processSecurityHeader(doc, null, null, crypto);
739     }
740 
741 }