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.io.IOException;
23 import java.nio.charset.StandardCharsets;
24 import java.security.MessageDigest;
25 import java.time.Instant;
26 import java.time.ZoneOffset;
27 import java.time.ZonedDateTime;
28 import java.util.Collections;
29
30 import javax.security.auth.callback.Callback;
31 import javax.security.auth.callback.CallbackHandler;
32 import javax.security.auth.callback.UnsupportedCallbackException;
33
34 import org.apache.wss4j.common.bsp.BSPEnforcer;
35 import org.apache.wss4j.common.bsp.BSPRule;
36 import org.apache.wss4j.common.ext.WSPasswordCallback;
37 import org.apache.wss4j.common.ext.WSSecurityException;
38 import org.apache.wss4j.common.util.*;
39 import org.apache.wss4j.dom.WSConstants;
40 import org.apache.wss4j.dom.common.CustomHandler;
41 import org.apache.wss4j.dom.common.EncodedPasswordCallbackHandler;
42
43 import org.apache.wss4j.dom.common.UsernamePasswordCallbackHandler;
44 import org.apache.wss4j.dom.engine.WSSecurityEngine;
45 import org.apache.wss4j.dom.engine.WSSecurityEngineResult;
46 import org.apache.wss4j.dom.handler.HandlerAction;
47 import org.apache.wss4j.dom.handler.RequestData;
48 import org.apache.wss4j.dom.handler.WSHandlerConstants;
49 import org.apache.wss4j.dom.handler.WSHandlerResult;
50 import org.apache.wss4j.dom.message.token.UsernameToken;
51
52 import org.junit.jupiter.api.Test;
53 import org.w3c.dom.Document;
54 import org.w3c.dom.Element;
55 import org.w3c.dom.Node;
56 import org.w3c.dom.NodeList;
57
58 import static org.junit.jupiter.api.Assertions.assertEquals;
59 import static org.junit.jupiter.api.Assertions.assertFalse;
60 import static org.junit.jupiter.api.Assertions.assertNotNull;
61 import static org.junit.jupiter.api.Assertions.assertTrue;
62 import static org.junit.jupiter.api.Assertions.fail;
63
64
65
66
67 public class UsernameTokenTest implements CallbackHandler {
68 private static final org.slf4j.Logger LOG =
69 org.slf4j.LoggerFactory.getLogger(UsernameTokenTest.class);
70 private static final String SOAPUTMSG =
71 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
72 + "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" "
73 + "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" "
74 + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
75 + "<SOAP-ENV:Header>"
76 + "<wsse:Security SOAP-ENV:mustUnderstand=\"1\" "
77 + "xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">"
78 + "<wsse:UsernameToken wsu:Id=\"UsernameToken-29477163\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">"
79 + "<wsse:Username>wernerd</wsse:Username>"
80 + "<wsse:Password>verySecret</wsse:Password>"
81 + "</wsse:UsernameToken></wsse:Security></SOAP-ENV:Header>"
82 + "<SOAP-ENV:Body>"
83 + "<add xmlns=\"http://ws.apache.org/counter/counter_port_type\">"
84 + "<value xmlns=\"\">15</value>" + "</add>"
85 + "</SOAP-ENV:Body>\r\n \r\n" + "</SOAP-ENV:Envelope>";
86 private static final String SOAPUTNOUSERMSG =
87 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
88 + "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" "
89 + "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" "
90 + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
91 + "<SOAP-ENV:Header>"
92 + "<wsse:Security SOAP-ENV:mustUnderstand=\"1\" "
93 + "xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">"
94 + "<wsse:UsernameToken wsu:Id=\"UsernameToken-29477163\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">"
95 + "<wsse:Username></wsse:Username>"
96 + "<wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText\"></wsse:Password>"
97 + "</wsse:UsernameToken></wsse:Security></SOAP-ENV:Header>"
98 + "<SOAP-ENV:Body>"
99 + "<add xmlns=\"http://ws.apache.org/counter/counter_port_type\">"
100 + "<value xmlns=\"\">15</value>" + "</add>"
101 + "</SOAP-ENV:Body>\r\n \r\n" + "</SOAP-ENV:Envelope>";
102 private static final String EMPTY_PASSWORD_MSG =
103 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
104 + "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" "
105 + "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" "
106 + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
107 + "<SOAP-ENV:Header>"
108 + "<wsse:Security SOAP-ENV:mustUnderstand=\"1\" "
109 + "xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">"
110 + "<wsse:UsernameToken wsu:Id=\"UsernameToken-1\" "
111 + "xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" "
112 + "xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">"
113 + "<wsse:Username>emptyuser</wsse:Username>"
114 + "<wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText\"/>"
115 + "</wsse:UsernameToken></wsse:Security></SOAP-ENV:Header>"
116 + "<SOAP-ENV:Body>"
117 + "<add xmlns=\"http://ws.apache.org/counter/counter_port_type\">"
118 + "<value xmlns=\"\">15</value>" + "</add>"
119 + "</SOAP-ENV:Body>\r\n \r\n" + "</SOAP-ENV:Envelope>";
120
121 private CallbackHandler callbackHandler = new UsernamePasswordCallbackHandler();
122
123
124
125
126 @Test
127 public void testUsernameTokenDigest() throws Exception {
128 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
129 WSSecHeader secHeader = new WSSecHeader(doc);
130 secHeader.insertSecurityHeader();
131
132 WSSecUsernameToken builder = new WSSecUsernameToken(secHeader);
133 builder.setUserInfo("wernerd", "verySecret");
134 LOG.info("Before adding UsernameToken PW Digest....");
135 Document signedDoc = builder.build();
136
137 if (LOG.isDebugEnabled()) {
138 LOG.debug("Message with UserNameToken PW Digest:");
139 String outputString =
140 XMLUtils.prettyDocumentToString(signedDoc);
141 LOG.debug(outputString);
142 }
143 LOG.info("After adding UsernameToken PW Digest....");
144
145 WSHandlerResult results = verify(signedDoc);
146 WSSecurityEngineResult actionResult =
147 results.getActionResults().get(WSConstants.UT).get(0);
148 UsernameToken receivedToken =
149 (UsernameToken) actionResult.get(WSSecurityEngineResult.TAG_USERNAME_TOKEN);
150 assertNotNull(receivedToken);
151
152 UsernameToken clone =
153 new UsernameToken(receivedToken.getElement(), false, new BSPEnforcer());
154 assertTrue(clone.equals(receivedToken));
155 assertTrue(clone.hashCode() == receivedToken.hashCode());
156 }
157
158
159
160
161 @Test
162 public void testUsernameTokenWithEncodedPasswordBaseline() throws Exception {
163 String password = "password";
164
165 byte[] passwordHash = MessageDigest.getInstance("SHA-1").digest(password.getBytes(StandardCharsets.UTF_8));
166
167 String nonce = "0x7bXAPZVn40AdCD0Xbt0g==";
168 String created = "2010-06-28T15:16:37Z";
169 String expectedPasswordDigest = "C0rena/6gKpRZ9ATj+e6ss5sAbQ=";
170 byte[] decodedNonce = org.apache.xml.security.utils.XMLUtils.decode(nonce);
171 String actualPasswordDigest = UsernameTokenUtil.doPasswordDigest(decodedNonce, created, passwordHash);
172 assertEquals(expectedPasswordDigest, actualPasswordDigest, "the password digest is not as expected");
173 }
174
175
176
177
178 @Test
179 public void testUsernameTokenWithEncodedPassword() throws Exception {
180 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
181 WSSecHeader secHeader = new WSSecHeader(doc);
182 secHeader.insertSecurityHeader();
183
184 WSSecUsernameToken builder = new WSSecUsernameToken(secHeader);
185 builder.setPasswordsAreEncoded(true);
186 byte[] bytes = MessageDigest.getInstance("SHA-1").digest("verySecret".getBytes(StandardCharsets.UTF_8));
187 builder.setUserInfo("wernerd", org.apache.xml.security.utils.XMLUtils.encodeToString(bytes));
188 LOG.info("Before adding UsernameToken PW Digest....");
189 Document signedDoc = builder.build();
190
191 if (LOG.isDebugEnabled()) {
192 LOG.debug("Message with UserNameToken PW Digest:");
193 String outputString =
194 XMLUtils.prettyDocumentToString(signedDoc);
195 LOG.debug(outputString);
196 }
197 LOG.info("After adding UsernameToken PW Digest....");
198
199 WSSecurityEngine newEngine = new WSSecurityEngine();
200 RequestData requestData = new RequestData();
201 requestData.setEncodePasswords(true);
202 requestData.setCallbackHandler(new EncodedPasswordCallbackHandler());
203 newEngine.processSecurityHeader(signedDoc, requestData);
204 }
205
206
207
208
209
210 @Test
211 public void testUsernameTokenBadUsername() throws Exception {
212 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
213 WSSecHeader secHeader = new WSSecHeader(doc);
214 secHeader.insertSecurityHeader();
215
216 WSSecUsernameToken builder = new WSSecUsernameToken(secHeader);
217 builder.setUserInfo("badusername", "verySecret");
218 LOG.info("Before adding UsernameToken PW Digest....");
219 Document signedDoc = builder.build();
220
221 if (LOG.isDebugEnabled()) {
222 LOG.debug("Message with UserNameToken PW Digest:");
223 String outputString =
224 XMLUtils.prettyDocumentToString(signedDoc);
225 LOG.debug(outputString);
226 }
227 LOG.info("After adding UsernameToken PW Digest....");
228 try {
229 verify(signedDoc);
230 fail("Failure expected on a bad username");
231 } catch (WSSecurityException ex) {
232 String message = ex.getMessage();
233 assertFalse(message.contains("badusername"));
234 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
235
236 }
237 }
238
239
240
241
242 @Test
243 public void testUsernameTokenBadDigest() throws Exception {
244 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
245 WSSecHeader secHeader = new WSSecHeader(doc);
246 secHeader.insertSecurityHeader();
247
248 WSSecUsernameToken builder = new WSSecUsernameToken(secHeader);
249 builder.setUserInfo("wernerd", "verySecre");
250 LOG.info("Before adding UsernameToken PW Digest....");
251 Document signedDoc = builder.build();
252
253 if (LOG.isDebugEnabled()) {
254 LOG.debug("Message with UserNameToken PW Digest:");
255 String outputString =
256 XMLUtils.prettyDocumentToString(signedDoc);
257 LOG.debug(outputString);
258 }
259 LOG.info("After adding UsernameToken PW Digest....");
260 try {
261 verify(signedDoc);
262 fail("Failure expected on a bad password digest");
263 } catch (WSSecurityException ex) {
264 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
265
266 }
267 }
268
269
270
271
272
273 @Test
274 public void testOldUsernameToken() throws Exception {
275 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
276 WSSecHeader secHeader = new WSSecHeader(doc);
277 secHeader.insertSecurityHeader();
278
279 WSSecUsernameToken builder = new WSSecUsernameToken(secHeader);
280 builder.setUserInfo("wernerd", "verySecret");
281 Document signedDoc = builder.build();
282
283 if (LOG.isDebugEnabled()) {
284 String outputString =
285 XMLUtils.prettyDocumentToString(signedDoc);
286 LOG.debug(outputString);
287 }
288
289 RequestData requestData = new RequestData();
290 requestData.setUtTTL(-1);
291 requestData.setCallbackHandler(callbackHandler);
292
293 try {
294 WSSecurityEngine secEngine = new WSSecurityEngine();
295 secEngine.processSecurityHeader(doc, requestData);
296 fail("The UsernameToken validation should have failed");
297 } catch (WSSecurityException ex) {
298 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.MESSAGE_EXPIRED);
299 }
300 }
301
302
303
304
305
306
307 @Test
308 public void testNearFutureCreated() throws Exception {
309 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
310 WSSecHeader secHeader = new WSSecHeader(doc);
311 secHeader.insertSecurityHeader();
312
313 Element usernameTokenElement =
314 doc.createElementNS(
315 WSConstants.WSSE_NS, WSConstants.WSSE_PREFIX + ":" + WSConstants.USERNAME_TOKEN_LN
316 );
317 Element usernameElement =
318 doc.createElementNS(
319 WSConstants.WSSE_NS, WSConstants.WSSE_PREFIX + ":" + WSConstants.USERNAME_LN
320 );
321 usernameElement.appendChild(doc.createTextNode("wernerd"));
322 usernameTokenElement.appendChild(usernameElement);
323
324 Element passwordElement =
325 doc.createElementNS(
326 WSConstants.WSSE_NS, WSConstants.WSSE_PREFIX + ":" + WSConstants.PASSWORD_LN
327 );
328 passwordElement.setAttributeNS(null, "Type", WSConstants.PASSWORD_TEXT);
329 passwordElement.appendChild(doc.createTextNode("verySecret"));
330 usernameTokenElement.appendChild(passwordElement);
331
332 Element elementCreated =
333 doc.createElementNS(
334 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.CREATED_LN
335 );
336 ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC).plusSeconds(30L);
337 elementCreated.appendChild(doc.createTextNode(DateUtil.getDateTimeFormatter(true).format(now)));
338 usernameTokenElement.appendChild(elementCreated);
339
340 secHeader.getSecurityHeaderElement().appendChild(usernameTokenElement);
341
342 if (LOG.isDebugEnabled()) {
343 String outputString =
344 XMLUtils.prettyDocumentToString(doc);
345 LOG.debug(outputString);
346 }
347
348
349 WSSecurityEngine secEngine = new WSSecurityEngine();
350 secEngine.processSecurityHeader(doc, null, callbackHandler, null);
351
352
353 try {
354 RequestData requestData = new RequestData();
355 requestData.setUtFutureTTL(0);
356 requestData.setCallbackHandler(callbackHandler);
357
358 secEngine.processSecurityHeader(doc, requestData);
359 fail("The UsernameToken validation should have failed");
360 } catch (WSSecurityException ex) {
361 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.MESSAGE_EXPIRED);
362 }
363 }
364
365
366
367
368
369 @Test
370 public void testFutureCreated() throws Exception {
371 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
372 WSSecHeader secHeader = new WSSecHeader(doc);
373 secHeader.insertSecurityHeader();
374
375 Element usernameTokenElement =
376 doc.createElementNS(
377 WSConstants.WSSE_NS, WSConstants.WSSE_PREFIX + ":" + WSConstants.USERNAME_TOKEN_LN
378 );
379 Element usernameElement =
380 doc.createElementNS(
381 WSConstants.WSSE_NS, WSConstants.WSSE_PREFIX + ":" + WSConstants.USERNAME_LN
382 );
383 usernameElement.appendChild(doc.createTextNode("wernerd"));
384 usernameTokenElement.appendChild(usernameElement);
385
386 Element passwordElement =
387 doc.createElementNS(
388 WSConstants.WSSE_NS, WSConstants.WSSE_PREFIX + ":" + WSConstants.PASSWORD_LN
389 );
390 passwordElement.setAttributeNS(null, "Type", WSConstants.PASSWORD_TEXT);
391 passwordElement.appendChild(doc.createTextNode("verySecret"));
392 usernameTokenElement.appendChild(passwordElement);
393
394 Element elementCreated =
395 doc.createElementNS(
396 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.CREATED_LN
397 );
398 ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC).plusSeconds(120L);
399 elementCreated.appendChild(doc.createTextNode(DateUtil.getDateTimeFormatter(true).format(now)));
400 usernameTokenElement.appendChild(elementCreated);
401
402 secHeader.getSecurityHeaderElement().appendChild(usernameTokenElement);
403
404 if (LOG.isDebugEnabled()) {
405 String outputString =
406 XMLUtils.prettyDocumentToString(doc);
407 LOG.debug(outputString);
408 }
409
410 try {
411 WSSecurityEngine secEngine = new WSSecurityEngine();
412 secEngine.processSecurityHeader(doc, null, callbackHandler, null);
413 fail("The UsernameToken validation should have failed");
414 } catch (WSSecurityException ex) {
415 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.MESSAGE_EXPIRED);
416 }
417 }
418
419
420
421
422 @Test
423 public void testUsernameTokenText() 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.setPasswordType(WSConstants.PASSWORD_TEXT);
430 builder.setUserInfo("wernerd", "verySecret");
431 LOG.info("Before adding UsernameToken PW Text....");
432 Document signedDoc = builder.build();
433 if (LOG.isDebugEnabled()) {
434 LOG.debug("Message with UserNameToken PW Text:");
435 String outputString =
436 XMLUtils.prettyDocumentToString(signedDoc);
437 LOG.debug(outputString);
438 }
439 LOG.info("After adding UsernameToken PW Text....");
440
441 WSHandlerResult results = verify(signedDoc);
442 WSSecurityEngineResult actionResult =
443 results.getActionResults().get(WSConstants.UT).get(0);
444 UsernameToken receivedToken =
445 (UsernameToken) actionResult.get(WSSecurityEngineResult.TAG_USERNAME_TOKEN);
446 assertNotNull(receivedToken);
447
448 UsernameToken clone =
449 new UsernameToken(receivedToken.getElement(), false, new BSPEnforcer());
450 assertTrue(clone.equals(receivedToken));
451 assertTrue(clone.hashCode() == receivedToken.hashCode());
452 }
453
454
455
456
457
458 @Test
459 public void testUsernameTokenDigestText() throws Exception {
460 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
461 WSSecHeader secHeader = new WSSecHeader(doc);
462 secHeader.insertSecurityHeader();
463
464 WSSecUsernameToken builder = new WSSecUsernameToken(secHeader);
465 builder.setPasswordType(WSConstants.PASSWORD_TEXT);
466 byte[] password = "verySecret".getBytes();
467 MessageDigest sha = MessageDigest.getInstance("MD5");
468 sha.reset();
469 sha.update(password);
470 String passwdDigest = org.apache.xml.security.utils.XMLUtils.encodeToString(sha.digest());
471
472 builder.setUserInfo("wernerd", passwdDigest);
473 LOG.info("Before adding UsernameToken PW Text....");
474 Document signedDoc = builder.build();
475 if (LOG.isDebugEnabled()) {
476 LOG.debug("Message with UserNameToken PW Text:");
477 String outputString =
478 XMLUtils.prettyDocumentToString(signedDoc);
479 LOG.debug(outputString);
480 }
481 }
482
483
484
485
486 @Test
487 public void testUsernameTokenBadText() throws Exception {
488 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
489 WSSecHeader secHeader = new WSSecHeader(doc);
490 secHeader.insertSecurityHeader();
491
492 WSSecUsernameToken builder = new WSSecUsernameToken(secHeader);
493 builder.setPasswordType(WSConstants.PASSWORD_TEXT);
494 builder.setUserInfo("wernerd", "verySecre");
495 LOG.info("Before adding UsernameToken PW Text....");
496 Document signedDoc = builder.build();
497 if (LOG.isDebugEnabled()) {
498 LOG.debug("Message with UserNameToken PW Text:");
499 String outputString =
500 XMLUtils.prettyDocumentToString(signedDoc);
501 LOG.debug(outputString);
502 }
503 LOG.info("After adding UsernameToken PW Text....");
504
505 try {
506 verify(signedDoc);
507 fail("Failure expected on a bad password text");
508 } catch (WSSecurityException ex) {
509 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
510
511 }
512 }
513
514
515
516
517
518
519
520
521 @Test
522 public void testUsernameTokenNoPasswordType() throws Exception {
523 Document doc = SOAPUtil.toSOAPPart(SOAPUTMSG);
524 if (LOG.isDebugEnabled()) {
525 String outputString =
526 XMLUtils.prettyDocumentToString(doc);
527 LOG.debug(outputString);
528 }
529
530 WSSecurityEngine newEngine = new WSSecurityEngine();
531 try {
532 newEngine.processSecurityHeader(doc, null, callbackHandler, null);
533 fail("Expected failure as it is not BSP compliant");
534 } catch (WSSecurityException ex) {
535 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
536 }
537 RequestData data = new RequestData();
538 data.setCallbackHandler(callbackHandler);
539 data.setIgnoredBSPRules(Collections.singletonList(BSPRule.R4201));
540 newEngine.processSecurityHeader(doc, data);
541 }
542
543
544
545
546
547
548 @Test
549 public void testUsernameTokenNoUser() throws Exception {
550 Document doc = SOAPUtil.toSOAPPart(SOAPUTNOUSERMSG);
551 if (LOG.isDebugEnabled()) {
552 String outputString =
553 XMLUtils.prettyDocumentToString(doc);
554 LOG.debug(outputString);
555 }
556 try {
557 verify(doc);
558 fail("Failure expected on no password");
559 } catch (WSSecurityException ex) {
560 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
561
562 }
563 }
564
565
566
567
568 @Test
569 public void testUsernameTokenNoPassword() throws Exception {
570 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
571 WSSecHeader secHeader = new WSSecHeader(doc);
572 secHeader.insertSecurityHeader();
573
574 WSSecUsernameToken builder = new WSSecUsernameToken(secHeader);
575 builder.setPasswordType(null);
576 builder.setUserInfo("nopassuser", null);
577 LOG.info("Before adding UsernameToken with no password....");
578 Document signedDoc = builder.build();
579 if (LOG.isDebugEnabled()) {
580 String outputString =
581 XMLUtils.prettyDocumentToString(signedDoc);
582 LOG.debug(outputString);
583 }
584
585 WSHandlerResult results = verify(signedDoc, true);
586 WSSecurityEngineResult actionResult =
587 results.getActionResults().get(WSConstants.UT_NOPASSWORD).get(0);
588 UsernameToken receivedToken =
589 (UsernameToken) actionResult.get(WSSecurityEngineResult.TAG_USERNAME_TOKEN);
590 assertNotNull(receivedToken);
591 }
592
593
594
595
596 @Test
597 public void testUsernameTokenEmptyPassword() throws Exception {
598 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
599 WSSecHeader secHeader = new WSSecHeader(doc);
600 secHeader.insertSecurityHeader();
601
602 WSSecUsernameToken builder = new WSSecUsernameToken(secHeader);
603 builder.setPasswordType(WSConstants.PASSWORD_TEXT);
604 builder.setUserInfo("emptyuser", "");
605 LOG.info("Before adding UsernameToken with an empty password....");
606 Document signedDoc = builder.build();
607 if (LOG.isDebugEnabled()) {
608 String outputString =
609 XMLUtils.prettyDocumentToString(signedDoc);
610 LOG.debug(outputString);
611 }
612 WSSecurityEngine secEngine = new WSSecurityEngine();
613 secEngine.processSecurityHeader(doc, null, this, null);
614 }
615
616
617
618
619 @Test
620 public void testEmptyPasswordProcessing() throws Exception {
621 Document doc = SOAPUtil.toSOAPPart(EMPTY_PASSWORD_MSG);
622 if (LOG.isDebugEnabled()) {
623 LOG.debug("Empty password message: ");
624 String outputString =
625 XMLUtils.prettyDocumentToString(doc);
626 LOG.debug(outputString);
627 }
628
629 WSSecurityEngine secEngine = new WSSecurityEngine();
630 secEngine.processSecurityHeader(doc, null, this, null);
631 }
632
633
634
635
636
637 @Test
638 public void testUsernameTokenCustomFail() throws Exception {
639 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
640 WSSecHeader secHeader = new WSSecHeader(doc);
641 secHeader.insertSecurityHeader();
642
643 WSSecUsernameToken builder = new WSSecUsernameToken(secHeader);
644 builder.setPasswordType("RandomType");
645 builder.setUserInfo("wernerd", "verySecret");
646
647 Document signedDoc = builder.build();
648
649 if (LOG.isDebugEnabled()) {
650 LOG.debug("Message with UserNameToken PW Text:");
651 String outputString =
652 XMLUtils.prettyDocumentToString(signedDoc);
653 LOG.debug(outputString);
654 }
655 try {
656 WSSecurityEngine secEngine = new WSSecurityEngine();
657 secEngine.processSecurityHeader(signedDoc, null, this, null);
658 fail("Custom token types are not permitted");
659 } catch (WSSecurityException ex) {
660 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
661
662 }
663 }
664
665
666
667
668
669 @Test
670 public void testUsernameTokenCustomPass() throws Exception {
671 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
672 WSSecHeader secHeader = new WSSecHeader(doc);
673 secHeader.insertSecurityHeader();
674
675 WSSecUsernameToken builder = new WSSecUsernameToken(secHeader);
676 builder.setPasswordType("RandomType");
677 builder.setUserInfo("wernerd", "verySecret");
678
679 Document signedDoc = builder.build();
680
681 if (LOG.isDebugEnabled()) {
682 LOG.debug("Message with UserNameToken PW custom type:");
683 String outputString =
684 XMLUtils.prettyDocumentToString(signedDoc);
685 LOG.debug(outputString);
686 }
687
688
689
690
691 WSSecurityEngine secEngine = new WSSecurityEngine();
692
693 RequestData requestData = new RequestData();
694 requestData.setHandleCustomPasswordTypes(true);
695 requestData.setCallbackHandler(callbackHandler);
696
697 secEngine.processSecurityHeader(doc, requestData);
698 }
699
700
701
702
703
704
705
706 @Test
707 public void testNullNonce() throws Exception {
708 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
709 WSSecHeader secHeader = new WSSecHeader(doc);
710 secHeader.insertSecurityHeader();
711
712 WSSecUsernameToken builder = new WSSecUsernameToken(secHeader);
713 builder.setPasswordType(WSConstants.PASSWORD_DIGEST);
714 builder.setUserInfo("wernerd", "BAD_PASSWORD");
715
716 Document utDoc = builder.build();
717
718
719
720
721 Element elem = builder.getUsernameTokenElement();
722 NodeList list = elem.getElementsByTagNameNS(WSConstants.WSSE_NS, "Nonce");
723 Node nonceNode = list.item(0);
724 Node childNode = nonceNode.getFirstChild();
725 childNode.setNodeValue("");
726
727 if (LOG.isDebugEnabled()) {
728 String outputString =
729 XMLUtils.prettyDocumentToString(utDoc);
730 LOG.debug(outputString);
731 }
732
733 try {
734
735
736
737 verify(utDoc);
738 fail("Expected failure due to a bad password");
739 } catch (WSSecurityException ex) {
740 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
741
742 }
743 }
744
745
746
747
748
749
750 @Test
751 public void testNullCreated() throws Exception {
752 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
753 WSSecHeader secHeader = new WSSecHeader(doc);
754 secHeader.insertSecurityHeader();
755
756 WSSecUsernameToken builder = new WSSecUsernameToken(secHeader);
757 builder.setPasswordType(WSConstants.PASSWORD_DIGEST);
758 builder.setUserInfo("wernerd", "BAD_PASSWORD");
759
760 Document utDoc = builder.build();
761
762
763
764 Element elem = builder.getUsernameTokenElement();
765 NodeList list = elem.getElementsByTagNameNS(WSConstants.WSU_NS, "Created");
766 Node nonceNode = list.item(0);
767 Node childNode = nonceNode.getFirstChild();
768 childNode.setNodeValue("");
769
770 if (LOG.isDebugEnabled()) {
771 String outputString =
772 XMLUtils.prettyDocumentToString(utDoc);
773 LOG.debug(outputString);
774 }
775
776 try {
777
778
779
780 verify(utDoc);
781 fail("Expected failure due to a bad password");
782 } catch (WSSecurityException ex) {
783 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
784
785 }
786 }
787
788
789
790
791 @Test
792 public void testUsernameTokenNonceEncodingType() throws Exception {
793 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
794 WSSecHeader secHeader = new WSSecHeader(doc);
795 secHeader.insertSecurityHeader();
796
797 WSSecUsernameToken builder = new WSSecUsernameToken(secHeader);
798 builder.setUserInfo("wernerd", "verySecret");
799 LOG.info("Before adding UsernameToken PW Digest....");
800 Document signedDoc = builder.build();
801 String outputString =
802 XMLUtils.prettyDocumentToString(signedDoc);
803 assertTrue(outputString.contains("EncodingType"));
804 }
805
806
807
808
809 @Test
810 public void testUsernameTokenWSHandler() throws Exception {
811 CustomHandler handler = new CustomHandler();
812 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
813
814 RequestData reqData = new RequestData();
815 java.util.Map<String, Object> config = new java.util.TreeMap<>();
816 config.put("password", "verySecret");
817 config.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
818 reqData.setUsername("wernerd");
819 reqData.setMsgContext(config);
820
821 HandlerAction action = new HandlerAction(WSConstants.UT);
822 handler.send(
823 doc,
824 reqData,
825 Collections.singletonList(action),
826 true
827 );
828
829 if (LOG.isDebugEnabled()) {
830 LOG.debug("Username Token via WSHandler");
831 String outputString =
832 XMLUtils.prettyDocumentToString(doc);
833 LOG.debug(outputString);
834 }
835 }
836
837
838
839
840 @Test
841 public void testUsernameTokenWSHandlerNoPassword() throws Exception {
842 CustomHandler handler = new CustomHandler();
843 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
844
845 RequestData reqData = new RequestData();
846 java.util.Map<String, Object> config = new java.util.TreeMap<>();
847 config.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_NONE);
848 reqData.setUsername("wernerd");
849 reqData.setMsgContext(config);
850
851 HandlerAction action = new HandlerAction(WSConstants.UT);
852 handler.send(
853 doc,
854 reqData,
855 Collections.singletonList(action),
856 true
857 );
858
859 if (LOG.isDebugEnabled()) {
860 LOG.debug("Username Token via WSHandler");
861 String outputString =
862 XMLUtils.prettyDocumentToString(doc);
863 LOG.debug(outputString);
864 }
865 }
866
867
868
869
870 @Test
871 public void testUsernameTokenWSHandlerNoPassword2() throws Exception {
872 CustomHandler handler = new CustomHandler();
873 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
874
875 RequestData reqData = new RequestData();
876 java.util.Map<String, Object> config = new java.util.TreeMap<>();
877 reqData.setUsername("wernerd");
878 reqData.setMsgContext(config);
879
880 HandlerAction action = new HandlerAction(WSConstants.UT_NOPASSWORD);
881 handler.send(
882 doc,
883 reqData,
884 Collections.singletonList(action),
885 true
886 );
887
888 if (LOG.isDebugEnabled()) {
889 LOG.debug("Username Token via WSHandler");
890 String outputString =
891 XMLUtils.prettyDocumentToString(doc);
892 LOG.debug(outputString);
893 }
894 }
895
896
897
898
899 @Test
900 public void testUsernameTokenWSHandlerEmptyPassword() throws Exception {
901 CustomHandler handler = new CustomHandler();
902 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
903
904 RequestData reqData = new RequestData();
905 java.util.Map<String, Object> config = new java.util.TreeMap<>();
906 config.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
907 config.put(WSHandlerConstants.PW_CALLBACK_REF, this);
908 reqData.setUsername("emptyuser");
909 reqData.setMsgContext(config);
910
911 HandlerAction action = new HandlerAction(WSConstants.UT);
912 handler.send(
913 doc,
914 reqData,
915 Collections.singletonList(action),
916 true
917 );
918
919 if (LOG.isDebugEnabled()) {
920 LOG.debug("Username Token with an empty password via WSHandler");
921 String outputString =
922 XMLUtils.prettyDocumentToString(doc);
923 LOG.debug(outputString);
924 }
925 }
926
927
928
929
930 @Test
931 public void testMultipleNonce() throws Exception {
932 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
933 WSSecHeader secHeader = new WSSecHeader(doc);
934 secHeader.insertSecurityHeader();
935
936 WSSecUsernameToken builder = new WSSecUsernameToken(secHeader);
937 builder.setPasswordType(WSConstants.PASSWORD_DIGEST);
938 builder.setUserInfo("wernerd", "verySecret");
939
940 Document utDoc = builder.build();
941
942
943
944
945 Element elem = builder.getUsernameTokenElement();
946 NodeList list = elem.getElementsByTagNameNS(WSConstants.WSSE_NS, "Nonce");
947 Node nonceNode = list.item(0);
948 Node nonceCopy = nonceNode.cloneNode(true);
949 nonceNode.getParentNode().insertBefore(nonceCopy, nonceNode);
950
951 if (LOG.isDebugEnabled()) {
952 String outputString =
953 XMLUtils.prettyDocumentToString(utDoc);
954 LOG.debug(outputString);
955 }
956
957 WSSecurityEngine newEngine = new WSSecurityEngine();
958 try {
959 newEngine.processSecurityHeader(doc, null, callbackHandler, null);
960 fail("Expected failure as it is not BSP compliant");
961 } catch (WSSecurityException ex) {
962 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY );
963 }
964
965 RequestData data = new RequestData();
966 data.setCallbackHandler(callbackHandler);
967 data.setIgnoredBSPRules(Collections.singletonList(BSPRule.R4225));
968 newEngine.processSecurityHeader(doc, data);
969 }
970
971
972
973
974 @Test
975 public void testMultipleCreated() throws Exception {
976 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
977 WSSecHeader secHeader = new WSSecHeader(doc);
978 secHeader.insertSecurityHeader();
979
980 WSSecUsernameToken builder = new WSSecUsernameToken(secHeader);
981 builder.setPasswordType(WSConstants.PASSWORD_DIGEST);
982 builder.setUserInfo("wernerd", "verySecret");
983
984 Document utDoc = builder.build();
985
986
987
988
989 Element elem = builder.getUsernameTokenElement();
990 NodeList list = elem.getElementsByTagNameNS(WSConstants.WSU_NS, "Created");
991 Node createdNode = list.item(0);
992 Node createdCopy = createdNode.cloneNode(true);
993 createdNode.getParentNode().insertBefore(createdCopy, createdNode);
994
995 if (LOG.isDebugEnabled()) {
996 String outputString =
997 XMLUtils.prettyDocumentToString(utDoc);
998 LOG.debug(outputString);
999 }
1000
1001 WSSecurityEngine newEngine = new WSSecurityEngine();
1002 try {
1003 newEngine.processSecurityHeader(doc, null, callbackHandler, null);
1004 fail("Expected failure as it is not BSP compliant");
1005 } catch (WSSecurityException ex) {
1006 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
1007 }
1008
1009 RequestData data = new RequestData();
1010 data.setCallbackHandler(callbackHandler);
1011 data.setIgnoredBSPRules(Collections.singletonList(BSPRule.R4223));
1012 newEngine.processSecurityHeader(doc, data);
1013 }
1014
1015
1016
1017
1018 @Test
1019 public void testMultiplePassword() throws Exception {
1020 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
1021 WSSecHeader secHeader = new WSSecHeader(doc);
1022 secHeader.insertSecurityHeader();
1023
1024 WSSecUsernameToken builder = new WSSecUsernameToken(secHeader);
1025 builder.setPasswordType(WSConstants.PASSWORD_DIGEST);
1026 builder.setUserInfo("wernerd", "verySecret");
1027
1028 Document utDoc = builder.build();
1029
1030
1031
1032
1033 Element elem = builder.getUsernameTokenElement();
1034 NodeList list = elem.getElementsByTagNameNS(WSConstants.WSSE_NS, "Password");
1035 Node passwordNode = list.item(0);
1036 Node passwordCopy = passwordNode.cloneNode(true);
1037 passwordNode.getParentNode().insertBefore(passwordCopy, passwordNode);
1038
1039 if (LOG.isDebugEnabled()) {
1040 String outputString =
1041 XMLUtils.prettyDocumentToString(utDoc);
1042 LOG.debug(outputString);
1043 }
1044
1045 WSSecurityEngine newEngine = new WSSecurityEngine();
1046 try {
1047 newEngine.processSecurityHeader(doc, null, callbackHandler, null);
1048 fail("Expected failure as it is not BSP compliant");
1049 } catch (WSSecurityException ex) {
1050 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
1051 }
1052
1053 RequestData data = new RequestData();
1054 data.setCallbackHandler(callbackHandler);
1055 data.setIgnoredBSPRules(Collections.singletonList(BSPRule.R4222));
1056 newEngine.processSecurityHeader(doc, data);
1057 }
1058
1059
1060
1061
1062 @Test
1063 public void testNonceBadEncodingType() throws Exception {
1064 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
1065 WSSecHeader secHeader = new WSSecHeader(doc);
1066 secHeader.insertSecurityHeader();
1067
1068 WSSecUsernameToken builder = new WSSecUsernameToken(secHeader);
1069 builder.setPasswordType(WSConstants.PASSWORD_DIGEST);
1070 builder.setUserInfo("wernerd", "verySecret");
1071
1072 Document utDoc = builder.build();
1073
1074
1075
1076
1077 Element elem = builder.getUsernameTokenElement();
1078 NodeList list = elem.getElementsByTagNameNS(WSConstants.WSSE_NS, "Nonce");
1079 Node nonceNode = list.item(0);
1080 ((Element)nonceNode).setAttributeNS(
1081 null, "EncodingType", "http://bad_encoding_type"
1082 );
1083
1084 if (LOG.isDebugEnabled()) {
1085 String outputString =
1086 XMLUtils.prettyDocumentToString(utDoc);
1087 LOG.debug(outputString);
1088 }
1089
1090 WSSecurityEngine newEngine = new WSSecurityEngine();
1091 try {
1092 newEngine.processSecurityHeader(doc, null, callbackHandler, null);
1093 fail("Expected failure as it is not BSP compliant");
1094 } catch (WSSecurityException ex) {
1095 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
1096 }
1097
1098 RequestData data = new RequestData();
1099 data.setCallbackHandler(callbackHandler);
1100 data.setIgnoredBSPRules(Collections.singletonList(BSPRule.R4221));
1101 newEngine.processSecurityHeader(doc, data);
1102 }
1103
1104 @Test
1105 public void testUsernameTokenWSHandlerNonceCreated() throws Exception {
1106 CustomHandler handler = new CustomHandler();
1107 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
1108
1109 RequestData reqData = new RequestData();
1110 java.util.Map<String, Object> config = new java.util.TreeMap<>();
1111 config.put("password", "verySecret");
1112 config.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
1113 config.put(WSHandlerConstants.ADD_USERNAMETOKEN_NONCE, "true");
1114 config.put(WSHandlerConstants.ADD_USERNAMETOKEN_CREATED, "true");
1115 reqData.setUsername("wernerd");
1116 reqData.setMsgContext(config);
1117
1118 HandlerAction action = new HandlerAction(WSConstants.UT);
1119 handler.send(
1120 doc,
1121 reqData,
1122 Collections.singletonList(action),
1123 true
1124 );
1125
1126 if (LOG.isDebugEnabled()) {
1127 LOG.debug("Username Token via WSHandler");
1128 String outputString =
1129 XMLUtils.prettyDocumentToString(doc);
1130 LOG.debug(outputString);
1131 }
1132 }
1133
1134
1135
1136
1137 @Test
1138 public void testSpoofedUsernameToken() throws Exception {
1139 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
1140 WSSecHeader secHeader = new WSSecHeader(doc);
1141 secHeader.insertSecurityHeader();
1142
1143 WSSecUsernameToken builder = new WSSecUsernameToken(secHeader);
1144 builder.setUserInfo("wernerd", "verySecret");
1145
1146 WSTimeSource spoofedTimeSource = new WSTimeSource() {
1147
1148 public Instant now() {
1149 return Instant.now().minusSeconds(500L);
1150 }
1151
1152 };
1153
1154 builder.setWsTimeSource(spoofedTimeSource);
1155 Document signedDoc = builder.build();
1156
1157 if (LOG.isDebugEnabled()) {
1158 String outputString =
1159 XMLUtils.prettyDocumentToString(signedDoc);
1160 LOG.debug(outputString);
1161 }
1162
1163 try {
1164 WSSecurityEngine secEngine = new WSSecurityEngine();
1165 secEngine.processSecurityHeader(doc, null, callbackHandler, null);
1166 fail("The UsernameToken validation should have failed");
1167 } catch (WSSecurityException ex) {
1168 assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.MESSAGE_EXPIRED);
1169 }
1170 }
1171
1172
1173 private WSHandlerResult verify(Document doc) throws Exception {
1174 return verify(doc, false);
1175 }
1176
1177
1178
1179
1180
1181
1182
1183
1184 private WSHandlerResult verify(Document doc, boolean allowUsernameTokenDerivedKeys) throws Exception {
1185 WSSecurityEngine secEngine = new WSSecurityEngine();
1186
1187 RequestData requestData = new RequestData();
1188 requestData.setAllowUsernameTokenNoPassword(allowUsernameTokenDerivedKeys);
1189 requestData.setCallbackHandler(callbackHandler);
1190
1191 return secEngine.processSecurityHeader(doc, requestData);
1192 }
1193
1194
1195
1196
1197 public void handle(Callback[] callbacks)
1198 throws IOException, UnsupportedCallbackException {
1199 for (Callback callback : callbacks) {
1200 if (callback instanceof WSPasswordCallback) {
1201 WSPasswordCallback pc = (WSPasswordCallback) callback;
1202 if (pc.getUsage() == WSPasswordCallback.USERNAME_TOKEN) {
1203 if ("emptyuser".equals(pc.getIdentifier())) {
1204 pc.setPassword("");
1205 } else if ("customUser".equals(pc.getIdentifier())) {
1206 return;
1207 } else if (null == pc.getIdentifier()) {
1208
1209 return;
1210 }
1211 }
1212 } else {
1213 throw new UnsupportedCallbackException(callback, "Unrecognized Callback");
1214 }
1215 }
1216 }
1217 }