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.saml;
21
22 import org.apache.ws.security.WSConstants;
23 import org.apache.ws.security.WSSConfig;
24 import org.apache.ws.security.WSSecurityEngine;
25 import org.apache.ws.security.WSSecurityEngineResult;
26 import org.apache.ws.security.WSSecurityException;
27 import org.apache.ws.security.common.AbstractSAMLCallbackHandler;
28 import org.apache.ws.security.common.KeystoreCallbackHandler;
29 import org.apache.ws.security.common.SAML1CallbackHandler;
30 import org.apache.ws.security.common.SAML2CallbackHandler;
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.CryptoType;
35 import org.apache.ws.security.components.crypto.Merlin;
36 import org.apache.ws.security.message.WSSecHeader;
37 import org.apache.ws.security.message.WSSecSAMLToken;
38 import org.apache.ws.security.saml.ext.AssertionWrapper;
39 import org.apache.ws.security.saml.ext.SAMLCallback;
40 import org.apache.ws.security.saml.ext.SAMLParms;
41 import org.apache.ws.security.saml.ext.bean.SubjectBean;
42 import org.apache.ws.security.saml.ext.builder.SAML1Constants;
43 import org.apache.ws.security.saml.ext.builder.SAML2Constants;
44 import org.apache.ws.security.util.Loader;
45 import org.w3c.dom.Document;
46
47 import javax.security.auth.callback.Callback;
48 import javax.security.auth.callback.CallbackHandler;
49 import javax.security.auth.callback.UnsupportedCallbackException;
50
51 import java.io.IOException;
52 import java.io.InputStream;
53 import java.security.KeyStore;
54 import java.util.List;
55
56 import org.w3c.dom.Element;
57 import org.w3c.dom.NodeList;
58
59
60
61
62
63 public class SamlNegativeTest extends org.junit.Assert {
64 private static final org.apache.commons.logging.Log LOG =
65 org.apache.commons.logging.LogFactory.getLog(SamlNegativeTest.class);
66 private WSSecurityEngine secEngine = new WSSecurityEngine();
67 private CallbackHandler callbackHandler = new KeystoreCallbackHandler();
68 private Crypto trustCrypto = null;
69 private Crypto issuerCrypto = null;
70 private Crypto userCrypto = CryptoFactory.getInstance("wss40.properties");
71
72 public SamlNegativeTest() throws Exception {
73 WSSConfig.init();
74
75 issuerCrypto = new Merlin();
76 KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
77 ClassLoader loader = Loader.getClassLoader(SamlNegativeTest.class);
78 InputStream input = Merlin.loadInputStream(loader, "keys/wss40_server.jks");
79 keyStore.load(input, "security".toCharArray());
80 ((Merlin)issuerCrypto).setKeyStore(keyStore);
81
82
83 trustCrypto = new Merlin();
84 KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
85 input = Merlin.loadInputStream(loader, "keys/wss40CA.jks");
86 trustStore.load(input, "security".toCharArray());
87 ((Merlin)trustCrypto).setTrustStore(trustStore);
88 }
89
90
91
92
93
94
95 @org.junit.Test
96 public void testSAML2AuthnAssertionModified() throws Exception {
97 SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
98 callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
99 callbackHandler.setConfirmationMethod(SAML2Constants.CONF_SENDER_VOUCHES);
100 callbackHandler.setIssuer("www.example.com");
101
102 SAMLParms samlParms = new SAMLParms();
103 samlParms.setCallbackHandler(callbackHandler);
104 AssertionWrapper assertion = new AssertionWrapper(samlParms);
105
106 WSSecSignatureSAML wsSign = new WSSecSignatureSAML();
107 wsSign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
108
109 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
110 WSSecHeader secHeader = new WSSecHeader();
111 secHeader.insertSecurityHeader(doc);
112
113 Document signedDoc =
114 wsSign.build(
115 doc, null, assertion, userCrypto, "wss40", "security", secHeader
116 );
117
118
119
120
121 Element envelope = signedDoc.getDocumentElement();
122 NodeList list = envelope.getElementsByTagNameNS(WSConstants.SAML2_NS, "Assertion");
123 Element assertionElement = (org.w3c.dom.Element)list.item(0);
124 assertionElement.setAttributeNS(null, "MinorVersion", "5");
125
126 if (LOG.isDebugEnabled()) {
127 LOG.debug("SAML 2 Authn Assertion (sender vouches):");
128 String outputString =
129 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
130 LOG.debug(outputString);
131 }
132
133 try {
134 verify(signedDoc, trustCrypto);
135 fail("Failure expected on a modified SAML Assertion");
136 } catch (Exception ex) {
137
138 }
139 }
140
141
142
143
144
145
146
147 @org.junit.Test
148 public void testSAML1SignedKeyHolderSigModified() throws Exception {
149 SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
150 callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
151 callbackHandler.setConfirmationMethod(SAML1Constants.CONF_HOLDER_KEY);
152 callbackHandler.setIssuer("www.example.com");
153
154 SAMLParms samlParms = new SAMLParms();
155 samlParms.setCallbackHandler(callbackHandler);
156 AssertionWrapper assertion = new AssertionWrapper(samlParms);
157 assertion.signAssertion("wss40_server", "security", issuerCrypto, false);
158
159 WSSecSAMLToken wsSign = new WSSecSAMLToken();
160
161 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
162 WSSecHeader secHeader = new WSSecHeader();
163 secHeader.insertSecurityHeader(doc);
164
165 Document signedDoc = wsSign.build(doc, assertion, secHeader);
166
167
168
169
170 Element envelope = signedDoc.getDocumentElement();
171 NodeList list = envelope.getElementsByTagNameNS(WSConstants.SAML_NS, "Assertion");
172 Element assertionElement = (org.w3c.dom.Element)list.item(0);
173 list = assertionElement.getElementsByTagNameNS(WSConstants.SIG_NS, "Signature");
174 Element sigElement = (org.w3c.dom.Element)list.item(0);
175 list = sigElement.getElementsByTagNameNS(WSConstants.SIG_NS, "Transform");
176 Element transformElement = (org.w3c.dom.Element)list.item(0);
177 transformElement.setAttributeNS(null, "Algorithm", WSConstants.C14N_EXCL_OMIT_COMMENTS);
178
179 if (LOG.isDebugEnabled()) {
180 LOG.debug("Signed (modified) SAML message (key holder):");
181 String outputString =
182 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
183 LOG.debug(outputString);
184 }
185
186 try {
187 verify(signedDoc, trustCrypto);
188 fail("Expected failure on a modified signature");
189 } catch (WSSecurityException ex) {
190
191 }
192 }
193
194
195
196
197
198 @org.junit.Test
199 public void testSAML2SignedKeyHolderKeyModified() throws Exception {
200 SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
201 callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
202 callbackHandler.setConfirmationMethod(SAML2Constants.CONF_HOLDER_KEY);
203 callbackHandler.setIssuer("www.example.com");
204
205 SAMLParms samlParms = new SAMLParms();
206 samlParms.setCallbackHandler(callbackHandler);
207 AssertionWrapper assertion = new AssertionWrapper(samlParms);
208 assertion.signAssertion("wss40_server", "security", issuerCrypto, false);
209
210 WSSecSAMLToken wsSign = new WSSecSAMLToken();
211
212 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
213 WSSecHeader secHeader = new WSSecHeader();
214 secHeader.insertSecurityHeader(doc);
215
216 Document signedDoc = wsSign.build(doc, assertion, secHeader);
217
218
219
220 Element envelope = signedDoc.getDocumentElement();
221 NodeList list = envelope.getElementsByTagNameNS(WSConstants.SAML2_NS, "Assertion");
222 Element assertionElement = (org.w3c.dom.Element)list.item(0);
223 assertionElement.setAttributeNS(null, "MinorVersion", "5");
224
225 if (LOG.isDebugEnabled()) {
226 LOG.debug("Signed (modified) SAML message (key holder):");
227 String outputString =
228 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
229 LOG.debug(outputString);
230 }
231
232 try {
233 verify(signedDoc, trustCrypto);
234 fail("Expected failure on a modified signature");
235 } catch (WSSecurityException ex) {
236
237 }
238 }
239
240
241
242
243
244 @org.junit.Test
245 public void testHOKNoKeyInfo() throws Exception {
246 SAML1HOKNoKeyInfoCallbackHandler callbackHandler =
247 new SAML1HOKNoKeyInfoCallbackHandler();
248 callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
249 callbackHandler.setIssuer("www.example.com");
250
251 SAMLParms samlParms = new SAMLParms();
252 samlParms.setCallbackHandler(callbackHandler);
253 AssertionWrapper assertion = new AssertionWrapper(samlParms);
254 assertion.signAssertion("wss40_server", "security", issuerCrypto, false);
255
256 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
257 WSSecHeader secHeader = new WSSecHeader();
258 secHeader.insertSecurityHeader(doc);
259
260 WSSecSAMLToken wsSign = new WSSecSAMLToken();
261 Document signedDoc = wsSign.build(doc, assertion, secHeader);
262
263 String outputString =
264 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
265 if (LOG.isDebugEnabled()) {
266 LOG.debug("SAML 1.1 Authn Assertion (key holder):");
267 LOG.debug(outputString);
268 }
269
270 try {
271 verify(signedDoc, trustCrypto);
272 fail("Expected failure on a holder-of-key confirmation method with no KeyInfo");
273 } catch (WSSecurityException ex) {
274
275 }
276 }
277
278
279
280
281
282 @org.junit.Test
283 public void testHOKNotSigned() throws Exception {
284 SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
285 callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
286 callbackHandler.setConfirmationMethod(SAML1Constants.CONF_HOLDER_KEY);
287 SAMLIssuer saml = new SAMLIssuerImpl();
288 saml.setIssuerName("www.example.com");
289 saml.setIssuerCrypto(issuerCrypto);
290 saml.setIssuerKeyName("wss40_server");
291 saml.setIssuerKeyPassword("security");
292
293 saml.setCallbackHandler(callbackHandler);
294 AssertionWrapper assertion = saml.newAssertion();
295
296 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
297 WSSecHeader secHeader = new WSSecHeader();
298 secHeader.insertSecurityHeader(doc);
299
300 WSSecSAMLToken wsSign = new WSSecSAMLToken();
301 Document signedDoc = wsSign.build(doc, assertion, secHeader);
302
303 String outputString =
304 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
305 if (LOG.isDebugEnabled()) {
306 LOG.debug("SAML 1.1 Authn Assertion (unsigned key holder):");
307 LOG.debug(outputString);
308 }
309
310 try {
311 verify(signedDoc, trustCrypto);
312 fail("Expected failure on an unsigned assertion with holder-of-key confirmation method");
313 } catch (WSSecurityException ex) {
314
315 }
316 }
317
318
319
320
321
322 @org.junit.Test
323 public void testSAML2TrustFailure() throws Exception {
324 SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
325 callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
326 callbackHandler.setConfirmationMethod(SAML2Constants.CONF_HOLDER_KEY);
327 callbackHandler.setIssuer("www.example.com");
328
329 SAMLParms samlParms = new SAMLParms();
330 samlParms.setCallbackHandler(callbackHandler);
331 AssertionWrapper assertion = new AssertionWrapper(samlParms);
332 assertion.signAssertion(
333 "16c73ab6-b892-458f-abf5-2f875f74882e", "security",
334 CryptoFactory.getInstance("crypto.properties"), false
335 );
336
337 WSSecSignatureSAML wsSign = new WSSecSignatureSAML();
338 wsSign.setUserInfo("wss40", "security");
339 wsSign.setDigestAlgo("http://www.w3.org/2001/04/xmlenc#sha256");
340 wsSign.setSignatureAlgorithm("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
341 wsSign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
342
343 Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
344 WSSecHeader secHeader = new WSSecHeader();
345 secHeader.insertSecurityHeader(doc);
346
347 Document signedDoc =
348 wsSign.build(doc, userCrypto, assertion, null, null, null, secHeader);
349
350 String outputString =
351 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
352 if (LOG.isDebugEnabled()) {
353 LOG.debug("Untrusted signed SAML 2 Authn Assertion (key holder):");
354 LOG.debug(outputString);
355 }
356
357 try {
358 verify(signedDoc, trustCrypto);
359 fail ("Failure expected on an untrusted signed assertion");
360 } catch (WSSecurityException ex) {
361
362 }
363 }
364
365
366
367
368
369
370
371 private List<WSSecurityEngineResult> verify(Document doc, Crypto sigCrypto) throws Exception {
372 List<WSSecurityEngineResult> results =
373 secEngine.processSecurityHeader(
374 doc, null, callbackHandler, sigCrypto, userCrypto
375 );
376 String outputString =
377 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
378 assertTrue(outputString.indexOf("counter_port_type") > 0 ? true : false);
379 return results;
380 }
381
382
383
384
385
386 private static class SAML1HOKNoKeyInfoCallbackHandler extends AbstractSAMLCallbackHandler {
387
388 public SAML1HOKNoKeyInfoCallbackHandler() throws Exception {
389 Crypto crypto = CryptoFactory.getInstance("wss40.properties");
390 CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
391 cryptoType.setAlias("wss40");
392 certs = crypto.getX509Certificates(cryptoType);
393
394 subjectName = "uid=joe,ou=people,ou=saml-demo,o=example.com";
395 subjectQualifier = "www.example.com";
396 confirmationMethod = SAML1Constants.CONF_HOLDER_KEY;
397 }
398
399 public void handle(Callback[] callbacks)
400 throws IOException, UnsupportedCallbackException {
401 for (int i = 0; i < callbacks.length; i++) {
402 if (callbacks[i] instanceof SAMLCallback) {
403 SAMLCallback callback = (SAMLCallback) callbacks[i];
404 SubjectBean subjectBean =
405 new SubjectBean(
406 subjectName, subjectQualifier, confirmationMethod
407 );
408 createAndSetStatement(subjectBean, callback);
409 } else {
410 throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");
411 }
412 }
413 }
414 }
415
416 }