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.SOAPConstants;
23 import org.apache.ws.security.WSDataRef;
24 import org.apache.ws.security.WSEncryptionPart;
25 import org.apache.ws.security.WSSConfig;
26 import org.apache.ws.security.WSSecurityEngine;
27 import org.apache.ws.security.WSConstants;
28 import org.apache.ws.security.WSSecurityEngineResult;
29 import org.apache.ws.security.WSSecurityException;
30 import org.apache.ws.security.common.SAML1CallbackHandler;
31 import org.apache.ws.security.common.SOAPUtil;
32 import org.apache.ws.security.components.crypto.Crypto;
33 import org.apache.ws.security.components.crypto.CryptoFactory;
34 import org.apache.ws.security.components.crypto.Merlin;
35 import org.apache.ws.security.saml.SAMLIssuer;
36 import org.apache.ws.security.saml.SAMLIssuerImpl;
37 import org.apache.ws.security.saml.SignedSamlTokenHOKTest;
38 import org.apache.ws.security.saml.WSSecSignatureSAML;
39 import org.apache.ws.security.saml.ext.AssertionWrapper;
40 import org.apache.ws.security.saml.ext.builder.SAML1Constants;
41 import org.apache.ws.security.util.Loader;
42 import org.apache.ws.security.util.WSSecurityUtil;
43 import org.w3c.dom.Document;
44 import org.w3c.dom.Element;
45
46 import java.io.InputStream;
47 import java.security.KeyStore;
48 import java.util.List;
49 import java.util.ArrayList;
50 import javax.xml.namespace.QName;
51
52
53
54
55
56 public class SignaturePartsTest extends org.junit.Assert {
57 private static final org.apache.commons.logging.Log LOG =
58 org.apache.commons.logging.LogFactory.getLog(SignaturePartsTest.class);
59 private static final String SOAPMSG = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
60 "<soapenv:Envelope xmlns:foo=\"urn:foo.bar\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" +
61 " <soapenv:Header>" +
62 " <foo:foobar>baz</foo:foobar>" +
63 " </soapenv:Header>" +
64 " <soapenv:Body>" +
65 " <ns1:testMethod xmlns:ns1=\"http://axis/service/security/test6/LogTestService8\"></ns1:testMethod>" +
66 " </soapenv:Body>" +
67 "</soapenv:Envelope>";
68 private static final String SOAPMSG_MULTIPLE = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
69 "<soapenv:Envelope xmlns:foo=\"urn:foo.bar\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" +
70 " <soapenv:Header>" +
71 " <foo:foobar>baz</foo:foobar>" +
72 " </soapenv:Header>" +
73 " <soapenv:Body>" +
74 " <ns1:testMethod xmlns:ns1=\"http://axis/service/security/test6/LogTestService8\">asf1</ns1:testMethod>" +
75 " <ns1:testMethod xmlns:ns1=\"http://axis/service/security/test6/LogTestService8\">asf2</ns1:testMethod>" +
76 " </soapenv:Body>" +
77 "</soapenv:Envelope>";
78
79 private WSSecurityEngine secEngine = new WSSecurityEngine();
80 private Crypto crypto = null;
81
82 public SignaturePartsTest() throws Exception {
83 WSSConfig.init();
84 crypto = CryptoFactory.getInstance();
85 }
86
87
88
89
90 @SuppressWarnings("unchecked")
91 @org.junit.Test
92 public void testSOAPHeader() throws Exception {
93 WSSecSignature sign = new WSSecSignature();
94 sign.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
95 sign.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
96
97 Document doc = SOAPUtil.toSOAPPart(SOAPMSG);
98
99 WSSecHeader secHeader = new WSSecHeader();
100 secHeader.insertSecurityHeader(doc);
101
102 List<WSEncryptionPart> parts = new ArrayList<WSEncryptionPart>();
103 WSEncryptionPart encP =
104 new WSEncryptionPart(
105 "foobar",
106 "urn:foo.bar",
107 "");
108 parts.add(encP);
109 sign.setParts(parts);
110
111 Document signedDoc = sign.build(doc, crypto, secHeader);
112
113 if (LOG.isDebugEnabled()) {
114 String outputString =
115 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
116 LOG.debug(outputString);
117 }
118
119 List<WSSecurityEngineResult> results = verify(signedDoc);
120
121 QName name = new QName("urn:foo.bar", "foobar");
122 WSSecurityUtil.checkAllElementsProtected(results, WSConstants.SIGN, new QName[]{name});
123 try {
124 name = new QName("urn:foo.bar", "foobar2");
125 WSSecurityUtil.checkAllElementsProtected(results, WSConstants.SIGN, new QName[]{name});
126 fail("Failure expected on a wrong protected part");
127 } catch (WSSecurityException ex) {
128
129 }
130 try {
131 name = new QName("urn:foo.bar", "foobar");
132 WSSecurityUtil.checkAllElementsProtected(results, WSConstants.ENCR, new QName[]{name});
133 fail("Failure expected on a wrong action");
134 } catch (WSSecurityException ex) {
135
136 }
137
138 WSSecurityEngineResult actionResult =
139 WSSecurityUtil.fetchActionResult(results, WSConstants.SIGN);
140 assertTrue(actionResult != null);
141 assertFalse(actionResult.isEmpty());
142 final List<WSDataRef> refs =
143 (List<WSDataRef>) actionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
144
145 WSDataRef wsDataRef = (WSDataRef)refs.get(0);
146 String xpath = wsDataRef.getXpath();
147 assertEquals("/soapenv:Envelope/soapenv:Header/foo:foobar", xpath);
148 assertEquals(WSConstants.RSA_SHA1, wsDataRef.getAlgorithm());
149
150 assertEquals(WSConstants.SHA1, wsDataRef.getDigestAlgorithm());
151
152 String sigMethod = (String)actionResult.get(WSSecurityEngineResult.TAG_SIGNATURE_METHOD);
153 assertEquals(WSConstants.RSA_SHA1, sigMethod);
154
155 String c14nMethod =
156 (String)actionResult.get(WSSecurityEngineResult.TAG_CANONICALIZATION_METHOD);
157 assertEquals(WSConstants.C14N_EXCL_OMIT_COMMENTS, c14nMethod);
158
159 List<String> transformAlgorithms = wsDataRef.getTransformAlgorithms();
160 assertTrue(transformAlgorithms.size() == 1);
161 assertTrue(WSConstants.C14N_EXCL_OMIT_COMMENTS.equals(transformAlgorithms.get(0)));
162 }
163
164
165
166
167 @SuppressWarnings("unchecked")
168 @org.junit.Test
169 public void testSOAPHeaderSTRTransform() throws Exception {
170
171 Crypto issuerCrypto = new Merlin();
172 KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
173 ClassLoader loader = Loader.getClassLoader(SignedSamlTokenHOKTest.class);
174 InputStream input = Merlin.loadInputStream(loader, "keys/wss40_server.jks");
175 keyStore.load(input, "security".toCharArray());
176 ((Merlin)issuerCrypto).setKeyStore(keyStore);
177
178 Crypto userCrypto = CryptoFactory.getInstance("wss40.properties");
179
180 SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
181 callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
182 callbackHandler.setConfirmationMethod(SAML1Constants.CONF_HOLDER_KEY);
183 SAMLIssuer saml = new SAMLIssuerImpl();
184 saml.setIssuerName("www.example.com");
185 saml.setIssuerCrypto(issuerCrypto);
186 saml.setIssuerKeyName("wss40_server");
187 saml.setIssuerKeyPassword("security");
188 saml.setSignAssertion(true);
189 saml.setCallbackHandler(callbackHandler);
190 AssertionWrapper assertion = saml.newAssertion();
191
192 WSSecSignatureSAML wsSign = new WSSecSignatureSAML();
193 wsSign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
194 wsSign.setUserInfo("wss40", "security");
195
196 Document doc = SOAPUtil.toSOAPPart(SOAPMSG);
197 WSSecHeader secHeader = new WSSecHeader();
198 secHeader.insertSecurityHeader(doc);
199
200 List<WSEncryptionPart> parts = new ArrayList<WSEncryptionPart>();
201 WSEncryptionPart encP =
202 new WSEncryptionPart("STRTransform", "", "Element");
203 parts.add(encP);
204 wsSign.setParts(parts);
205
206
207
208
209 Document signedDoc = wsSign.build(doc, userCrypto, assertion, null, null, null, secHeader);
210
211 if (LOG.isDebugEnabled()) {
212 LOG.debug("Signed SAML message (key holder):");
213 String outputString =
214 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
215 LOG.debug(outputString);
216 }
217
218
219 Crypto trustCrypto = new Merlin();
220 KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
221 input = Merlin.loadInputStream(loader, "keys/wss40CA.jks");
222 trustStore.load(input, "security".toCharArray());
223 ((Merlin)trustCrypto).setTrustStore(trustStore);
224
225 List<WSSecurityEngineResult> results =
226 secEngine.processSecurityHeader(doc, null, null, trustCrypto);
227 WSSecurityEngineResult stUnsignedActionResult =
228 WSSecurityUtil.fetchActionResult(results, WSConstants.ST_SIGNED);
229 AssertionWrapper receivedAssertion =
230 (AssertionWrapper) stUnsignedActionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
231 assertTrue(receivedAssertion != null);
232 assertTrue(receivedAssertion.isSigned());
233
234 WSSecurityEngineResult signActionResult =
235 WSSecurityUtil.fetchActionResult(results, WSConstants.SIGN);
236 assertTrue(signActionResult != null);
237 assertFalse(signActionResult.isEmpty());
238 final List<WSDataRef> refs =
239 (List<WSDataRef>) signActionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
240
241 WSDataRef wsDataRef = (WSDataRef)refs.get(0);
242 String xpath = wsDataRef.getXpath();
243 assertEquals("/soapenv:Envelope/soapenv:Header/wsse:Security/saml1:Assertion", xpath);
244 }
245
246
247
248
249 @org.junit.Test
250 public void testBadLocalname() throws Exception {
251 WSSecSignature sign = new WSSecSignature();
252 sign.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
253 sign.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
254
255 Document doc = SOAPUtil.toSOAPPart(SOAPMSG);
256
257 WSSecHeader secHeader = new WSSecHeader();
258 secHeader.insertSecurityHeader(doc);
259
260 List<WSEncryptionPart> parts = new ArrayList<WSEncryptionPart>();
261 WSEncryptionPart encP =
262 new WSEncryptionPart(
263 "foobar2",
264 "urn:foo.bar",
265 "");
266 parts.add(encP);
267 sign.setParts(parts);
268
269 try {
270 sign.build(doc, crypto, secHeader);
271 fail("Failure expected on a bad localname");
272 } catch (WSSecurityException ex) {
273
274 }
275 }
276
277
278
279
280 @org.junit.Test
281 public void testBadNamespace() throws Exception {
282 WSSecSignature sign = new WSSecSignature();
283 sign.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
284 sign.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
285
286 Document doc = SOAPUtil.toSOAPPart(SOAPMSG);
287
288 WSSecHeader secHeader = new WSSecHeader();
289 secHeader.insertSecurityHeader(doc);
290
291 List<WSEncryptionPart> parts = new ArrayList<WSEncryptionPart>();
292 WSEncryptionPart encP =
293 new WSEncryptionPart(
294 "foobar",
295 "urn:foo.bar2",
296 "");
297 parts.add(encP);
298 sign.setParts(parts);
299
300 try {
301 sign.build(doc, crypto, secHeader);
302 fail("Failure expected on a bad namespace");
303 } catch (WSSecurityException ex) {
304
305 }
306 }
307
308
309
310
311 @org.junit.Test
312 public void testSOAPHeaderAndBody() throws Exception {
313 WSSecSignature sign = new WSSecSignature();
314 sign.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
315 sign.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
316
317 Document doc = SOAPUtil.toSOAPPart(SOAPMSG);
318 SOAPConstants soapConstants =
319 WSSecurityUtil.getSOAPConstants(doc.getDocumentElement());
320
321 WSSecHeader secHeader = new WSSecHeader();
322 secHeader.insertSecurityHeader(doc);
323
324 List<WSEncryptionPart> parts = new ArrayList<WSEncryptionPart>();
325 WSEncryptionPart encP =
326 new WSEncryptionPart(
327 soapConstants.getBodyQName().getLocalPart(),
328 soapConstants.getEnvelopeURI(),
329 "");
330 parts.add(encP);
331 WSEncryptionPart encP2 =
332 new WSEncryptionPart(
333 "foobar",
334 "urn:foo.bar",
335 "");
336 parts.add(encP2);
337 sign.setParts(parts);
338
339 Document signedDoc = sign.build(doc, crypto, secHeader);
340
341 if (LOG.isDebugEnabled()) {
342 String outputString =
343 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
344 LOG.debug(outputString);
345 }
346
347 List<WSSecurityEngineResult> results = verify(signedDoc);
348
349 QName fooName = new QName("urn:foo.bar", "foobar");
350 QName bodyName = new QName(soapConstants.getEnvelopeURI(), "Body");
351 WSSecurityUtil.checkAllElementsProtected(results, WSConstants.SIGN, new QName[]{fooName});
352 WSSecurityUtil.checkAllElementsProtected(results, WSConstants.SIGN, new QName[]{bodyName});
353 WSSecurityUtil.checkAllElementsProtected(
354 results,
355 WSConstants.SIGN,
356 new QName[]{bodyName, fooName}
357 );
358 WSSecurityUtil.checkAllElementsProtected(
359 results,
360 WSConstants.SIGN,
361 new QName[]{fooName, bodyName}
362 );
363 try {
364 WSSecurityUtil.checkAllElementsProtected(
365 results,
366 WSConstants.ENCR,
367 new QName[]{fooName, bodyName}
368 );
369 fail("Failure expected on a wrong action");
370 } catch (WSSecurityException ex) {
371
372 }
373 try {
374 QName headerName = new QName(soapConstants.getEnvelopeURI(), "Header");
375 WSSecurityUtil.checkAllElementsProtected(
376 results,
377 WSConstants.SIGN,
378 new QName[]{fooName, bodyName, headerName}
379 );
380 fail("Failure expected on an unsatisfied requirement");
381 } catch (WSSecurityException ex) {
382
383 }
384 }
385
386
387
388
389
390 @org.junit.Test
391 public void testSignaturePartDOMElement() throws Exception {
392 WSSecSignature sign = new WSSecSignature();
393 sign.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
394 sign.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
395
396 Document doc = SOAPUtil.toSOAPPart(SOAPMSG);
397 SOAPConstants soapConstants =
398 WSSecurityUtil.getSOAPConstants(doc.getDocumentElement());
399
400 WSSecHeader secHeader = new WSSecHeader();
401 secHeader.insertSecurityHeader(doc);
402
403 List<WSEncryptionPart> parts = new ArrayList<WSEncryptionPart>();
404
405 WSEncryptionPart encP =
406 new WSEncryptionPart(
407 "Incorrect Localname",
408 "Incorrect N/S",
409 "");
410 Element bodyElement = WSSecurityUtil.findBodyElement(doc);
411 assertTrue(bodyElement != null && "Body".equals(bodyElement.getLocalName()));
412 encP.setElement(bodyElement);
413 parts.add(encP);
414 sign.setParts(parts);
415
416 Document signedDoc = sign.build(doc, crypto, secHeader);
417
418 if (LOG.isDebugEnabled()) {
419 String outputString =
420 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
421 LOG.debug(outputString);
422 }
423
424 List<WSSecurityEngineResult> results = verify(signedDoc);
425
426 QName bodyName = new QName(soapConstants.getEnvelopeURI(), "Body");
427 WSSecurityUtil.checkAllElementsProtected(results, WSConstants.SIGN, new QName[]{bodyName});
428 }
429
430
431
432
433 @org.junit.Test
434 public void testMultipleElements() throws Exception {
435 Document doc = SOAPUtil.toSOAPPart(SOAPMSG_MULTIPLE);
436 WSSecSignature sign = new WSSecSignature();
437 sign.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
438 sign.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
439
440 WSSecHeader secHeader = new WSSecHeader();
441 secHeader.insertSecurityHeader(doc);
442
443 List<WSEncryptionPart> parts = new ArrayList<WSEncryptionPart>();
444 WSEncryptionPart encP =
445 new WSEncryptionPart(
446 "testMethod",
447 "http://axis/service/security/test6/LogTestService8",
448 "");
449 parts.add(encP);
450 sign.setParts(parts);
451
452 Document signedDoc = sign.build(doc, crypto, secHeader);
453
454 String outputString =
455 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
456 if (LOG.isDebugEnabled()) {
457 LOG.debug(outputString);
458 }
459
460 verify(signedDoc);
461 }
462
463
464
465
466
467
468
469
470
471 private List<WSSecurityEngineResult> verify(Document doc) throws Exception {
472 List<WSSecurityEngineResult> results =
473 secEngine.processSecurityHeader(doc, null, null, crypto);
474 if (LOG.isDebugEnabled()) {
475 LOG.debug("Verfied and decrypted message:");
476 String outputString =
477 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
478 LOG.debug(outputString);
479 }
480 return results;
481 }
482
483 }