1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.ws.security.message;
21
22 import org.apache.ws.security.WSConstants;
23 import org.apache.ws.security.WSEncryptionPart;
24 import org.apache.ws.security.WSSConfig;
25 import org.apache.ws.security.WSSecurityEngine;
26 import org.apache.ws.security.WSSecurityEngineResult;
27 import org.apache.ws.security.WSSecurityException;
28 import org.apache.ws.security.common.KeystoreCallbackHandler;
29 import org.apache.ws.security.common.SAML1CallbackHandler;
30 import org.apache.ws.security.common.SOAPUtil;
31 import org.apache.ws.security.components.crypto.Crypto;
32 import org.apache.ws.security.components.crypto.CryptoFactory;
33 import org.apache.ws.security.saml.WSSecSignatureSAML;
34 import org.apache.ws.security.saml.ext.AssertionWrapper;
35 import org.apache.ws.security.saml.ext.SAMLParms;
36 import org.apache.ws.security.saml.ext.builder.SAML1Constants;
37 import org.apache.ws.security.util.WSSecurityUtil;
38 import org.apache.ws.security.util.XmlSchemaDateFormat;
39 import org.w3c.dom.Document;
40 import org.w3c.dom.Element;
41 import org.w3c.dom.Node;
42
43 import java.text.DateFormat;
44 import java.util.Date;
45 import java.util.List;
46 import java.util.ArrayList;
47
48 import javax.security.auth.callback.CallbackHandler;
49
50
51
52
53 public class ModifiedRequestTest extends org.junit.Assert {
54 private static final org.apache.commons.logging.Log LOG =
55 org.apache.commons.logging.LogFactory.getLog(ModifiedRequestTest.class);
56 private static final String SOAPMSG =
57 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
58 + "<SOAP-ENV:Envelope "
59 + "xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" "
60 + "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" "
61 + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
62 + "<SOAP-ENV:Body>"
63 + "<add xmlns=\"http://ws.apache.org/counter/counter_port_type\">"
64 + "<value xmlns=\"http://blah.com\">15</value>"
65 + "</add>"
66 + "</SOAP-ENV:Body>"
67 + "</SOAP-ENV:Envelope>";
68
69 private WSSecurityEngine secEngine = new WSSecurityEngine();
70 private CallbackHandler callbackHandler = new KeystoreCallbackHandler();
71 private Crypto crypto = null;
72
73 public ModifiedRequestTest() throws Exception {
74 WSSConfig.init();
75 crypto = CryptoFactory.getInstance();
76 }
77
78
79
80
81
82
83
84 @org.junit.Test
85 public void testMovedElement() throws Exception {
86 WSSecSignature builder = new WSSecSignature();
87 builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
88 LOG.info("Before Signing....");
89 Document doc = SOAPUtil.toSOAPPart(SOAPMSG);
90 WSSecHeader secHeader = new WSSecHeader();
91 secHeader.insertSecurityHeader(doc);
92
93 List<WSEncryptionPart> parts = new ArrayList<WSEncryptionPart>();
94 WSEncryptionPart encP =
95 new WSEncryptionPart(
96 "value",
97 "http://blah.com",
98 "");
99 parts.add(encP);
100 builder.setParts(parts);
101
102 Document signedDoc = builder.build(doc, crypto, secHeader);
103
104
105
106
107
108 org.w3c.dom.Element secHeaderElement = secHeader.getSecurityHeader();
109 org.w3c.dom.Element envelopeElement = signedDoc.getDocumentElement();
110 org.w3c.dom.Node valueNode =
111 envelopeElement.getElementsByTagNameNS("http://blah.com", "value").item(0);
112 org.w3c.dom.Node clonedValueNode = valueNode.cloneNode(true);
113 secHeaderElement.appendChild(clonedValueNode);
114 valueNode.getFirstChild().setNodeValue("250");
115
116 if (LOG.isDebugEnabled()) {
117 LOG.debug("After Signing....");
118 String outputString =
119 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
120 LOG.debug(outputString);
121 }
122
123 try {
124 verify(signedDoc);
125 fail("Failure expected on multiple elements with the same wsu:Id");
126 } catch (WSSecurityException ex) {
127 assertTrue(ex.getErrorCode() == 6);
128 assertTrue(ex.getMessage().startsWith("The signature or decryption was invalid"));
129 }
130 }
131
132
133
134
135
136
137
138
139 @org.junit.Test
140 public void testMovedElementChangedId() throws Exception {
141 WSSecSignature builder = new WSSecSignature();
142 builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
143 LOG.info("Before Signing....");
144 Document doc = SOAPUtil.toSOAPPart(SOAPMSG);
145 WSSecHeader secHeader = new WSSecHeader();
146 secHeader.insertSecurityHeader(doc);
147
148 List<WSEncryptionPart> parts = new ArrayList<WSEncryptionPart>();
149 WSEncryptionPart encP =
150 new WSEncryptionPart(
151 "value",
152 "http://blah.com",
153 "");
154 parts.add(encP);
155 builder.setParts(parts);
156
157 Document signedDoc = builder.build(doc, crypto, secHeader);
158
159
160
161
162
163 org.w3c.dom.Element secHeaderElement = secHeader.getSecurityHeader();
164 org.w3c.dom.Element envelopeElement = signedDoc.getDocumentElement();
165 org.w3c.dom.Node valueNode =
166 envelopeElement.getElementsByTagNameNS("http://blah.com", "value").item(0);
167 org.w3c.dom.Node clonedValueNode = valueNode.cloneNode(true);
168 secHeaderElement.appendChild(clonedValueNode);
169 valueNode.getFirstChild().setNodeValue("250");
170 String savedId =
171 ((org.w3c.dom.Element)valueNode).getAttributeNS(WSConstants.WSU_NS, "Id");
172 ((org.w3c.dom.Element)valueNode).setAttributeNS(
173 WSConstants.WSU_NS, "wsu:Id", "id-250"
174 );
175
176 if (LOG.isDebugEnabled()) {
177 LOG.debug("After Signing....");
178 String outputString =
179 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
180 LOG.debug(outputString);
181 }
182
183
184
185
186
187 List<WSSecurityEngineResult> results = verify(signedDoc);
188
189 WSSecurityEngineResult actionResult =
190 WSSecurityUtil.fetchActionResult(results, WSConstants.SIGN);
191 WSSecurityUtil.checkSignsAllElements(actionResult, new String[]{savedId});
192
193
194
195
196
197 envelopeElement = signedDoc.getDocumentElement();
198 org.w3c.dom.Node bodyNode =
199 envelopeElement.getElementsByTagNameNS(
200 WSConstants.URI_SOAP11_ENV, "Body"
201 ).item(0);
202 valueNode =
203 ((org.w3c.dom.Element)bodyNode).getElementsByTagNameNS(
204 "http://blah.com", "value"
205 ).item(0);
206 String actualId =
207 ((org.w3c.dom.Element)valueNode).getAttributeNS(WSConstants.WSU_NS, "Id");
208 try {
209 WSSecurityUtil.checkSignsAllElements(actionResult, new String[]{actualId});
210 fail("Failure expected on bad wsu:Id");
211 } catch (WSSecurityException ex) {
212 assertTrue(ex.getErrorCode() == 6);
213 assertTrue(ex.getMessage().startsWith("The signature or decryption was invalid"));
214 }
215 }
216
217
218
219
220 @org.junit.Test
221 public void testDuplicatedSignedSAMLAssertion() throws Exception {
222 SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
223 callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
224 callbackHandler.setConfirmationMethod(SAML1Constants.CONF_SENDER_VOUCHES);
225 callbackHandler.setIssuer("www.example.com");
226
227 SAMLParms samlParms = new SAMLParms();
228 samlParms.setCallbackHandler(callbackHandler);
229 AssertionWrapper assertion = new AssertionWrapper(samlParms);
230
231 WSSecSignatureSAML wsSign = new WSSecSignatureSAML();
232 wsSign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
233
234 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
235 WSSecHeader secHeader = new WSSecHeader();
236 secHeader.insertSecurityHeader(doc);
237
238 Document signedDoc =
239 wsSign.build(
240 doc, null, assertion, crypto, "16c73ab6-b892-458f-abf5-2f875f74882e",
241 "security", secHeader
242 );
243 Element assertionElement = (Element)assertion.getElement().cloneNode(true);
244 assertionElement.removeChild(assertionElement.getFirstChild());
245 secHeader.getSecurityHeader().appendChild(assertionElement);
246
247 if (LOG.isDebugEnabled()) {
248 LOG.debug("SAML 1.1 Authn Assertion (sender vouches):");
249 String outputString =
250 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
251 LOG.debug(outputString);
252 }
253
254 try {
255 verify(signedDoc);
256 fail("Failure expected on duplicate tokens");
257 } catch (WSSecurityException ex) {
258 assertTrue(ex.getMessage().contains(
259 "Multiple security tokens with the same Id have been detected"
260 ));
261 }
262 }
263
264
265
266
267 @org.junit.Test
268 public void testDuplicatedSignedUsernameToken() throws Exception {
269 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
270 WSSecHeader secHeader = new WSSecHeader();
271 secHeader.insertSecurityHeader(doc);
272
273 WSSecUsernameToken usernameToken = new WSSecUsernameToken();
274 usernameToken.setUserInfo("wss86", "security");
275 Document createdDoc = usernameToken.build(doc, secHeader);
276
277 List<WSEncryptionPart> parts = new ArrayList<WSEncryptionPart>();
278 WSEncryptionPart encP =
279 new WSEncryptionPart(
280 "UsernameToken",
281 WSConstants.WSSE_NS,
282 "");
283 parts.add(encP);
284
285 WSSecSignature builder = new WSSecSignature();
286 builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
287 builder.setParts(parts);
288
289 builder.prepare(createdDoc, crypto, secHeader);
290
291 List<javax.xml.crypto.dsig.Reference> referenceList =
292 builder.addReferencesToSign(parts, secHeader);
293
294 builder.computeSignature(referenceList, false, null);
295
296 secHeader.getSecurityHeader().appendChild(
297 usernameToken.getUsernameTokenElement().cloneNode(true)
298 );
299
300 if (LOG.isDebugEnabled()) {
301 LOG.debug("Signed Timestamp");
302 String outputString =
303 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
304 LOG.debug(outputString);
305 }
306
307 try {
308 verify(doc);
309 fail("Failure expected on duplicate tokens");
310 } catch (WSSecurityException ex) {
311 assertTrue(ex.getMessage().contains(
312 "Multiple security tokens with the same Id have been detected"
313 ));
314 }
315 }
316
317
318
319
320 @org.junit.Test
321 public void testModifiedEncryptedDataStructure() throws Exception {
322 WSSecEncrypt builder = new WSSecEncrypt();
323 builder.setUserInfo("wss40");
324 builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
325 builder.setSymmetricEncAlgorithm(WSConstants.TRIPLE_DES);
326 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
327 WSSecHeader secHeader = new WSSecHeader();
328 secHeader.insertSecurityHeader(doc);
329 Crypto wssCrypto = CryptoFactory.getInstance("wss40.properties");
330 Document encryptedDoc = builder.build(doc, wssCrypto, secHeader);
331
332 Element body = WSSecurityUtil.findBodyElement(doc);
333 Element encryptionMethod =
334 WSSecurityUtil.findElement(body, "EncryptionMethod", WSConstants.ENC_NS);
335 encryptionMethod.setAttribute("Algorithm", "http://new-algorithm");
336
337 String outputString =
338 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(encryptedDoc);
339 if (LOG.isDebugEnabled()) {
340 LOG.debug(outputString);
341 }
342
343 WSSecurityEngine newEngine = new WSSecurityEngine();
344 try {
345 newEngine.processSecurityHeader(doc, null, new KeystoreCallbackHandler(), wssCrypto);
346 fail("Failure expected on a modified EncryptedData structure");
347 } catch (WSSecurityException ex) {
348
349 }
350 }
351
352
353
354
355 @org.junit.Test
356 public void testModifiedEncryptedDataCipherValue() throws Exception {
357 WSSecEncrypt builder = new WSSecEncrypt();
358 builder.setUserInfo("wss40");
359 builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
360 builder.setSymmetricEncAlgorithm(WSConstants.TRIPLE_DES);
361 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
362 WSSecHeader secHeader = new WSSecHeader();
363 secHeader.insertSecurityHeader(doc);
364 Crypto wssCrypto = CryptoFactory.getInstance("wss40.properties");
365 Document encryptedDoc = builder.build(doc, wssCrypto, secHeader);
366
367 Element body = WSSecurityUtil.findBodyElement(doc);
368 Element cipherValue =
369 WSSecurityUtil.findElement(body, "CipherValue", WSConstants.ENC_NS);
370 String cipherText = cipherValue.getTextContent();
371
372 StringBuilder stringBuilder = new StringBuilder(cipherText);
373 int index = stringBuilder.length() / 2;
374 char ch = stringBuilder.charAt(index);
375 if (ch != 'A') {
376 ch = 'A';
377 } else {
378 ch = 'B';
379 }
380 stringBuilder.setCharAt(index, ch);
381 cipherValue.setTextContent(stringBuilder.toString());
382
383 String outputString =
384 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(encryptedDoc);
385 if (LOG.isDebugEnabled()) {
386 LOG.debug(outputString);
387 }
388
389 WSSecurityEngine newEngine = new WSSecurityEngine();
390 try {
391 newEngine.processSecurityHeader(doc, null, new KeystoreCallbackHandler(), wssCrypto);
392 fail("Failure expected on a modified EncryptedData CipherValue");
393 } catch (WSSecurityException ex) {
394 assertTrue(ex.getErrorCode() == 6);
395 assertTrue(ex.getMessage().startsWith("The signature or decryption was invalid"));
396 }
397 }
398
399
400
401
402 @org.junit.Test
403 public void testModifiedEncryptedKeyCipherValue() throws Exception {
404 WSSecEncrypt builder = new WSSecEncrypt();
405 builder.setUserInfo("wss40");
406 builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
407 builder.setSymmetricEncAlgorithm(WSConstants.TRIPLE_DES);
408 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
409 WSSecHeader secHeader = new WSSecHeader();
410 secHeader.insertSecurityHeader(doc);
411 Crypto wssCrypto = CryptoFactory.getInstance("wss40.properties");
412 Document encryptedDoc = builder.build(doc, wssCrypto, secHeader);
413
414 Element encryptedKey =
415 WSSecurityUtil.findElement(doc.getDocumentElement(), "EncryptedKey", WSConstants.ENC_NS);
416 Element cipherValue =
417 WSSecurityUtil.findElement(encryptedKey, "CipherValue", WSConstants.ENC_NS);
418 String cipherText = cipherValue.getTextContent();
419
420 StringBuilder stringBuilder = new StringBuilder(cipherText);
421 int index = stringBuilder.length() / 2;
422 char ch = stringBuilder.charAt(index);
423 if (ch != 'A') {
424 ch = 'A';
425 } else {
426 ch = 'B';
427 }
428 stringBuilder.setCharAt(index, ch);
429 cipherValue.setTextContent(stringBuilder.toString());
430
431 String outputString =
432 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(encryptedDoc);
433 if (LOG.isDebugEnabled()) {
434 LOG.debug(outputString);
435 }
436
437 WSSecurityEngine newEngine = new WSSecurityEngine();
438 try {
439 newEngine.processSecurityHeader(doc, null, new KeystoreCallbackHandler(), wssCrypto);
440 fail("Failure expected on a modified EncryptedData CipherValue");
441 } catch (WSSecurityException ex) {
442 assertTrue(ex.getErrorCode() == 6);
443 assertTrue(ex.getMessage().startsWith("The signature or decryption was invalid"));
444 }
445 }
446
447
448
449
450
451
452 @org.junit.Test
453 public void testModifiedSignatureReference() throws Exception {
454 WSSecSignature builder = new WSSecSignature();
455 builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
456 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
457 WSSecHeader secHeader = new WSSecHeader();
458 secHeader.insertSecurityHeader(doc);
459
460 WSSecTimestamp timestamp = new WSSecTimestamp();
461 timestamp.setTimeToLive(300);
462 Document createdDoc = timestamp.build(doc, secHeader);
463
464 List<WSEncryptionPart> parts = new ArrayList<WSEncryptionPart>();
465 WSEncryptionPart encP =
466 new WSEncryptionPart(
467 "Timestamp",
468 WSConstants.WSU_NS,
469 "");
470 parts.add(encP);
471 builder.setParts(parts);
472
473 Document signedDoc = builder.build(createdDoc, crypto, secHeader);
474
475
476 Element timestampElement = timestamp.getElement();
477 Element createdValue =
478 WSSecurityUtil.findElement(timestampElement, "Created", WSConstants.WSU_NS);
479 DateFormat zulu = new XmlSchemaDateFormat();
480 createdValue.setTextContent(zulu.format(new Date()));
481
482 if (LOG.isDebugEnabled()) {
483 String outputString =
484 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
485 LOG.debug(outputString);
486 }
487
488 try {
489 verify(signedDoc);
490 fail("Failure expected on a modified Signature Reference");
491 } catch (WSSecurityException ex) {
492 assertTrue(ex.getErrorCode() == 6);
493 assertTrue(ex.getMessage().startsWith("The signature or decryption was invalid"));
494 }
495 }
496
497
498
499
500 @org.junit.Test
501 public void testUntrustedSignature() throws Exception {
502 WSSecSignature builder = new WSSecSignature();
503 builder.setUserInfo("wss40", "security");
504 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
505 WSSecHeader secHeader = new WSSecHeader();
506 secHeader.insertSecurityHeader(doc);
507
508 Crypto wss40Crypto = CryptoFactory.getInstance("wss40.properties");
509 Document signedDoc = builder.build(doc, wss40Crypto, secHeader);
510
511 if (LOG.isDebugEnabled()) {
512 String outputString =
513 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
514 LOG.debug(outputString);
515 }
516
517 try {
518 verify(signedDoc);
519 fail("Failure expected on an untrusted Certificate");
520 } catch (WSSecurityException ex) {
521 assertTrue(ex.getErrorCode() == 6);
522 assertTrue(ex.getMessage().startsWith("The signature or decryption was invalid"));
523 }
524 }
525
526
527
528
529 @org.junit.Test
530 public void testModifiedSignature() throws Exception {
531 WSSecSignature builder = new WSSecSignature();
532 builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
533 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
534 WSSecHeader secHeader = new WSSecHeader();
535 secHeader.insertSecurityHeader(doc);
536
537 Document signedDoc = builder.build(doc, crypto, secHeader);
538
539
540 Element signatureElement = builder.getSignatureElement();
541 Node firstChild = signatureElement.getFirstChild();
542 while (!(firstChild instanceof Element) && firstChild != null) {
543 firstChild = signatureElement.getNextSibling();
544 }
545 ((Element)firstChild).setAttributeNS(null, "Id", "xyz");
546
547 if (LOG.isDebugEnabled()) {
548 String outputString =
549 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
550 LOG.debug(outputString);
551 }
552
553 try {
554 verify(signedDoc);
555 fail("Failure expected on a modified Signature element");
556 } catch (WSSecurityException ex) {
557 assertTrue(ex.getErrorCode() == 6);
558 assertTrue(ex.getMessage().startsWith("The signature or decryption was invalid"));
559 }
560 }
561
562
563
564
565
566
567
568
569 private List<WSSecurityEngineResult> verify(Document doc) throws Exception {
570 return secEngine.processSecurityHeader(doc, null, callbackHandler, crypto);
571 }
572
573 }