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.time.Instant;
23  import java.time.ZoneOffset;
24  import java.time.ZonedDateTime;
25  import java.util.ArrayList;
26  import java.util.Collections;
27  import java.util.List;
28  import java.util.Locale;
29  
30  import org.apache.wss4j.common.bsp.BSPEnforcer;
31  import org.apache.wss4j.common.bsp.BSPRule;
32  import org.apache.wss4j.common.ext.WSSecurityException;
33  import org.apache.wss4j.common.util.DateUtil;
34  import org.apache.wss4j.common.util.SOAPUtil;
35  import org.apache.wss4j.common.util.WSTimeSource;
36  import org.apache.wss4j.common.util.XMLUtils;
37  import org.apache.wss4j.dom.WSConstants;
38  
39  import org.apache.wss4j.dom.engine.WSSConfig;
40  import org.apache.wss4j.dom.engine.WSSecurityEngine;
41  import org.apache.wss4j.dom.engine.WSSecurityEngineResult;
42  import org.apache.wss4j.dom.handler.RequestData;
43  import org.apache.wss4j.dom.handler.WSHandlerResult;
44  import org.apache.wss4j.dom.message.token.Timestamp;
45  import org.apache.wss4j.dom.validate.NoOpValidator;
46  
47  import org.junit.jupiter.api.Test;
48  import org.w3c.dom.Document;
49  import org.w3c.dom.Element;
50  
51  import static org.junit.jupiter.api.Assertions.assertNotNull;
52  import static org.junit.jupiter.api.Assertions.assertTrue;
53  import static org.junit.jupiter.api.Assertions.fail;
54  
55  /**
56   * WS-Security Test Case for Timestamps.
57   */
58  public class TimestampTest {
59      private static final org.slf4j.Logger LOG =
60          org.slf4j.LoggerFactory.getLogger(TimestampTest.class);
61  
62      /**
63       * This is a test for processing a valid Timestamp.
64       */
65      @Test
66      public void testValidTimestamp() throws Exception {
67  
68          Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
69          WSSecHeader secHeader = new WSSecHeader(doc);
70          secHeader.insertSecurityHeader();
71  
72          WSSecTimestamp timestamp = new WSSecTimestamp(secHeader);
73          timestamp.setTimeToLive(300);
74          Document createdDoc = timestamp.build();
75  
76          if (LOG.isDebugEnabled()) {
77              String outputString =
78                  XMLUtils.prettyDocumentToString(createdDoc);
79              LOG.debug(outputString);
80          }
81  
82          //
83          // Do some processing
84          //
85          WSHandlerResult wsResult = verify(createdDoc);
86          WSSecurityEngineResult actionResult =
87              wsResult.getActionResults().get(WSConstants.TS).get(0);
88          assertNotNull(actionResult);
89  
90          Timestamp receivedTimestamp =
91              (Timestamp)actionResult.get(WSSecurityEngineResult.TAG_TIMESTAMP);
92          assertNotNull(receivedTimestamp);
93  
94          Timestamp clone = new Timestamp(receivedTimestamp.getElement(), new BSPEnforcer(true));
95          assertTrue(clone.equals(receivedTimestamp));
96          assertTrue(clone.hashCode() == receivedTimestamp.hashCode());
97      }
98  
99  
100     /**
101      * This is a test for processing a valid Timestamp with no expires element
102      */
103     @Test
104     public void testValidTimestampNoExpires() throws Exception {
105 
106         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
107         WSSecHeader secHeader = new WSSecHeader(doc);
108         secHeader.insertSecurityHeader();
109 
110         WSSecTimestamp timestamp = new WSSecTimestamp(secHeader);
111         timestamp.setTimeToLive(0);
112         Document createdDoc = timestamp.build();
113 
114         if (LOG.isDebugEnabled()) {
115             String outputString =
116                 XMLUtils.prettyDocumentToString(createdDoc);
117             LOG.debug(outputString);
118         }
119 
120         //
121         // Do some processing
122         //
123         WSHandlerResult wsResult = verify(createdDoc);
124         WSSecurityEngineResult actionResult =
125             wsResult.getActionResults().get(WSConstants.TS).get(0);
126         assertNotNull(actionResult);
127 
128         Timestamp receivedTimestamp =
129             (Timestamp)actionResult.get(WSSecurityEngineResult.TAG_TIMESTAMP);
130         assertNotNull(receivedTimestamp);
131     }
132 
133     @Test
134     public void testInvalidTimestampNoExpires() throws Exception {
135 
136         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
137         WSSecHeader secHeader = new WSSecHeader(doc);
138         secHeader.insertSecurityHeader();
139 
140         WSSecTimestamp timestamp = new WSSecTimestamp(secHeader);
141         timestamp.setTimeToLive(0);
142         Document createdDoc = timestamp.build();
143 
144         if (LOG.isDebugEnabled()) {
145             String outputString =
146                 XMLUtils.prettyDocumentToString(createdDoc);
147             LOG.debug(outputString);
148         }
149 
150         //
151         // Do some processing
152         //
153         WSSecurityEngine secEngine = new WSSecurityEngine();
154         RequestData requestData = new RequestData();
155         requestData.setWssConfig(WSSConfig.getNewInstance());
156         requestData.setRequireTimestampExpires(true);
157         try {
158             secEngine.processSecurityHeader(doc, requestData);
159             fail("Failure expected on no Expires Element");
160         } catch (WSSecurityException ex) {
161             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.SECURITY_ERROR);
162         }
163 
164         requestData.setWssConfig(WSSConfig.getNewInstance());
165         requestData.setRequireTimestampExpires(false);
166         WSHandlerResult wsResult = secEngine.processSecurityHeader(doc, requestData);
167         WSSecurityEngineResult actionResult =
168             wsResult.getActionResults().get(WSConstants.TS).get(0);
169         assertNotNull(actionResult);
170 
171         Timestamp receivedTimestamp =
172             (Timestamp)actionResult.get(WSSecurityEngineResult.TAG_TIMESTAMP);
173         assertNotNull(receivedTimestamp);
174     }
175 
176 
177     /**
178      * This is a test for processing an expired Timestamp.
179      */
180     @Test
181     public void testExpiredTimestamp() throws Exception {
182 
183         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
184         WSSecHeader secHeader = new WSSecHeader(doc);
185         secHeader.insertSecurityHeader();
186 
187         WSSecTimestamp timestamp = new WSSecTimestamp(secHeader);
188         timestamp.setTimeToLive(-1);
189         Document createdDoc = timestamp.build();
190 
191         if (LOG.isDebugEnabled()) {
192             String outputString =
193                 XMLUtils.prettyDocumentToString(createdDoc);
194             LOG.debug(outputString);
195         }
196 
197         try {
198             verify(createdDoc);
199             fail("Expected failure on an expired timestamp");
200         } catch (WSSecurityException ex) {
201             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.MESSAGE_EXPIRED);
202         }
203     }
204 
205 
206     /**
207      * This is a test for processing an "old" Timestamp, i.e. one with a "Created" element that is
208      * out of date
209      */
210     @Test
211     public void testOldTimestamp() throws Exception {
212 
213         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
214         WSSecHeader secHeader = new WSSecHeader(doc);
215         secHeader.insertSecurityHeader();
216 
217         WSSecTimestamp timestamp = new WSSecTimestamp(secHeader);
218         Document createdDoc = timestamp.build();
219 
220         if (LOG.isDebugEnabled()) {
221             String outputString =
222                 XMLUtils.prettyDocumentToString(createdDoc);
223             LOG.debug(outputString);
224         }
225 
226         //
227         // Do some processing
228         //
229         RequestData requestData = new RequestData();
230         requestData.setWssConfig(WSSConfig.getNewInstance());
231         requestData.setTimeStampTTL(-1);
232         try {
233             verify(createdDoc, requestData);
234             fail("The timestamp validation should have failed");
235         } catch (WSSecurityException ex) {
236             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.MESSAGE_EXPIRED);
237         }
238     }
239 
240 
241     /**
242      * This is a test for processing an Timestamp where the "Created" element is in the (near)
243      * future. It should be accepted by default when it is created 30 seconds in the future,
244      * and then rejected once we configure "0 seconds" for future-time-to-live.
245      */
246     @Test
247     public void testNearFutureCreated() throws Exception {
248 
249         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
250         WSSecHeader secHeader = new WSSecHeader(doc);
251         secHeader.insertSecurityHeader();
252 
253         Element timestampElement =
254             doc.createElementNS(
255                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.TIMESTAMP_TOKEN_LN
256             );
257 
258         Element elementCreated =
259             doc.createElementNS(
260                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.CREATED_LN
261             );
262         ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC).plusSeconds(30L);
263         elementCreated.appendChild(doc.createTextNode(DateUtil.getDateTimeFormatter(true).format(now)));
264         timestampElement.appendChild(elementCreated);
265 
266         secHeader.getSecurityHeaderElement().appendChild(timestampElement);
267 
268         if (LOG.isDebugEnabled()) {
269             String outputString =
270                 XMLUtils.prettyDocumentToString(doc);
271             LOG.debug(outputString);
272         }
273         //
274         // Do some processing
275         //
276         RequestData requestData = new RequestData();
277         requestData.setWssConfig(WSSConfig.getNewInstance());
278         requestData.setTimeStampFutureTTL(0);
279         try {
280             verify(doc, requestData);
281             fail("The timestamp validation should have failed");
282         } catch (WSSecurityException ex) {
283             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.MESSAGE_EXPIRED);
284         }
285     }
286 
287     /**
288      * This is a test for processing an Timestamp where the "Created" element is in the future.
289      * A Timestamp that is 120 seconds in the future should be rejected by default.
290      */
291     @Test
292     public void testFutureCreated() throws Exception {
293 
294         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
295         WSSecHeader secHeader = new WSSecHeader(doc);
296         secHeader.insertSecurityHeader();
297 
298         Element timestampElement =
299             doc.createElementNS(
300                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.TIMESTAMP_TOKEN_LN
301             );
302 
303         Element elementCreated =
304             doc.createElementNS(
305                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.CREATED_LN
306             );
307         ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC).plusSeconds(120L);
308         elementCreated.appendChild(doc.createTextNode(DateUtil.getDateTimeFormatter(true).format(now)));
309         timestampElement.appendChild(elementCreated);
310 
311         secHeader.getSecurityHeaderElement().appendChild(timestampElement);
312 
313         if (LOG.isDebugEnabled()) {
314             String outputString =
315                 XMLUtils.prettyDocumentToString(doc);
316             LOG.debug(outputString);
317         }
318         //
319         // Do some processing
320         //
321         try {
322             verify(doc);
323             fail("The timestamp validation should have failed");
324         } catch (WSSecurityException ex) {
325             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.MESSAGE_EXPIRED);
326         }
327     }
328 
329 
330     /**
331      * This is a test for processing an Timestamp where the "Created" element is greater than
332      * the expiration time.
333      */
334     @Test
335     public void testExpiresBeforeCreated() throws Exception {
336 
337         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
338         WSSecHeader secHeader = new WSSecHeader(doc);
339         secHeader.insertSecurityHeader();
340 
341         Element timestampElement =
342             doc.createElementNS(
343                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.TIMESTAMP_TOKEN_LN
344             );
345 
346         Element elementCreated =
347             doc.createElementNS(
348                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.CREATED_LN
349             );
350         ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
351         elementCreated.appendChild(doc.createTextNode(DateUtil.getDateTimeFormatter(true).format(now)));
352         timestampElement.appendChild(elementCreated);
353 
354         Element elementExpires =
355             doc.createElementNS(
356                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.EXPIRES_LN
357             );
358         now = now.minusSeconds(300L);
359         elementExpires.appendChild(doc.createTextNode(DateUtil.getDateTimeFormatter(true).format(now)));
360         timestampElement.appendChild(elementExpires);
361 
362         secHeader.getSecurityHeaderElement().appendChild(timestampElement);
363 
364         if (LOG.isDebugEnabled()) {
365             String outputString =
366                 XMLUtils.prettyDocumentToString(doc);
367             LOG.debug(outputString);
368         }
369         //
370         // Do some processing
371         //
372         try {
373             verify(doc);
374             fail("The timestamp validation should have failed");
375         } catch (WSSecurityException ex) {
376             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.MESSAGE_EXPIRED);
377         }
378     }
379 
380     /**
381      * This is a test for processing multiple Timestamps in the security header
382      */
383     @Test
384     public void testMultipleTimestamps() throws Exception {
385 
386         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
387         WSSecHeader secHeader = new WSSecHeader(doc);
388         secHeader.insertSecurityHeader();
389 
390         WSSecTimestamp timestamp = new WSSecTimestamp(secHeader);
391         timestamp.setTimeToLive(300);
392         Document createdDoc = timestamp.build();
393 
394         timestamp = new WSSecTimestamp(secHeader);
395         timestamp.setTimeToLive(60);
396         createdDoc = timestamp.build();
397 
398         if (LOG.isDebugEnabled()) {
399             String outputString =
400                 XMLUtils.prettyDocumentToString(createdDoc);
401             LOG.debug(outputString);
402         }
403 
404         //
405         // Do some processing
406         //
407         try {
408             verify(createdDoc);
409             fail("Expected failure on multiple timestamps");
410         } catch (WSSecurityException ex) {
411             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
412         }
413 
414         verify(createdDoc, Collections.singletonList(BSPRule.R3227));
415     }
416 
417     /**
418      * This is a test for processing an Timestamp where it contains multiple "Created" elements.
419      * This Timestamp should be rejected.
420      */
421     @Test
422     public void testMultipleCreated() throws Exception {
423 
424         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
425         WSSecHeader secHeader = new WSSecHeader(doc);
426         secHeader.insertSecurityHeader();
427 
428         Element timestampElement =
429             doc.createElementNS(
430                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.TIMESTAMP_TOKEN_LN
431             );
432 
433         Element elementCreated =
434             doc.createElementNS(
435                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.CREATED_LN
436             );
437         ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
438         elementCreated.appendChild(doc.createTextNode(DateUtil.getDateTimeFormatter(true).format(now)));
439         timestampElement.appendChild(elementCreated);
440         timestampElement.appendChild(elementCreated.cloneNode(true));
441 
442         secHeader.getSecurityHeaderElement().appendChild(timestampElement);
443 
444         if (LOG.isDebugEnabled()) {
445             String outputString =
446                 XMLUtils.prettyDocumentToString(doc);
447             LOG.debug(outputString);
448         }
449         //
450         // Do some processing
451         //
452         try {
453             verify(doc);
454             fail("The timestamp validation should have failed on multiple Created elements");
455         } catch (WSSecurityException ex) {
456             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
457         }
458 
459         verify(doc, Collections.singletonList(BSPRule.R3203));
460     }
461 
462     /**
463      * This is a test for processing an Timestamp where it contains no "Created" element.
464      * This Timestamp should be rejected.
465      */
466     @Test
467     public void testNoCreated() throws Exception {
468 
469         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
470         WSSecHeader secHeader = new WSSecHeader(doc);
471         secHeader.insertSecurityHeader();
472 
473         Element timestampElement =
474             doc.createElementNS(
475                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.TIMESTAMP_TOKEN_LN
476             );
477 
478         Element elementExpires =
479             doc.createElementNS(
480                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.EXPIRES_LN
481             );
482         ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC).plusSeconds(300L);
483         elementExpires.appendChild(doc.createTextNode(DateUtil.getDateTimeFormatter(true).format(now)));
484         timestampElement.appendChild(elementExpires);
485 
486         secHeader.getSecurityHeaderElement().appendChild(timestampElement);
487 
488         if (LOG.isDebugEnabled()) {
489             String outputString =
490                 XMLUtils.prettyDocumentToString(doc);
491             LOG.debug(outputString);
492         }
493         //
494         // Do some processing
495         //
496         try {
497             verify(doc);
498             fail("The timestamp validation should have failed on no Created element");
499         } catch (WSSecurityException ex) {
500             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
501         }
502 
503         List<BSPRule> rules = new ArrayList<>();
504         rules.add(BSPRule.R3203);
505         rules.add(BSPRule.R3221);
506         verify(doc, rules);
507     }
508 
509     /**
510      * This is a test for processing an Timestamp where it contains multiple "Expires" elements.
511      * This Timestamp should be rejected.
512      */
513     @Test
514     public void testMultipleExpires() throws Exception {
515 
516         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
517         WSSecHeader secHeader = new WSSecHeader(doc);
518         secHeader.insertSecurityHeader();
519 
520         Element timestampElement =
521             doc.createElementNS(
522                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.TIMESTAMP_TOKEN_LN
523             );
524 
525         Element elementCreated =
526             doc.createElementNS(
527                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.CREATED_LN
528             );
529         ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
530         elementCreated.appendChild(doc.createTextNode(DateUtil.getDateTimeFormatter(true).format(now)));
531         timestampElement.appendChild(elementCreated);
532 
533         Element elementExpires =
534             doc.createElementNS(
535                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.EXPIRES_LN
536             );
537         now = now.plusSeconds(300L);
538         elementExpires.appendChild(doc.createTextNode(DateUtil.getDateTimeFormatter(true).format(now)));
539         timestampElement.appendChild(elementExpires);
540         timestampElement.appendChild(elementExpires.cloneNode(true));
541 
542         secHeader.getSecurityHeaderElement().appendChild(timestampElement);
543 
544         if (LOG.isDebugEnabled()) {
545             String outputString =
546                 XMLUtils.prettyDocumentToString(doc);
547             LOG.debug(outputString);
548         }
549         //
550         // Do some processing
551         //
552         try {
553             verify(doc);
554             fail("The timestamp validation should have failed on multiple Expires elements");
555         } catch (WSSecurityException ex) {
556             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
557         }
558 
559         verify(doc, Collections.singletonList(BSPRule.R3224));
560     }
561 
562     /**
563      * This is a test for processing an Timestamp where it contains an "Expires" element before
564      * the Created element. This Timestamp should be rejected as per the BSP spec.
565      */
566     @Test
567     public void testExpiresInFrontOfCreated() throws Exception {
568 
569         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
570         WSSecHeader secHeader = new WSSecHeader(doc);
571         secHeader.insertSecurityHeader();
572 
573         Element timestampElement =
574             doc.createElementNS(
575                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.TIMESTAMP_TOKEN_LN
576             );
577 
578         Element elementCreated =
579             doc.createElementNS(
580                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.EXPIRES_LN
581             );
582         ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC).plusSeconds(300L);
583         elementCreated.appendChild(doc.createTextNode(DateUtil.getDateTimeFormatter(true).format(now)));
584         timestampElement.appendChild(elementCreated);
585 
586         Element elementExpires =
587             doc.createElementNS(
588                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.CREATED_LN
589             );
590         now = ZonedDateTime.now(ZoneOffset.UTC);
591         elementExpires.appendChild(doc.createTextNode(DateUtil.getDateTimeFormatter(true).format(now)));
592         timestampElement.appendChild(elementExpires);
593 
594         secHeader.getSecurityHeaderElement().appendChild(timestampElement);
595 
596         if (LOG.isDebugEnabled()) {
597             String outputString =
598                 XMLUtils.prettyDocumentToString(doc);
599             LOG.debug(outputString);
600         }
601         //
602         // Do some processing
603         //
604         try {
605             verify(doc);
606             fail("The timestamp validation should have failed");
607         } catch (WSSecurityException ex) {
608             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
609         }
610 
611         verify(doc, Collections.singletonList(BSPRule.R3221));
612     }
613 
614 
615     /**
616      * This is a test for processing an Timestamp where it contains a Created element with
617      * seconds > 60. This should be rejected as per the BSP spec.
618      */
619     @Test
620     public void testCreatedSeconds() throws Exception {
621 
622         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
623         WSSecHeader secHeader = new WSSecHeader(doc);
624         secHeader.insertSecurityHeader();
625 
626         Element timestampElement =
627             doc.createElementNS(
628                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.TIMESTAMP_TOKEN_LN
629             );
630 
631         Element elementCreated =
632             doc.createElementNS(
633                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.CREATED_LN
634             );
635         elementCreated.appendChild(doc.createTextNode("2011-02-08T13:13:84.535Z"));
636         timestampElement.appendChild(elementCreated);
637 
638         secHeader.getSecurityHeaderElement().appendChild(timestampElement);
639 
640         if (LOG.isDebugEnabled()) {
641             String outputString =
642                 XMLUtils.prettyDocumentToString(doc);
643             LOG.debug(outputString);
644         }
645         //
646         // Do some processing - disable the validator to make sure that the Timestamp processor
647         // is rejecting the Timestamp
648         //
649         WSSConfig wssConfig = WSSConfig.getNewInstance();
650         wssConfig.setValidator(WSConstants.TIMESTAMP, new NoOpValidator());
651         try {
652             verify(doc, wssConfig, new ArrayList<>());
653             fail("The timestamp validation should have failed");
654         } catch (WSSecurityException ex) {
655             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
656         }
657     }
658 
659 
660     /**
661      * This is a test for processing an Timestamp where it contains a Created element with
662      * a ValueType. This should be rejected as per the BSP spec.
663      */
664     @Test
665     public void testCreatedValueType() throws Exception {
666 
667         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
668         WSSecHeader secHeader = new WSSecHeader(doc);
669         secHeader.insertSecurityHeader();
670 
671         Element timestampElement =
672             doc.createElementNS(
673                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.TIMESTAMP_TOKEN_LN
674             );
675 
676         Element elementCreated =
677             doc.createElementNS(
678                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.CREATED_LN
679             );
680         ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
681         elementCreated.appendChild(doc.createTextNode(DateUtil.getDateTimeFormatter(true).format(now)));
682         elementCreated.setAttributeNS(null, "ValueType", WSConstants.WSS_SAML_KI_VALUE_TYPE);
683         timestampElement.appendChild(elementCreated);
684 
685         secHeader.getSecurityHeaderElement().appendChild(timestampElement);
686 
687         if (LOG.isDebugEnabled()) {
688             String outputString =
689                 XMLUtils.prettyDocumentToString(doc);
690             LOG.debug(outputString);
691         }
692         //
693         // Do some processing
694         //
695         try {
696             verify(doc);
697             fail("The timestamp validation should have failed");
698         } catch (WSSecurityException ex) {
699             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
700         }
701 
702         // Now it should pass...
703         WSSConfig wssConfig = WSSConfig.getNewInstance();
704         wssConfig.setValidator(WSConstants.TIMESTAMP, new NoOpValidator());
705         verify(doc, wssConfig, Collections.singletonList(BSPRule.R3225));
706     }
707 
708 
709 
710     /**
711      * This is a test for processing an Timestamp where it contains a CustomElement. This should
712      * be rejected as per the BSP spec.
713      */
714     @Test
715     public void testCustomElement() throws Exception {
716 
717         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
718         WSSecHeader secHeader = new WSSecHeader(doc);
719         secHeader.insertSecurityHeader();
720 
721         Element timestampElement =
722             doc.createElementNS(
723                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.TIMESTAMP_TOKEN_LN
724             );
725 
726         Element elementCreated =
727             doc.createElementNS(
728                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.CREATED_LN
729             );
730         ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
731         elementCreated.appendChild(doc.createTextNode(DateUtil.getDateTimeFormatter(true).format(now)));
732         timestampElement.appendChild(elementCreated);
733 
734         Element elementExpires =
735             doc.createElementNS(
736                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.EXPIRES_LN
737             );
738         now = now.plusSeconds(300L);
739         elementExpires.appendChild(doc.createTextNode(DateUtil.getDateTimeFormatter(true).format(now)));
740         timestampElement.appendChild(elementExpires);
741 
742         Element elementCustom =
743             doc.createElementNS(
744                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + "Custom"
745             );
746         timestampElement.appendChild(elementCustom);
747 
748         secHeader.getSecurityHeaderElement().appendChild(timestampElement);
749 
750         if (LOG.isDebugEnabled()) {
751             String outputString =
752                 XMLUtils.prettyDocumentToString(doc);
753             LOG.debug(outputString);
754         }
755         //
756         // Do some processing
757         //
758         try {
759             verify(doc);
760             fail("The timestamp validation should have failed");
761         } catch (WSSecurityException ex) {
762             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
763         }
764 
765         // Now it should pass...
766         verify(doc, Collections.singletonList(BSPRule.R3222));
767     }
768 
769     /**
770      * This is a test to create a "Spoofed" Timestamp (see WSS-441)
771      */
772     @Test
773     public void testSpoofedTimestamp() throws Exception {
774 
775         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
776         WSSecHeader secHeader = new WSSecHeader(doc);
777         secHeader.insertSecurityHeader();
778 
779         WSSecTimestamp timestamp = new WSSecTimestamp(secHeader);
780         timestamp.setTimeToLive(300);
781 
782         WSTimeSource spoofedTimeSource = new WSTimeSource() {
783 
784             public Instant now() {
785                 return Instant.now().minusSeconds(500L);
786             }
787 
788         };
789         timestamp.setWsTimeSource(spoofedTimeSource);
790 
791         Document createdDoc = timestamp.build();
792 
793         if (LOG.isDebugEnabled()) {
794             String outputString =
795                 XMLUtils.prettyDocumentToString(createdDoc);
796             LOG.debug(outputString);
797         }
798 
799         //
800         // Do some processing
801         //
802         try {
803             verify(createdDoc);
804             fail("Expected failure on an expired timestamp");
805         } catch (WSSecurityException ex) {
806             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.MESSAGE_EXPIRED);
807         }
808     }
809 
810     @Test
811     public void testTimestampNoMilliseconds() throws Exception {
812 
813         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
814         WSSecHeader secHeader = new WSSecHeader(doc);
815         secHeader.insertSecurityHeader();
816 
817         WSSecTimestamp timestamp = new WSSecTimestamp(secHeader);
818         timestamp.setPrecisionInMilliSeconds(false);
819         timestamp.setTimeToLive(300);
820         Document createdDoc = timestamp.build();
821 
822         if (LOG.isDebugEnabled()) {
823             String outputString =
824                 XMLUtils.prettyDocumentToString(createdDoc);
825             LOG.debug(outputString);
826         }
827 
828         //
829         // Do some processing
830         //
831         WSHandlerResult wsResult = verify(createdDoc);
832         WSSecurityEngineResult actionResult =
833             wsResult.getActionResults().get(WSConstants.TS).get(0);
834         assertNotNull(actionResult);
835     }
836 
837     @Test
838     public void testThaiLocaleVerification() throws Exception {
839 
840         Locale defaultLocale = Locale.getDefault();
841         try {
842             Locale.setDefault(new Locale("th", "TH"));
843 
844             Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
845             WSSecHeader secHeader = new WSSecHeader(doc);
846             secHeader.insertSecurityHeader();
847 
848             WSSecTimestamp timestamp = new WSSecTimestamp(secHeader);
849             timestamp.setTimeToLive(300);
850             Document createdDoc = timestamp.build();
851 
852             //
853             // Do some processing
854             //
855             WSHandlerResult wsResult = verify(createdDoc);
856             WSSecurityEngineResult actionResult =
857                 wsResult.getActionResults().get(WSConstants.TS).get(0);
858             assertNotNull(actionResult);
859         } finally {
860             Locale.setDefault(defaultLocale);
861         }
862     }
863 
864     /**
865      * Verifies the soap envelope
866      */
867     private WSHandlerResult verify(
868         Document doc
869     ) throws Exception {
870         WSSecurityEngine secEngine = new WSSecurityEngine();
871         RequestData requestData = new RequestData();
872         requestData.setWssConfig(WSSConfig.getNewInstance());
873         return secEngine.processSecurityHeader(doc, requestData);
874     }
875 
876     private WSHandlerResult verify(
877         Document doc, RequestData requestData
878     ) throws Exception {
879         WSSecurityEngine secEngine = new WSSecurityEngine();
880         return secEngine.processSecurityHeader(doc, requestData);
881     }
882 
883     /**
884      * Verifies the soap envelope
885      */
886     private WSHandlerResult verify(
887         Document doc, List<BSPRule> ignoredRules
888     ) throws Exception {
889         WSSecurityEngine secEngine = new WSSecurityEngine();
890         RequestData requestData = new RequestData();
891         requestData.setIgnoredBSPRules(ignoredRules);
892         return secEngine.processSecurityHeader(doc, requestData);
893     }
894 
895     /**
896      * Verifies the soap envelope
897      */
898     private WSHandlerResult verify(
899         Document doc, WSSConfig wssConfig, List<BSPRule> ignoredRules
900     ) throws Exception {
901         WSSecurityEngine secEngine = new WSSecurityEngine();
902         RequestData requestData = new RequestData();
903         requestData.setWssConfig(wssConfig);
904         requestData.setIgnoredBSPRules(ignoredRules);
905         return secEngine.processSecurityHeader(doc, requestData);
906     }
907 
908 
909 }