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.saml;
21  
22  import java.time.Duration;
23  import java.time.Instant;
24  import java.util.ArrayList;
25  import java.util.Collections;
26  import java.util.List;
27  
28  import javax.security.auth.callback.CallbackHandler;
29  
30  import org.apache.wss4j.common.ext.WSSecurityException;
31  import org.apache.wss4j.common.saml.SAMLCallback;
32  import org.apache.wss4j.common.saml.SAMLUtil;
33  import org.apache.wss4j.common.saml.SamlAssertionWrapper;
34  import org.apache.wss4j.common.saml.bean.AudienceRestrictionBean;
35  import org.apache.wss4j.common.saml.bean.ConditionsBean;
36  import org.apache.wss4j.common.saml.bean.DelegateBean;
37  import org.apache.wss4j.common.saml.bean.NameIDBean;
38  import org.apache.wss4j.common.saml.bean.ProxyRestrictionBean;
39  import org.apache.wss4j.common.saml.builder.SAML2Constants;
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.CustomSamlAssertionValidator;
44  import org.apache.wss4j.dom.common.SAML1CallbackHandler;
45  import org.apache.wss4j.dom.common.SAML2CallbackHandler;
46  
47  import org.apache.wss4j.dom.engine.WSSConfig;
48  import org.apache.wss4j.dom.engine.WSSecurityEngine;
49  import org.apache.wss4j.dom.handler.RequestData;
50  import org.apache.wss4j.dom.handler.WSHandlerResult;
51  import org.apache.wss4j.dom.message.WSSecHeader;
52  import org.apache.wss4j.dom.message.WSSecSAMLToken;
53  
54  import org.junit.jupiter.api.Test;
55  import org.w3c.dom.Document;
56  
57  import static org.junit.jupiter.api.Assertions.assertFalse;
58  import static org.junit.jupiter.api.Assertions.assertTrue;
59  import static org.junit.jupiter.api.Assertions.fail;
60  
61  /**
62   * Test-case for sending and processing an a SAML Token with a custom Conditions element.
63   */
64  public class SamlConditionsTest {
65      private static final org.slf4j.Logger LOG =
66          org.slf4j.LoggerFactory.getLogger(SamlConditionsTest.class);
67      private WSSecurityEngine secEngine = new WSSecurityEngine();
68  
69      public SamlConditionsTest() {
70          WSSConfig config = WSSConfig.getNewInstance();
71          config.setValidator(WSConstants.SAML_TOKEN, new CustomSamlAssertionValidator());
72          config.setValidator(WSConstants.SAML2_TOKEN, new CustomSamlAssertionValidator());
73          secEngine.setWssConfig(config);
74      }
75  
76      /**
77       * Test that creates, sends and processes an unsigned SAML 1.1 authentication assertion
78       * with a custom Conditions statement.
79       */
80      @Test
81      public void testSAML1Conditions() throws Exception {
82          SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
83          callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
84          callbackHandler.setIssuer("www.example.com");
85  
86          ConditionsBean conditions = new ConditionsBean();
87          Instant notBefore = Instant.now();
88          conditions.setNotBefore(notBefore);
89          conditions.setNotAfter(notBefore.plus(Duration.ofMinutes(20)));
90          callbackHandler.setConditions(conditions);
91  
92          createAndVerifyMessage(callbackHandler, true);
93      }
94  
95      /**
96       * Test that creates, sends and processes an unsigned SAML 2 authentication assertion
97       * with an (invalid) custom Conditions statement.
98       */
99      @Test
100     public void testSAML2InvalidAfterConditions() throws Exception {
101         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
102         callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
103         callbackHandler.setIssuer("www.example.com");
104 
105         ConditionsBean conditions = new ConditionsBean();
106         Instant notBefore = Instant.now();
107         conditions.setNotBefore(notBefore.minus(Duration.ofMinutes(5)));
108         conditions.setNotAfter(notBefore.minus(Duration.ofMinutes(3)));
109         callbackHandler.setConditions(conditions);
110 
111         createAndVerifyMessage(callbackHandler, false);
112     }
113 
114     @Test
115     public void testSAML2StaleNotOnOrAfter() throws Exception {
116         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
117         callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
118         callbackHandler.setIssuer("www.example.com");
119 
120         ConditionsBean conditions = new ConditionsBean();
121         Instant notBefore = Instant.now();
122         conditions.setNotAfter(notBefore.minus(Duration.ofMinutes(60)));
123         conditions.setNotBefore(notBefore.minus(Duration.ofMinutes(70)));
124         callbackHandler.setConditions(conditions);
125 
126         createAndVerifyMessage(callbackHandler, false);
127     }
128 
129     @Test
130     public void testSAML2FutureNotBefore() throws Exception {
131         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
132         callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
133         callbackHandler.setIssuer("www.example.com");
134 
135         ConditionsBean conditions = new ConditionsBean();
136         Instant notBefore = Instant.now();
137         conditions.setNotAfter(notBefore.plus(Duration.ofMinutes(70)));
138         conditions.setNotBefore(notBefore.plus(Duration.ofMinutes(60)));
139         callbackHandler.setConditions(conditions);
140 
141         createAndVerifyMessage(callbackHandler, false);
142     }
143 
144     @Test
145     public void testSAML2FutureIssueInstant() throws Exception {
146         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
147         callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
148         callbackHandler.setIssuer("www.example.com");
149 
150         SAMLCallback samlCallback = new SAMLCallback();
151         SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
152         SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
153 
154         Instant issueInstant = Instant.now();
155         issueInstant = issueInstant.plus(Duration.ofMinutes(60));
156         samlAssertion.getSaml2().setIssueInstant(issueInstant);
157 
158         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
159         WSSecHeader secHeader = new WSSecHeader(doc);
160         secHeader.insertSecurityHeader();
161 
162         WSSecSAMLToken wsSign = new WSSecSAMLToken(secHeader);
163 
164         Document unsignedDoc = wsSign.build(samlAssertion);
165 
166         if (LOG.isDebugEnabled()) {
167             LOG.debug("SAML 2 Authn Assertion (sender vouches):");
168             String outputString =
169                 XMLUtils.prettyDocumentToString(unsignedDoc);
170             LOG.debug(outputString);
171         }
172 
173         try {
174             verify(unsignedDoc);
175             fail("Failure expected in processing the SAML Conditions element");
176         } catch (WSSecurityException ex) {
177             assertTrue(ex.getMessage().contains("SAML token security failure"));
178         }
179     }
180 
181     @Test
182     public void testSAML2StaleIssueInstant() throws Exception {
183         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
184         callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
185         callbackHandler.setIssuer("www.example.com");
186 
187         SAMLCallback samlCallback = new SAMLCallback();
188         SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
189         SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
190 
191         Instant issueInstant = Instant.now();
192         issueInstant = issueInstant.minus(Duration.ofMinutes(31));
193         samlAssertion.getSaml2().setIssueInstant(issueInstant);
194         samlAssertion.getSaml2().getConditions().setNotOnOrAfter(null);
195 
196         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
197         WSSecHeader secHeader = new WSSecHeader(doc);
198         secHeader.insertSecurityHeader();
199 
200         WSSecSAMLToken wsSign = new WSSecSAMLToken(secHeader);
201 
202         Document unsignedDoc = wsSign.build(samlAssertion);
203 
204         if (LOG.isDebugEnabled()) {
205             LOG.debug("SAML 2 Authn Assertion (sender vouches):");
206             String outputString =
207                 XMLUtils.prettyDocumentToString(unsignedDoc);
208             LOG.debug(outputString);
209         }
210 
211         try {
212             verify(unsignedDoc);
213             fail("Failure expected in processing a stale SAML Assertion");
214         } catch (WSSecurityException ex) {
215             assertTrue(ex.getMessage().contains("SAML token security failure"));
216         }
217     }
218 
219     @Test
220     public void testSAML2NoNotOnOrAfter() throws Exception {
221         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
222         callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
223         callbackHandler.setIssuer("www.example.com");
224 
225         SAMLCallback samlCallback = new SAMLCallback();
226         SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
227         SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
228 
229         Instant issueInstant = Instant.now().minusSeconds(5);
230         samlAssertion.getSaml2().setIssueInstant(issueInstant);
231         samlAssertion.getSaml2().getConditions().setNotOnOrAfter(null);
232 
233         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
234         WSSecHeader secHeader = new WSSecHeader(doc);
235         secHeader.insertSecurityHeader();
236 
237         WSSecSAMLToken wsSign = new WSSecSAMLToken(secHeader);
238 
239         Document unsignedDoc = wsSign.build(samlAssertion);
240 
241         if (LOG.isDebugEnabled()) {
242             LOG.debug("SAML 2 Authn Assertion (sender vouches):");
243             String outputString =
244                 XMLUtils.prettyDocumentToString(unsignedDoc);
245             LOG.debug(outputString);
246         }
247 
248         verify(unsignedDoc);
249     }
250 
251     @Test
252     public void testSAML2StaleIssueInstantButWithNotOnOrAfter() throws Exception {
253         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
254         callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
255         callbackHandler.setIssuer("www.example.com");
256 
257         SAMLCallback samlCallback = new SAMLCallback();
258         SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
259         SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
260 
261         ConditionsBean conditions = new ConditionsBean();
262         Instant issueInstant = Instant.now();
263         conditions.setNotBefore(issueInstant);
264         conditions.setNotAfter(issueInstant.plus(Duration.ofMinutes(35)));
265 
266         issueInstant = issueInstant.minus(Duration.ofMinutes(31));
267         samlAssertion.getSaml2().setIssueInstant(issueInstant);
268 
269         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
270         WSSecHeader secHeader = new WSSecHeader(doc);
271         secHeader.insertSecurityHeader();
272 
273         WSSecSAMLToken wsSign = new WSSecSAMLToken(secHeader);
274 
275         Document unsignedDoc = wsSign.build(samlAssertion);
276 
277         if (LOG.isDebugEnabled()) {
278             LOG.debug("SAML 2 Authn Assertion (sender vouches):");
279             String outputString =
280                 XMLUtils.prettyDocumentToString(unsignedDoc);
281             LOG.debug(outputString);
282         }
283 
284         verify(unsignedDoc);
285     }
286 
287     @Test
288     public void testSAML1StaleIssueInstant() throws Exception {
289         SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
290         callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
291         callbackHandler.setIssuer("www.example.com");
292 
293         SAMLCallback samlCallback = new SAMLCallback();
294         SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
295         SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
296 
297         Instant issueInstant = Instant.now();
298         issueInstant = issueInstant.minus(Duration.ofMinutes(31));
299         samlAssertion.getSaml1().setIssueInstant(issueInstant);
300         samlAssertion.getSaml1().getConditions().setNotOnOrAfter(null);
301 
302         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
303         WSSecHeader secHeader = new WSSecHeader(doc);
304         secHeader.insertSecurityHeader();
305 
306         WSSecSAMLToken wsSign = new WSSecSAMLToken(secHeader);
307 
308         Document unsignedDoc = wsSign.build(samlAssertion);
309 
310         if (LOG.isDebugEnabled()) {
311             LOG.debug("SAML 1 Authn Assertion (sender vouches):");
312             String outputString =
313                 XMLUtils.prettyDocumentToString(unsignedDoc);
314             LOG.debug(outputString);
315         }
316 
317         try {
318             verify(unsignedDoc);
319             fail("Failure expected in processing a stale SAML Assertion");
320         } catch (WSSecurityException ex) {
321             assertTrue(ex.getMessage().contains("SAML token security failure"));
322         }
323     }
324 
325     /**
326      * Test that creates, sends and processes an unsigned SAML 2 authentication assertion
327      * with an (invalid) custom Conditions statement.
328      */
329     @Test
330     public void testSAML2InvalidBeforeConditions() throws Exception {
331         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
332         callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
333         callbackHandler.setIssuer("www.example.com");
334 
335         ConditionsBean conditions = new ConditionsBean();
336         Instant notBefore = Instant.now();
337         conditions.setNotBefore(notBefore.plus(Duration.ofMinutes(2)));
338         conditions.setNotAfter(notBefore.plus(Duration.ofMinutes(5)));
339         callbackHandler.setConditions(conditions);
340 
341         createAndVerifyMessage(callbackHandler, false);
342     }
343 
344     /**
345      * Test that creates, sends and processes an unsigned SAML 2 authentication assertion
346      * with a Conditions statement that has a NotBefore "in the future".
347      */
348     @Test
349     public void testSAML2FutureTTLConditions() throws Exception {
350         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
351         callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
352         callbackHandler.setIssuer("www.example.com");
353 
354         ConditionsBean conditions = new ConditionsBean();
355         Instant notBefore = Instant.now();
356         conditions.setNotBefore(notBefore.plusSeconds(30));
357         conditions.setNotAfter(notBefore.plus(Duration.ofMinutes(5)));
358         callbackHandler.setConditions(conditions);
359 
360         createAndVerifyMessage(callbackHandler, true);
361     }
362 
363     /**
364      * Test that creates, sends and processes an unsigned SAML 2 authentication assertion
365      * with a OneTimeUse Element
366      */
367     @Test
368     public void testSAML2OneTimeUse() throws Exception {
369         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
370         callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
371         callbackHandler.setIssuer("www.example.com");
372 
373         ConditionsBean conditions = new ConditionsBean();
374         conditions.setTokenPeriodMinutes(5);
375         conditions.setOneTimeUse(true);
376 
377         callbackHandler.setConditions(conditions);
378 
379         SAMLCallback samlCallback = new SAMLCallback();
380         SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
381         SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
382 
383         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
384         WSSecHeader secHeader = new WSSecHeader(doc);
385         secHeader.insertSecurityHeader();
386 
387         WSSecSAMLToken wsSign = new WSSecSAMLToken(secHeader);
388 
389         Document unsignedDoc = wsSign.build(samlAssertion);
390 
391         String outputString =
392             XMLUtils.prettyDocumentToString(unsignedDoc);
393         assertTrue(outputString.contains("OneTimeUse"));
394         if (LOG.isDebugEnabled()) {
395             LOG.debug(outputString);
396         }
397 
398         verify(unsignedDoc);
399     }
400 
401     /**
402      * Test that creates, sends and processes an unsigned SAML 2 authentication assertion
403      * with a ProxyRestriction Element
404      */
405     @Test
406     public void testSAML2ProxyRestriction() throws Exception {
407         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
408         callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
409         callbackHandler.setIssuer("www.example.com");
410 
411         ConditionsBean conditions = new ConditionsBean();
412         conditions.setTokenPeriodMinutes(5);
413         ProxyRestrictionBean proxyRestriction = new ProxyRestrictionBean();
414         List<String> audiences = new ArrayList<>();
415         audiences.add("http://apache.org/one");
416         audiences.add("http://apache.org/two");
417         proxyRestriction.getAudienceURIs().addAll(audiences);
418         proxyRestriction.setCount(5);
419         conditions.setProxyRestriction(proxyRestriction);
420 
421         callbackHandler.setConditions(conditions);
422 
423         SAMLCallback samlCallback = new SAMLCallback();
424         SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
425         SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
426 
427         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
428         WSSecHeader secHeader = new WSSecHeader(doc);
429         secHeader.insertSecurityHeader();
430 
431         WSSecSAMLToken wsSign = new WSSecSAMLToken(secHeader);
432 
433         Document unsignedDoc = wsSign.build(samlAssertion);
434 
435         String outputString =
436             XMLUtils.prettyDocumentToString(unsignedDoc);
437         assertTrue(outputString.contains("ProxyRestriction"));
438         if (LOG.isDebugEnabled()) {
439             LOG.debug(outputString);
440         }
441 
442         verify(unsignedDoc);
443     }
444 
445     /**
446      * Test that creates, sends and processes an unsigned SAML 2 authentication assertion
447      * with an AudienceRestriction Element
448      */
449     @Test
450     public void testSAML2AudienceRestriction() throws Exception {
451         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
452         callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
453         callbackHandler.setIssuer("www.example.com");
454 
455         ConditionsBean conditions = new ConditionsBean();
456         conditions.setTokenPeriodMinutes(5);
457         List<String> audiences = new ArrayList<>();
458         audiences.add("http://apache.org/one");
459         audiences.add("http://apache.org/two");
460         AudienceRestrictionBean audienceRestrictionBean = new AudienceRestrictionBean();
461         audienceRestrictionBean.setAudienceURIs(audiences);
462         conditions.setAudienceRestrictions(Collections.singletonList(audienceRestrictionBean));
463 
464         callbackHandler.setConditions(conditions);
465 
466         SAMLCallback samlCallback = new SAMLCallback();
467         SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
468         SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
469 
470         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
471         WSSecHeader secHeader = new WSSecHeader(doc);
472         secHeader.insertSecurityHeader();
473 
474         WSSecSAMLToken wsSign = new WSSecSAMLToken(secHeader);
475 
476         Document unsignedDoc = wsSign.build(samlAssertion);
477 
478         String outputString =
479             XMLUtils.prettyDocumentToString(unsignedDoc);
480         assertTrue(outputString.contains("AudienceRestriction"));
481         if (LOG.isDebugEnabled()) {
482             LOG.debug(outputString);
483         }
484 
485         verify(unsignedDoc);
486     }
487 
488     // Now test AudienceRestrictions with supplied restrictions
489     @Test
490     public void testSAML2AudienceRestrictionVerification() throws Exception {
491         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
492         callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
493         callbackHandler.setIssuer("www.example.com");
494 
495         ConditionsBean conditions = new ConditionsBean();
496         conditions.setTokenPeriodMinutes(5);
497         List<String> audiences = new ArrayList<>();
498         audiences.add("http://apache.org/one");
499         audiences.add("http://apache.org/two");
500         AudienceRestrictionBean audienceRestrictionBean = new AudienceRestrictionBean();
501         audienceRestrictionBean.setAudienceURIs(audiences);
502         conditions.setAudienceRestrictions(Collections.singletonList(audienceRestrictionBean));
503 
504         callbackHandler.setConditions(conditions);
505 
506         SAMLCallback samlCallback = new SAMLCallback();
507         SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
508         SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
509 
510         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
511         WSSecHeader secHeader = new WSSecHeader(doc);
512         secHeader.insertSecurityHeader();
513 
514         WSSecSAMLToken wsSign = new WSSecSAMLToken(secHeader);
515 
516         Document unsignedDoc = wsSign.build(samlAssertion);
517 
518         String outputString =
519             XMLUtils.prettyDocumentToString(unsignedDoc);
520         assertTrue(outputString.contains("AudienceRestriction"));
521         if (LOG.isDebugEnabled()) {
522             LOG.debug(outputString);
523         }
524 
525         // This should fail as the expected audience isn't in the assertion
526         audiences.clear();
527         audiences.add("http://apache.org/three");
528 
529         WSSecurityEngine newEngine = new WSSecurityEngine();
530         RequestData data = new RequestData();
531         data.setAudienceRestrictions(audiences);
532         data.setValidateSamlSubjectConfirmation(false);
533 
534         try {
535             newEngine.processSecurityHeader(doc, data);
536             fail("Failure expected on a bad audience restriction");
537         } catch (WSSecurityException ex) {
538             assertTrue(ex.getMessage().contains("SAML token security failure"));
539         }
540 
541         // Now add the correct audience back in...
542         audiences.add("http://apache.org/one");
543         data.setAudienceRestrictions(audiences);
544 
545         newEngine.processSecurityHeader(doc, data);
546     }
547 
548     // Now test AudienceRestrictions with supplied restrictions
549     @Test
550     public void testSAML1AudienceRestrictionVerification() throws Exception {
551         SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
552         callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
553         callbackHandler.setIssuer("www.example.com");
554 
555         ConditionsBean conditions = new ConditionsBean();
556         conditions.setTokenPeriodMinutes(5);
557         List<String> audiences = new ArrayList<>();
558         audiences.add("http://apache.org/one");
559         audiences.add("http://apache.org/two");
560         AudienceRestrictionBean audienceRestrictionBean = new AudienceRestrictionBean();
561         audienceRestrictionBean.setAudienceURIs(audiences);
562         conditions.setAudienceRestrictions(Collections.singletonList(audienceRestrictionBean));
563 
564         callbackHandler.setConditions(conditions);
565 
566         SAMLCallback samlCallback = new SAMLCallback();
567         SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
568         SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
569 
570         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
571         WSSecHeader secHeader = new WSSecHeader(doc);
572         secHeader.insertSecurityHeader();
573 
574         WSSecSAMLToken wsSign = new WSSecSAMLToken(secHeader);
575 
576         Document unsignedDoc = wsSign.build(samlAssertion);
577 
578         String outputString =
579             XMLUtils.prettyDocumentToString(unsignedDoc);
580         assertTrue(outputString.contains("AudienceRestriction"));
581         if (LOG.isDebugEnabled()) {
582             LOG.debug(outputString);
583         }
584 
585         // This should fail as the expected audience isn't in the assertion
586         audiences.clear();
587         audiences.add("http://apache.org/three");
588 
589         WSSecurityEngine newEngine = new WSSecurityEngine();
590         RequestData data = new RequestData();
591         data.setAudienceRestrictions(audiences);
592         data.setValidateSamlSubjectConfirmation(false);
593 
594         try {
595             newEngine.processSecurityHeader(doc, data);
596             fail("Failure expected on a bad audience restriction");
597         } catch (WSSecurityException ex) {
598             assertTrue(ex.getMessage().contains("SAML token security failure"));
599         }
600 
601         // Now add the correct audience back in...
602         audiences.add("http://apache.org/one");
603         data.setAudienceRestrictions(audiences);
604 
605         newEngine.processSecurityHeader(doc, data);
606     }
607 
608     /**
609      * Test that creates, sends and processes an unsigned SAML 2 authentication assertion
610      * with two AudienceRestriction Elements
611      */
612     @Test
613     public void testSAML2AudienceRestrictionSeparateRestrictions() throws Exception {
614         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
615         callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
616         callbackHandler.setIssuer("www.example.com");
617 
618         ConditionsBean conditions = new ConditionsBean();
619         conditions.setTokenPeriodMinutes(5);
620 
621         List<AudienceRestrictionBean> audiencesRestrictions = new ArrayList<>();
622         AudienceRestrictionBean audienceRestrictionBean = new AudienceRestrictionBean();
623         audienceRestrictionBean.setAudienceURIs(Collections.singletonList("http://apache.org/one"));
624         audiencesRestrictions.add(audienceRestrictionBean);
625 
626         audienceRestrictionBean = new AudienceRestrictionBean();
627         audienceRestrictionBean.setAudienceURIs(Collections.singletonList("http://apache.org/two"));
628         audiencesRestrictions.add(audienceRestrictionBean);
629 
630         conditions.setAudienceRestrictions(audiencesRestrictions);
631 
632         callbackHandler.setConditions(conditions);
633 
634         SAMLCallback samlCallback = new SAMLCallback();
635         SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
636         SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
637 
638         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
639         WSSecHeader secHeader = new WSSecHeader(doc);
640         secHeader.insertSecurityHeader();
641 
642         WSSecSAMLToken wsSign = new WSSecSAMLToken(secHeader);
643 
644         Document unsignedDoc = wsSign.build(samlAssertion);
645 
646         String outputString =
647             XMLUtils.prettyDocumentToString(unsignedDoc);
648         assertTrue(outputString.contains("AudienceRestriction"));
649         if (LOG.isDebugEnabled()) {
650             LOG.debug(outputString);
651         }
652 
653         verify(unsignedDoc);
654     }
655 
656     // Now test AudienceRestrictions with supplied restrictions
657     @Test
658     public void testSAML2AudienceRestrictionSeparateRestrictionsValidation() throws Exception {
659         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
660         callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
661         callbackHandler.setIssuer("www.example.com");
662 
663         ConditionsBean conditions = new ConditionsBean();
664         conditions.setTokenPeriodMinutes(5);
665 
666         List<AudienceRestrictionBean> audiencesRestrictions = new ArrayList<>();
667         AudienceRestrictionBean audienceRestrictionBean = new AudienceRestrictionBean();
668         audienceRestrictionBean.setAudienceURIs(Collections.singletonList("http://apache.org/one"));
669         audiencesRestrictions.add(audienceRestrictionBean);
670 
671         audienceRestrictionBean = new AudienceRestrictionBean();
672         audienceRestrictionBean.setAudienceURIs(Collections.singletonList("http://apache.org/two"));
673         audiencesRestrictions.add(audienceRestrictionBean);
674 
675         conditions.setAudienceRestrictions(audiencesRestrictions);
676 
677         callbackHandler.setConditions(conditions);
678 
679         SAMLCallback samlCallback = new SAMLCallback();
680         SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
681         SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
682 
683         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
684         WSSecHeader secHeader = new WSSecHeader(doc);
685         secHeader.insertSecurityHeader();
686 
687         WSSecSAMLToken wsSign = new WSSecSAMLToken(secHeader);
688 
689         Document unsignedDoc = wsSign.build(samlAssertion);
690 
691         String outputString =
692             XMLUtils.prettyDocumentToString(unsignedDoc);
693         assertTrue(outputString.contains("AudienceRestriction"));
694         if (LOG.isDebugEnabled()) {
695             LOG.debug(outputString);
696         }
697 
698         // This should fail as the expected audience isn't in the assertion
699         List<String> audiences = new ArrayList<>();
700         audiences.add("http://apache.org/three");
701 
702         WSSecurityEngine newEngine = new WSSecurityEngine();
703         RequestData data = new RequestData();
704         data.setAudienceRestrictions(audiences);
705         data.setValidateSamlSubjectConfirmation(false);
706 
707         try {
708             newEngine.processSecurityHeader(doc, data);
709             fail("Failure expected on a bad audience restriction");
710         } catch (WSSecurityException ex) {
711             assertTrue(ex.getMessage().contains("SAML token security failure"));
712         }
713 
714         // Now add the correct audience back in...
715         audiences.add("http://apache.org/one");
716         data.setAudienceRestrictions(audiences);
717 
718         newEngine.processSecurityHeader(doc, data);
719     }
720 
721     @Test
722     public void testSAML2Delegate() throws Exception {
723         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
724         callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
725         callbackHandler.setIssuer("www.example.com");
726 
727         ConditionsBean conditions = new ConditionsBean();
728         Instant notBefore = Instant.now();
729         conditions.setNotBefore(notBefore);
730         conditions.setNotAfter(notBefore.plus(Duration.ofMinutes(20)));
731 
732         DelegateBean delegate = new DelegateBean();
733         delegate.setDelegationInstant(Instant.now());
734         delegate.setConfirmationMethod(SAML2Constants.CONF_BEARER);
735 
736         NameIDBean nameID = new NameIDBean();
737         nameID.setNameValue("bob");
738         nameID.setNameQualifier("www.example.com");
739         delegate.setNameIDBean(nameID);
740 
741         conditions.setDelegates(Collections.singletonList(delegate));
742 
743         callbackHandler.setConditions(conditions);
744 
745         createAndVerifyMessage(callbackHandler, true);
746     }
747 
748     private void createAndVerifyMessage(    //NOPMD - It incorrectly thinks this method isn't called
749         CallbackHandler samlCallbackHandler, boolean success
750     ) throws Exception {
751         SAMLCallback samlCallback = new SAMLCallback();
752         SAMLUtil.doSAMLCallback(samlCallbackHandler, samlCallback);
753         SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
754 
755         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
756         WSSecHeader secHeader = new WSSecHeader(doc);
757         secHeader.insertSecurityHeader();
758 
759         WSSecSAMLToken wsSign = new WSSecSAMLToken(secHeader);
760 
761         Document unsignedDoc = wsSign.build(samlAssertion);
762 
763         if (LOG.isDebugEnabled()) {
764             String outputString =
765                 XMLUtils.prettyDocumentToString(unsignedDoc);
766             LOG.debug(outputString);
767         }
768 
769         try {
770             verify(unsignedDoc);
771             if (!success) {
772                 fail("Failure expected in processing the SAML assertion");
773             }
774         } catch (WSSecurityException ex) {
775             assertFalse(success);
776             assertTrue(ex.getMessage().contains("SAML token security failure"));
777         }
778     }
779 
780     /**
781      * Verifies the soap envelope
782      * <p/>
783      *
784      * @param envelope
785      * @throws Exception Thrown when there is a problem in verification
786      */
787     private WSHandlerResult verify(Document doc) throws Exception {
788         RequestData requestData = new RequestData();
789         requestData.setValidateSamlSubjectConfirmation(false);
790 
791         WSHandlerResult results = secEngine.processSecurityHeader(doc, requestData);
792         String outputString =
793             XMLUtils.prettyDocumentToString(doc);
794         assertTrue(outputString.indexOf("counter_port_type") > 0 ? true : false);
795         return results;
796     }
797 
798 }