1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.wss4j.dom.message;
21
22 import java.nio.file.Path;
23 import java.util.List;
24
25 import javax.security.auth.callback.CallbackHandler;
26
27 import org.apache.wss4j.common.cache.EHCacheReplayCache;
28 import org.apache.wss4j.common.util.SOAPUtil;
29 import org.apache.wss4j.dom.WSConstants;
30 import org.apache.wss4j.dom.common.KeystoreCallbackHandler;
31 import org.apache.wss4j.dom.common.SAML2CallbackHandler;
32
33 import org.apache.wss4j.dom.common.UsernamePasswordCallbackHandler;
34 import org.apache.wss4j.dom.engine.WSSConfig;
35 import org.apache.wss4j.dom.engine.WSSecurityEngine;
36 import org.apache.wss4j.common.WSEncryptionPart;
37 import org.apache.wss4j.common.cache.MemoryReplayCache;
38 import org.apache.wss4j.common.cache.ReplayCache;
39 import org.apache.wss4j.common.crypto.Crypto;
40 import org.apache.wss4j.common.crypto.CryptoFactory;
41 import org.apache.wss4j.common.ext.WSSecurityException;
42 import org.apache.wss4j.common.saml.SAMLCallback;
43 import org.apache.wss4j.common.saml.SAMLUtil;
44 import org.apache.wss4j.common.saml.SamlAssertionWrapper;
45 import org.apache.wss4j.common.saml.bean.ConditionsBean;
46 import org.apache.wss4j.common.saml.builder.SAML2Constants;
47 import org.apache.wss4j.common.util.XMLUtils;
48 import org.apache.wss4j.dom.handler.RequestData;
49 import org.apache.wss4j.dom.handler.WSHandlerResult;
50 import org.apache.wss4j.dom.util.WSSecurityUtil;
51 import org.apache.wss4j.dom.validate.SamlAssertionValidator;
52
53 import org.junit.jupiter.api.Test;
54 import org.junit.jupiter.api.io.TempDir;
55 import org.w3c.dom.Document;
56 import org.w3c.dom.Element;
57
58 import static org.junit.jupiter.api.Assertions.assertTrue;
59 import static org.junit.jupiter.api.Assertions.fail;
60
61
62
63
64 public class ReplayTest {
65 private static final org.slf4j.Logger LOG =
66 org.slf4j.LoggerFactory.getLogger(ReplayTest.class);
67
68 private CallbackHandler callbackHandler = new KeystoreCallbackHandler();
69 private Crypto crypto;
70
71 @TempDir
72 Path tempDir;
73
74 public ReplayTest() throws Exception {
75 crypto = CryptoFactory.getInstance();
76 }
77
78 private ReplayCache createCache(String key) throws WSSecurityException {
79 return new EHCacheReplayCache(key, tempDir);
80 }
81
82 @Test
83 public void testReplayedTimestamp() throws Exception {
84
85 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
86 WSSecHeader secHeader = new WSSecHeader(doc);
87 secHeader.insertSecurityHeader();
88
89 WSSecTimestamp timestamp = new WSSecTimestamp(secHeader);
90 timestamp.setTimeToLive(300);
91 Document createdDoc = timestamp.build();
92
93 WSSecSignature builder = new WSSecSignature(secHeader);
94 builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
95 builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
96
97 WSEncryptionPart encP =
98 new WSEncryptionPart(
99 "Timestamp", WSConstants.WSU_NS, "");
100 builder.getParts().add(encP);
101
102 builder.prepare(crypto);
103
104 List<javax.xml.crypto.dsig.Reference> referenceList =
105 builder.addReferencesToSign(builder.getParts());
106
107 builder.computeSignature(referenceList, false, null);
108
109 if (LOG.isDebugEnabled()) {
110 String outputString =
111 XMLUtils.prettyDocumentToString(createdDoc);
112 LOG.debug(outputString);
113 }
114
115 WSSConfig wssConfig = WSSConfig.getNewInstance();
116 RequestData data = new RequestData();
117 data.setWssConfig(wssConfig);
118 data.setCallbackHandler(callbackHandler);
119 data.setTimestampReplayCache(new MemoryReplayCache());
120
121
122 verify(createdDoc, wssConfig, data);
123
124
125 try {
126 verify(createdDoc, wssConfig, data);
127 fail("Expected failure on a replay attack");
128 } catch (WSSecurityException ex) {
129 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
130 }
131 }
132
133 @Test
134 public void testEhCacheReplayedTimestamp() 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(300);
142 Document createdDoc = timestamp.build();
143
144 WSSecSignature builder = new WSSecSignature(secHeader);
145 builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
146 builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
147
148 WSEncryptionPart encP =
149 new WSEncryptionPart(
150 "Timestamp", WSConstants.WSU_NS, "");
151 builder.getParts().add(encP);
152
153 builder.prepare(crypto);
154
155 List<javax.xml.crypto.dsig.Reference> referenceList =
156 builder.addReferencesToSign(builder.getParts());
157
158 builder.computeSignature(referenceList, false, null);
159
160 if (LOG.isDebugEnabled()) {
161 String outputString =
162 XMLUtils.prettyDocumentToString(createdDoc);
163 LOG.debug(outputString);
164 }
165
166 WSSConfig wssConfig = WSSConfig.getNewInstance();
167 RequestData data = new RequestData();
168 data.setWssConfig(wssConfig);
169 data.setCallbackHandler(callbackHandler);
170 ReplayCache replayCache = createCache("wss4j.timestamp.cache-");
171 data.setTimestampReplayCache(replayCache);
172
173
174 verify(createdDoc, wssConfig, data);
175
176
177 try {
178 verify(createdDoc, wssConfig, data);
179 fail("Expected failure on a replay attack");
180 } catch (WSSecurityException ex) {
181 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
182 }
183
184 replayCache.close();
185 }
186
187 @Test
188 public void testReplayedTimestampBelowSignature() throws Exception {
189
190 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
191 WSSecHeader secHeader = new WSSecHeader(doc);
192 secHeader.insertSecurityHeader();
193
194 WSSecTimestamp timestamp = new WSSecTimestamp(secHeader);
195 timestamp.setTimeToLive(300);
196 Document createdDoc = timestamp.build();
197
198 WSSecSignature builder = new WSSecSignature(secHeader);
199 builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
200 builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
201
202 WSEncryptionPart encP =
203 new WSEncryptionPart(
204 "Timestamp", WSConstants.WSU_NS, "");
205 builder.getParts().add(encP);
206
207 builder.build(crypto);
208
209 if (LOG.isDebugEnabled()) {
210 String outputString =
211 XMLUtils.prettyDocumentToString(createdDoc);
212 LOG.debug(outputString);
213 }
214
215 WSSConfig wssConfig = WSSConfig.getNewInstance();
216 RequestData data = new RequestData();
217 data.setWssConfig(wssConfig);
218 data.setCallbackHandler(callbackHandler);
219 data.setTimestampReplayCache(new MemoryReplayCache());
220
221
222 verify(createdDoc, wssConfig, data);
223
224
225 try {
226 verify(createdDoc, wssConfig, data);
227 fail("Expected failure on a replay attack");
228 } catch (WSSecurityException ex) {
229 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
230 }
231 }
232
233 @Test
234 public void testEhCacheReplayedTimestampBelowSignature() throws Exception {
235
236 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
237 WSSecHeader secHeader = new WSSecHeader(doc);
238 secHeader.insertSecurityHeader();
239
240 WSSecTimestamp timestamp = new WSSecTimestamp(secHeader);
241 timestamp.setTimeToLive(300);
242 Document createdDoc = timestamp.build();
243
244 WSSecSignature builder = new WSSecSignature(secHeader);
245 builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
246 builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
247
248 WSEncryptionPart encP =
249 new WSEncryptionPart(
250 "Timestamp", WSConstants.WSU_NS, "");
251 builder.getParts().add(encP);
252
253 builder.build(crypto);
254
255 if (LOG.isDebugEnabled()) {
256 String outputString =
257 XMLUtils.prettyDocumentToString(createdDoc);
258 LOG.debug(outputString);
259 }
260
261 WSSConfig wssConfig = WSSConfig.getNewInstance();
262 RequestData data = new RequestData();
263 data.setWssConfig(wssConfig);
264 data.setCallbackHandler(callbackHandler);
265 ReplayCache replayCache = createCache("wss4j.timestamp.cache-");
266 data.setTimestampReplayCache(replayCache);
267
268
269 verify(createdDoc, wssConfig, data);
270
271
272 try {
273 verify(createdDoc, wssConfig, data);
274 fail("Expected failure on a replay attack");
275 } catch (WSSecurityException ex) {
276 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
277 }
278
279 replayCache.close();
280 }
281
282 @Test
283 public void testReplayedTimestampNoExpires() throws Exception {
284
285 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
286 WSSecHeader secHeader = new WSSecHeader(doc);
287 secHeader.insertSecurityHeader();
288
289 WSSecTimestamp timestamp = new WSSecTimestamp(secHeader);
290 timestamp.setTimeToLive(0);
291 Document createdDoc = timestamp.build();
292
293 WSSecSignature builder = new WSSecSignature(secHeader);
294 builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
295 builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
296
297 WSEncryptionPart encP =
298 new WSEncryptionPart(
299 "Timestamp", WSConstants.WSU_NS, "");
300 builder.getParts().add(encP);
301
302 builder.prepare(crypto);
303
304 List<javax.xml.crypto.dsig.Reference> referenceList =
305 builder.addReferencesToSign(builder.getParts());
306
307 builder.computeSignature(referenceList, false, null);
308
309 if (LOG.isDebugEnabled()) {
310 String outputString =
311 XMLUtils.prettyDocumentToString(createdDoc);
312 LOG.debug(outputString);
313 }
314
315 WSSConfig wssConfig = WSSConfig.getNewInstance();
316 RequestData data = new RequestData();
317 data.setWssConfig(wssConfig);
318 data.setCallbackHandler(callbackHandler);
319 data.setTimestampReplayCache(new MemoryReplayCache());
320
321
322 verify(createdDoc, wssConfig, data);
323
324
325 try {
326 verify(createdDoc, wssConfig, data);
327 fail("Expected failure on a replay attack");
328 } catch (WSSecurityException ex) {
329 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
330 }
331 }
332
333 @Test
334 public void testEhCacheReplayedTimestampNoExpires() throws Exception {
335
336 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
337 WSSecHeader secHeader = new WSSecHeader(doc);
338 secHeader.insertSecurityHeader();
339
340 WSSecTimestamp timestamp = new WSSecTimestamp(secHeader);
341 timestamp.setTimeToLive(0);
342 Document createdDoc = timestamp.build();
343
344 WSSecSignature builder = new WSSecSignature(secHeader);
345 builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
346 builder.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
347
348 WSEncryptionPart encP =
349 new WSEncryptionPart(
350 "Timestamp", WSConstants.WSU_NS, "");
351 builder.getParts().add(encP);
352
353 builder.prepare(crypto);
354
355 List<javax.xml.crypto.dsig.Reference> referenceList =
356 builder.addReferencesToSign(builder.getParts());
357
358 builder.computeSignature(referenceList, false, null);
359
360 if (LOG.isDebugEnabled()) {
361 String outputString =
362 XMLUtils.prettyDocumentToString(createdDoc);
363 LOG.debug(outputString);
364 }
365
366 WSSConfig wssConfig = WSSConfig.getNewInstance();
367 RequestData data = new RequestData();
368 data.setWssConfig(wssConfig);
369 data.setCallbackHandler(callbackHandler);
370 ReplayCache replayCache = createCache("wss4j.timestamp.cache-");
371 data.setTimestampReplayCache(replayCache);
372
373
374 verify(createdDoc, wssConfig, data);
375
376
377 try {
378 verify(createdDoc, wssConfig, data);
379 fail("Expected failure on a replay attack");
380 } catch (WSSecurityException ex) {
381 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
382 }
383
384 replayCache.close();
385 }
386
387 @Test
388 public void testReplayedUsernameToken() throws Exception {
389 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
390 WSSecHeader secHeader = new WSSecHeader(doc);
391 secHeader.insertSecurityHeader();
392
393 WSSecUsernameToken builder = new WSSecUsernameToken(secHeader);
394 builder.setUserInfo("wernerd", "verySecret");
395
396 Document signedDoc = builder.build();
397
398 if (LOG.isDebugEnabled()) {
399 String outputString =
400 XMLUtils.prettyDocumentToString(signedDoc);
401 LOG.debug(outputString);
402 }
403
404 WSSConfig wssConfig = WSSConfig.getNewInstance();
405 RequestData data = new RequestData();
406 data.setCallbackHandler(new UsernamePasswordCallbackHandler());
407 data.setWssConfig(wssConfig);
408 data.setNonceReplayCache(new MemoryReplayCache());
409
410
411 verify(signedDoc, wssConfig, data);
412
413
414 try {
415 verify(signedDoc, wssConfig, data);
416 fail("Expected failure on a replay attack");
417 } catch (WSSecurityException ex) {
418 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
419 }
420 }
421
422 @Test
423 public void testEhCacheReplayedUsernameToken() throws Exception {
424 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
425 WSSecHeader secHeader = new WSSecHeader(doc);
426 secHeader.insertSecurityHeader();
427
428 WSSecUsernameToken builder = new WSSecUsernameToken(secHeader);
429 builder.setUserInfo("wernerd", "verySecret");
430
431 Document signedDoc = builder.build();
432
433 if (LOG.isDebugEnabled()) {
434 String outputString =
435 XMLUtils.prettyDocumentToString(signedDoc);
436 LOG.debug(outputString);
437 }
438
439 WSSConfig wssConfig = WSSConfig.getNewInstance();
440 RequestData data = new RequestData();
441 data.setCallbackHandler(new UsernamePasswordCallbackHandler());
442 data.setWssConfig(wssConfig);
443 ReplayCache replayCache = createCache("wss4j.nonce.cache-");
444 data.setNonceReplayCache(replayCache);
445
446
447 verify(signedDoc, wssConfig, data);
448
449
450 try {
451 verify(signedDoc, wssConfig, data);
452 fail("Expected failure on a replay attack");
453 } catch (WSSecurityException ex) {
454 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
455 }
456
457 replayCache.close();
458 }
459
460
461
462
463
464
465
466 @Test
467 public void testEhCacheReplayedSAML2() throws Exception {
468 SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
469 callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
470 callbackHandler.setIssuer("www.example.com");
471 callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER);
472
473 ConditionsBean conditions = new ConditionsBean();
474 conditions.setTokenPeriodMinutes(5);
475
476 callbackHandler.setConditions(conditions);
477
478 SAMLCallback samlCallback = new SAMLCallback();
479 SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
480 SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
481
482 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
483 WSSecHeader secHeader = new WSSecHeader(doc);
484 secHeader.insertSecurityHeader();
485
486 WSSecSAMLToken wsSign = new WSSecSAMLToken(secHeader);
487
488 Document unsignedDoc = wsSign.build(samlAssertion);
489
490 if (LOG.isDebugEnabled()) {
491 String outputString = XMLUtils.prettyDocumentToString(unsignedDoc);
492 LOG.debug(outputString);
493 }
494
495 WSSConfig wssConfig = WSSConfig.getNewInstance();
496 SamlAssertionValidator assertionValidator = new SamlAssertionValidator();
497 assertionValidator.setRequireBearerSignature(false);
498 wssConfig.setValidator(WSConstants.SAML_TOKEN, assertionValidator);
499 wssConfig.setValidator(WSConstants.SAML2_TOKEN, assertionValidator);
500
501 RequestData data = new RequestData();
502 data.setWssConfig(wssConfig);
503 data.setCallbackHandler(callbackHandler);
504 ReplayCache replayCache = createCache("wss4j.saml.one.time.use.cache-");
505 data.setSamlOneTimeUseReplayCache(replayCache);
506
507
508 verify(unsignedDoc, wssConfig, data);
509
510
511 verify(unsignedDoc, wssConfig, data);
512
513 replayCache.close();
514 }
515
516
517
518
519
520 @Test
521 public void testEhCacheReplayedSAML2OneTimeUse() throws Exception {
522 SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
523 callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
524 callbackHandler.setIssuer("www.example.com");
525 callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER);
526
527 ConditionsBean conditions = new ConditionsBean();
528 conditions.setTokenPeriodMinutes(5);
529 conditions.setOneTimeUse(true);
530
531 callbackHandler.setConditions(conditions);
532
533 SAMLCallback samlCallback = new SAMLCallback();
534 SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
535 SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
536
537 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
538 WSSecHeader secHeader = new WSSecHeader(doc);
539 secHeader.insertSecurityHeader();
540
541 WSSecSAMLToken wsSign = new WSSecSAMLToken(secHeader);
542
543 Document unsignedDoc = wsSign.build(samlAssertion);
544
545 String outputString =
546 XMLUtils.prettyDocumentToString(unsignedDoc);
547 assertTrue(outputString.contains("OneTimeUse"));
548 if (LOG.isDebugEnabled()) {
549 LOG.debug(outputString);
550 }
551
552 WSSConfig wssConfig = WSSConfig.getNewInstance();
553 SamlAssertionValidator assertionValidator = new SamlAssertionValidator();
554 assertionValidator.setRequireBearerSignature(false);
555 wssConfig.setValidator(WSConstants.SAML_TOKEN, assertionValidator);
556 wssConfig.setValidator(WSConstants.SAML2_TOKEN, assertionValidator);
557
558 RequestData data = new RequestData();
559 data.setWssConfig(wssConfig);
560 data.setCallbackHandler(callbackHandler);
561 ReplayCache replayCache = createCache("wss4j.saml.one.time.use.cache-");
562 data.setSamlOneTimeUseReplayCache(replayCache);
563
564
565 verify(unsignedDoc, wssConfig, data);
566
567
568 try {
569 verify(unsignedDoc, wssConfig, data);
570 fail("Expected failure on a replay attack");
571 } catch (WSSecurityException ex) {
572 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
573 }
574
575 replayCache.close();
576 }
577
578
579
580
581
582
583
584
585 private WSHandlerResult verify(
586 Document doc, WSSConfig wssConfig, RequestData data
587 ) throws Exception {
588 WSSecurityEngine secEngine = new WSSecurityEngine();
589 secEngine.setWssConfig(wssConfig);
590 Element elem = WSSecurityUtil.getSecurityHeader(doc, null);
591 data.setSigVerCrypto(crypto);
592 return secEngine.processSecurityHeader(elem, data);
593 }
594
595
596 }