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.ZoneOffset;
23  import java.time.ZonedDateTime;
24  import java.util.List;
25  
26  import javax.crypto.KeyGenerator;
27  import javax.crypto.SecretKey;
28  import javax.security.auth.callback.CallbackHandler;
29  
30  import org.apache.wss4j.common.WSEncryptionPart;
31  import org.apache.wss4j.common.crypto.Crypto;
32  import org.apache.wss4j.common.crypto.CryptoFactory;
33  import org.apache.wss4j.common.ext.WSSecurityException;
34  import org.apache.wss4j.common.saml.SAMLCallback;
35  import org.apache.wss4j.common.saml.SAMLUtil;
36  import org.apache.wss4j.common.saml.SamlAssertionWrapper;
37  import org.apache.wss4j.common.saml.builder.SAML1Constants;
38  import org.apache.wss4j.common.util.DateUtil;
39  import org.apache.wss4j.common.util.KeyUtils;
40  import org.apache.wss4j.common.util.SOAPUtil;
41  import org.apache.wss4j.common.util.XMLUtils;
42  import org.apache.wss4j.dom.WSConstants;
43  import org.apache.wss4j.dom.common.KeystoreCallbackHandler;
44  import org.apache.wss4j.dom.common.SAML1CallbackHandler;
45  
46  import org.apache.wss4j.dom.engine.WSSConfig;
47  import org.apache.wss4j.dom.engine.WSSecurityEngine;
48  import org.apache.wss4j.dom.engine.WSSecurityEngineResult;
49  import org.apache.wss4j.dom.handler.WSHandlerResult;
50  import org.apache.wss4j.dom.saml.WSSecSignatureSAML;
51  import org.apache.wss4j.dom.util.SignatureUtils;
52  import org.apache.wss4j.dom.util.WSSecurityUtil;
53  
54  import org.junit.jupiter.api.Test;
55  import org.w3c.dom.Document;
56  import org.w3c.dom.Element;
57  import org.w3c.dom.Node;
58  
59  import static org.junit.jupiter.api.Assertions.assertTrue;
60  import static org.junit.jupiter.api.Assertions.fail;
61  
62  /**
63   * This class tests the modification of requests.
64   */
65  public class ModifiedRequestTest {
66      private static final org.slf4j.Logger LOG =
67          org.slf4j.LoggerFactory.getLogger(ModifiedRequestTest.class);
68      private static final String SOAPMSG =
69          "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
70          + "<SOAP-ENV:Envelope "
71          +   "xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" "
72          +   "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" "
73          +   "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
74          +   "<SOAP-ENV:Body>"
75          +       "<add xmlns=\"http://ws.apache.org/counter/counter_port_type\">"
76          +           "<value xmlns=\"http://blah.com\">15</value>"
77          +       "</add>"
78          +   "</SOAP-ENV:Body>"
79          + "</SOAP-ENV:Envelope>";
80  
81      private WSSecurityEngine secEngine = new WSSecurityEngine();
82      private CallbackHandler callbackHandler = new KeystoreCallbackHandler();
83      private Crypto crypto;
84  
85      public ModifiedRequestTest() throws Exception {
86          WSSConfig.init();
87          crypto = CryptoFactory.getInstance();
88      }
89  
90      /**
91       * Test that signs a SOAP body element "value". The SOAP request is then modified
92       * so that the signed "value" element is put in the header, and the value of the
93       * original element is changed. This test will fail as the request will contain
94       * multiple elements with the same wsu:Id.
95       */
96      @Test
97      public void testMovedElement() throws Exception {
98          Document doc = SOAPUtil.toSOAPPart(SOAPMSG);
99          WSSecHeader secHeader = new WSSecHeader(doc);
100         secHeader.insertSecurityHeader();
101 
102         WSSecSignature builder = new WSSecSignature(secHeader);
103         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
104         LOG.info("Before Signing....");
105 
106         WSEncryptionPart encP =
107             new WSEncryptionPart(
108                 "value",
109                 "http://blah.com",
110                 "");
111         builder.getParts().add(encP);
112 
113         Document signedDoc = builder.build(crypto);
114 
115         //
116         // Replace the signed element with a modified element, and move the original
117         // signed element into the SOAP header
118         //
119         Element secHeaderElement = secHeader.getSecurityHeaderElement();
120         Element envelopeElement = signedDoc.getDocumentElement();
121         Node valueNode =
122             envelopeElement.getElementsByTagNameNS("http://blah.com", "value").item(0);
123         Node clonedValueNode = valueNode.cloneNode(true);
124         secHeaderElement.appendChild(clonedValueNode);
125         valueNode.getFirstChild().setNodeValue("250");
126 
127         if (LOG.isDebugEnabled()) {
128             LOG.debug("After Signing....");
129             String outputString =
130                 XMLUtils.prettyDocumentToString(signedDoc);
131             LOG.debug(outputString);
132         }
133 
134         try {
135             verify(signedDoc);
136             fail("Failure expected on multiple elements with the same wsu:Id");
137         } catch (WSSecurityException ex) {
138             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILED_CHECK);
139             assertTrue(ex.getMessage().startsWith("javax.xml.crypto.URIReferenceException: " +
140                     "org.apache.xml.security.utils.resolver.ResourceResolverException: "));
141         }
142     }
143 
144 
145     /**
146      * Test that signs a SOAP body element "value". The SOAP request is then modified
147      * so that the signed "value" element is put in the header, and the value of the
148      * original element is changed. The wsu:Id value of the original element is also
149      * changed. Signature verification will pass, so we need to check the Elements.
150      */
151     @Test
152     public void testMovedElementChangedId() throws Exception {
153         Document doc = SOAPUtil.toSOAPPart(SOAPMSG);
154         WSSecHeader secHeader = new WSSecHeader(doc);
155         secHeader.insertSecurityHeader();
156 
157         WSSecSignature builder = new WSSecSignature(secHeader);
158         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
159         LOG.info("Before Signing....");
160 
161         WSEncryptionPart encP =
162             new WSEncryptionPart(
163                 "value",
164                 "http://blah.com",
165                 "");
166         builder.getParts().add(encP);
167 
168         Document signedDoc = builder.build(crypto);
169 
170         //
171         // Replace the signed element with a modified element, and move the original
172         // signed element into the SOAP header
173         //
174         Element secHeaderElement = secHeader.getSecurityHeaderElement();
175         Element envelopeElement = signedDoc.getDocumentElement();
176         Node valueNode =
177             envelopeElement.getElementsByTagNameNS("http://blah.com", "value").item(0);
178         Node clonedValueNode = valueNode.cloneNode(true);
179         secHeaderElement.appendChild(clonedValueNode);
180         valueNode.getFirstChild().setNodeValue("250");
181         ((Element)valueNode).setAttributeNS(
182              WSConstants.WSU_NS, "wsu:Id", "id-250"
183         );
184 
185         if (LOG.isDebugEnabled()) {
186             LOG.debug("After Signing....");
187             String outputString =
188                 XMLUtils.prettyDocumentToString(signedDoc);
189             LOG.debug(outputString);
190         }
191 
192         //
193         // Check the signature...this should pass
194         //
195         WSHandlerResult results = verify(signedDoc);
196 
197         //
198         // Finally we need to check that the Element that was signed is what we expect to be signed
199         //
200         envelopeElement = signedDoc.getDocumentElement();
201         Node bodyNode =
202             envelopeElement.getElementsByTagNameNS(
203                 WSConstants.URI_SOAP11_ENV, "Body"
204             ).item(0);
205         valueNode =
206             ((Element)bodyNode).getElementsByTagNameNS(
207                 "http://blah.com", "value"
208             ).item(0);
209 
210         List<WSSecurityEngineResult> signedResults =
211             results.getActionResults().get(WSConstants.SIGN);
212         try {
213             SignatureUtils.verifySignedElement((Element)valueNode, signedResults);
214             fail("Failure expected on the required element not being signed");
215         } catch (WSSecurityException ex) {
216             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILED_CHECK);
217         }
218     }
219 
220     /**
221      * Test a duplicated signed SAML Assertion.
222      */
223     @Test
224     public void testDuplicatedSignedSAMLAssertion() throws Exception {
225         SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
226         callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
227         callbackHandler.setConfirmationMethod(SAML1Constants.CONF_SENDER_VOUCHES);
228         callbackHandler.setIssuer("www.example.com");
229 
230         SAMLCallback samlCallback = new SAMLCallback();
231         SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
232         SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
233 
234         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
235         WSSecHeader secHeader = new WSSecHeader(doc);
236         secHeader.insertSecurityHeader();
237 
238         WSSecSignatureSAML wsSign = new WSSecSignatureSAML(secHeader);
239         wsSign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
240 
241         Document signedDoc =
242             wsSign.build(
243                  null, samlAssertion, crypto, "16c73ab6-b892-458f-abf5-2f875f74882e", "security"
244             );
245         Element assertionElement = (Element) samlAssertion.getElement().cloneNode(true);
246         assertionElement.removeChild(assertionElement.getFirstChild());
247         secHeader.getSecurityHeaderElement().appendChild(assertionElement);
248 
249         if (LOG.isDebugEnabled()) {
250             LOG.debug("SAML 1.1 Authn Assertion (sender vouches):");
251             String outputString =
252                 XMLUtils.prettyDocumentToString(signedDoc);
253             LOG.debug(outputString);
254         }
255 
256         try {
257             verify(signedDoc);
258             fail("Failure expected on duplicate tokens");
259         } catch (WSSecurityException ex) {
260             assertTrue(ex.getMessage().contains(
261                 "Multiple security tokens with the same Id have been detected"
262             ));
263         }
264     }
265 
266     /**
267      * Test a duplicated signed UsernameToken
268      */
269     @Test
270     public void testDuplicatedSignedUsernameToken() throws Exception {
271         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
272         WSSecHeader secHeader = new WSSecHeader(doc);
273         secHeader.insertSecurityHeader();
274 
275         WSSecUsernameToken usernameToken = new WSSecUsernameToken(secHeader);
276         usernameToken.setUserInfo("wss86", "security");
277         usernameToken.build();
278 
279         WSSecSignature builder = new WSSecSignature(secHeader);
280         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
281 
282         WSEncryptionPart encP =
283             new WSEncryptionPart(
284                 "UsernameToken",
285                 WSConstants.WSSE_NS,
286                 "");
287         builder.getParts().add(encP);
288 
289         builder.prepare(crypto);
290 
291         List<javax.xml.crypto.dsig.Reference> referenceList =
292             builder.addReferencesToSign(builder.getParts());
293 
294         builder.computeSignature(referenceList, false, null);
295 
296         secHeader.getSecurityHeaderElement().appendChild(
297             usernameToken.getUsernameTokenElement().cloneNode(true)
298         );
299 
300         if (LOG.isDebugEnabled()) {
301             LOG.debug("Signed Timestamp");
302             String outputString =
303                 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      * Test for when an EncryptedData structure is modified
319      */
320     @Test
321     public void testModifiedEncryptedDataStructure() throws Exception {
322         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
323         WSSecHeader secHeader = new WSSecHeader(doc);
324         secHeader.insertSecurityHeader();
325 
326         WSSecEncrypt builder = new WSSecEncrypt(secHeader);
327         builder.setUserInfo("wss40");
328         builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
329         builder.setSymmetricEncAlgorithm(WSConstants.TRIPLE_DES);
330 
331         Crypto wssCrypto = CryptoFactory.getInstance("wss40.properties");
332         KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.TRIPLE_DES);
333         SecretKey symmetricKey = keyGen.generateKey();
334         Document encryptedDoc = builder.build(wssCrypto, symmetricKey);
335 
336         Element body = WSSecurityUtil.findBodyElement(doc);
337         Element encryptionMethod =
338             XMLUtils.findElement(body, "EncryptionMethod", WSConstants.ENC_NS);
339         encryptionMethod.setAttributeNS(null, "Algorithm", "http://new-algorithm");
340 
341         String outputString =
342             XMLUtils.prettyDocumentToString(encryptedDoc);
343         if (LOG.isDebugEnabled()) {
344             LOG.debug(outputString);
345         }
346 
347         WSSecurityEngine newEngine = new WSSecurityEngine();
348         try {
349             newEngine.processSecurityHeader(doc, null, new KeystoreCallbackHandler(), wssCrypto);
350             fail("Failure expected on a modified EncryptedData structure");
351         } catch (WSSecurityException ex) {
352             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
353         }
354     }
355 
356     /**
357      * Test for when some EncryptedData CipherValue data is modified.
358      */
359     @Test
360     public void testModifiedEncryptedDataCipherValue() throws Exception {
361         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
362         WSSecHeader secHeader = new WSSecHeader(doc);
363         secHeader.insertSecurityHeader();
364 
365         WSSecEncrypt builder = new WSSecEncrypt(secHeader);
366         builder.setUserInfo("wss40");
367         builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
368         builder.setSymmetricEncAlgorithm(WSConstants.TRIPLE_DES);
369 
370         Crypto wssCrypto = CryptoFactory.getInstance("wss40.properties");
371         KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.TRIPLE_DES);
372         SecretKey symmetricKey = keyGen.generateKey();
373         Document encryptedDoc = builder.build(wssCrypto, symmetricKey);
374 
375         Element body = WSSecurityUtil.findBodyElement(doc);
376         Element cipherValue =
377             XMLUtils.findElement(body, "CipherValue", WSConstants.ENC_NS);
378         String cipherText = cipherValue.getTextContent();
379 
380         StringBuilder stringBuilder = new StringBuilder(cipherText);
381         int index = stringBuilder.length() / 2;
382         char ch = stringBuilder.charAt(index);
383         if (ch != 'A') {
384             ch = 'A';
385         } else {
386             ch = 'B';
387         }
388         stringBuilder.setCharAt(index, ch);
389         cipherValue.setTextContent(stringBuilder.toString());
390 
391         String outputString =
392             XMLUtils.prettyDocumentToString(encryptedDoc);
393         if (LOG.isDebugEnabled()) {
394             LOG.debug(outputString);
395         }
396 
397         WSSecurityEngine newEngine = new WSSecurityEngine();
398         try {
399             newEngine.processSecurityHeader(doc, null, new KeystoreCallbackHandler(), wssCrypto);
400             fail("Failure expected on a modified EncryptedData CipherValue");
401         } catch (WSSecurityException ex) {
402             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILED_CHECK);
403         }
404     }
405 
406     /**
407      * Test for when some EncryptedData CipherValue data is modified
408      * (in the security header)
409      */
410     @Test
411     public void testModifiedSecurityHeaderEncryptedDataCipherValue() throws Exception {
412         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
413         WSSecHeader secHeader = new WSSecHeader(doc);
414         secHeader.insertSecurityHeader();
415 
416         WSSecEncrypt builder = new WSSecEncrypt(secHeader);
417         builder.setUserInfo("wss40");
418         builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
419         builder.setSymmetricEncAlgorithm(WSConstants.TRIPLE_DES);
420 
421         Crypto wssCrypto = CryptoFactory.getInstance("wss40.properties");
422 
423         WSSecTimestamp timestamp = new WSSecTimestamp(secHeader);
424         timestamp.setTimeToLive(300);
425         timestamp.build();
426 
427         WSEncryptionPart encP =
428             new WSEncryptionPart(
429                 "Timestamp",
430                 WSConstants.WSU_NS,
431                 "");
432         builder.getParts().add(encP);
433 
434         KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.TRIPLE_DES);
435         SecretKey symmetricKey = keyGen.generateKey();
436         Document encryptedDoc = builder.build(wssCrypto, symmetricKey);
437 
438         Element securityHeader =
439             WSSecurityUtil.getSecurityHeader(encryptedDoc, "");
440         Element encryptedTimestamp =
441             XMLUtils.findElement(securityHeader, "EncryptedData", WSConstants.ENC_NS);
442         Element cipherValue =
443             XMLUtils.findElement(encryptedTimestamp, "CipherValue", WSConstants.ENC_NS);
444         String cipherText = cipherValue.getTextContent();
445 
446         StringBuilder stringBuilder = new StringBuilder(cipherText);
447         int index = stringBuilder.length() / 2;
448         char ch = stringBuilder.charAt(index);
449         if (ch != 'A') {
450             ch = 'A';
451         } else {
452             ch = 'B';
453         }
454         stringBuilder.setCharAt(index, ch);
455         cipherValue.setTextContent(stringBuilder.toString());
456 
457         String outputString =
458             XMLUtils.prettyDocumentToString(encryptedDoc);
459         if (LOG.isDebugEnabled()) {
460             LOG.debug(outputString);
461         }
462 
463         WSSecurityEngine newEngine = new WSSecurityEngine();
464         try {
465             newEngine.processSecurityHeader(doc, null, new KeystoreCallbackHandler(), wssCrypto);
466             fail("Failure expected on a modified EncryptedData CipherValue");
467         } catch (WSSecurityException ex) {
468             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILED_CHECK);
469         }
470     }
471 
472     /**
473      * Test for when some EncryptedKey CipherValue data is modified.
474      */
475     @Test
476     public void testModifiedEncryptedKeyCipherValue() throws Exception {
477         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
478         WSSecHeader secHeader = new WSSecHeader(doc);
479         secHeader.insertSecurityHeader();
480 
481         WSSecEncrypt builder = new WSSecEncrypt(secHeader);
482         builder.setUserInfo("wss40");
483         builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
484         builder.setSymmetricEncAlgorithm(WSConstants.TRIPLE_DES);
485 
486         Crypto wssCrypto = CryptoFactory.getInstance("wss40.properties");
487         KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.TRIPLE_DES);
488         SecretKey symmetricKey = keyGen.generateKey();
489         Document encryptedDoc = builder.build(wssCrypto, symmetricKey);
490 
491         Element encryptedKey =
492             XMLUtils.findElement(doc.getDocumentElement(), "EncryptedKey", WSConstants.ENC_NS);
493         Element cipherValue =
494             XMLUtils.findElement(encryptedKey, "CipherValue", WSConstants.ENC_NS);
495         String cipherText = cipherValue.getTextContent();
496 
497         StringBuilder stringBuilder = new StringBuilder(cipherText);
498         int index = stringBuilder.length() / 2;
499         char ch = stringBuilder.charAt(index);
500         if (ch != 'A') {
501             ch = 'A';
502         } else {
503             ch = 'B';
504         }
505         stringBuilder.setCharAt(index, ch);
506         cipherValue.setTextContent(stringBuilder.toString());
507 
508         String outputString =
509             XMLUtils.prettyDocumentToString(encryptedDoc);
510         if (LOG.isDebugEnabled()) {
511             LOG.debug(outputString);
512         }
513 
514         WSSecurityEngine newEngine = new WSSecurityEngine();
515         try {
516             newEngine.processSecurityHeader(doc, null, new KeystoreCallbackHandler(), wssCrypto);
517             fail("Failure expected on a modified EncryptedData CipherValue");
518         } catch (WSSecurityException ex) {
519             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILED_CHECK);
520         }
521     }
522 
523 
524 
525     /**
526      * Test for when an element that a Signature Reference points to is modified
527      */
528     @Test
529     public void testModifiedSignatureReference() throws Exception {
530         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
531         WSSecHeader secHeader = new WSSecHeader(doc);
532         secHeader.insertSecurityHeader();
533 
534         WSSecSignature builder = new WSSecSignature(secHeader);
535         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
536 
537         WSSecTimestamp timestamp = new WSSecTimestamp(secHeader);
538         timestamp.setTimeToLive(300);
539         timestamp.build();
540 
541         WSEncryptionPart encP =
542             new WSEncryptionPart(
543                 "Timestamp",
544                 WSConstants.WSU_NS,
545                 "");
546         builder.getParts().add(encP);
547 
548         Document signedDoc = builder.build(crypto);
549 
550         // Modify the Created text of the Timestamp element
551         Element timestampElement = timestamp.getElement();
552         Element createdValue =
553             XMLUtils.findElement(timestampElement, "Created", WSConstants.WSU_NS);
554 
555         // Add 5 seconds
556         ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC).plusSeconds(5L);
557         createdValue.setTextContent(DateUtil.getDateTimeFormatter(true).format(now));
558 
559         if (LOG.isDebugEnabled()) {
560             String outputString =
561                 XMLUtils.prettyDocumentToString(signedDoc);
562             LOG.debug(outputString);
563         }
564 
565         try {
566             verify(signedDoc);
567             fail("Failure expected on a modified Signature Reference");
568         } catch (WSSecurityException ex) {
569             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILED_CHECK);
570         }
571     }
572 
573     /**
574      * Test for when a Signature is received with a certificate that is not trusted
575      */
576     @Test
577     public void testUntrustedSignature() throws Exception {
578         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
579         WSSecHeader secHeader = new WSSecHeader(doc);
580         secHeader.insertSecurityHeader();
581 
582         WSSecSignature builder = new WSSecSignature(secHeader);
583         builder.setUserInfo("wss40", "security");
584 
585         Crypto wss40Crypto = CryptoFactory.getInstance("wss40.properties");
586         Document signedDoc = builder.build(wss40Crypto);
587 
588         if (LOG.isDebugEnabled()) {
589             String outputString =
590                 XMLUtils.prettyDocumentToString(signedDoc);
591             LOG.debug(outputString);
592         }
593 
594         try {
595             verify(signedDoc);
596             fail("Failure expected on an untrusted Certificate");
597         } catch (WSSecurityException ex) {
598             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILED_CHECK);
599         }
600     }
601 
602     /**
603      * Test for when the Signature element is modified
604      */
605     @Test
606     public void testModifiedSignature() throws Exception {
607         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
608         WSSecHeader secHeader = new WSSecHeader(doc);
609         secHeader.insertSecurityHeader();
610 
611         WSSecSignature builder = new WSSecSignature(secHeader);
612         builder.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
613 
614         Document signedDoc = builder.build(crypto);
615 
616         // Modify the Signature element
617         Element signatureElement = builder.getSignatureElement();
618         Node firstChild = signatureElement.getFirstChild();
619         while (!(firstChild instanceof Element) && firstChild != null) {
620             firstChild = signatureElement.getNextSibling();
621         }
622         ((Element)firstChild).setAttributeNS(null, "Id", "xyz");
623 
624         if (LOG.isDebugEnabled()) {
625             String outputString =
626                 XMLUtils.prettyDocumentToString(signedDoc);
627             LOG.debug(outputString);
628         }
629 
630         try {
631             verify(signedDoc);
632             fail("Failure expected on a modified Signature element");
633         } catch (WSSecurityException ex) {
634             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILED_CHECK);
635         }
636     }
637 
638     /**
639      * Verifies the soap envelope
640      * <p/>
641      *
642      * @param doc soap envelope
643      * @throws Exception Thrown when there is a problem in verification
644      */
645     private WSHandlerResult verify(Document doc) throws Exception {
646         return secEngine.processSecurityHeader(doc, null, callbackHandler, crypto);
647     }
648 
649 }