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  
25  import javax.security.auth.callback.CallbackHandler;
26  
27  import org.apache.wss4j.common.ext.WSSecurityException;
28  import org.apache.wss4j.common.saml.SAMLCallback;
29  import org.apache.wss4j.common.saml.SAMLUtil;
30  import org.apache.wss4j.common.saml.SamlAssertionWrapper;
31  import org.apache.wss4j.common.util.SOAPUtil;
32  import org.apache.wss4j.common.util.XMLUtils;
33  import org.apache.wss4j.dom.WSConstants;
34  import org.apache.wss4j.dom.common.CustomSamlAssertionValidator;
35  import org.apache.wss4j.dom.common.SAML1CallbackHandler;
36  import org.apache.wss4j.dom.common.SAML2CallbackHandler;
37  
38  import org.apache.wss4j.dom.engine.WSSConfig;
39  import org.apache.wss4j.dom.engine.WSSecurityEngine;
40  import org.apache.wss4j.dom.handler.RequestData;
41  import org.apache.wss4j.dom.handler.WSHandlerResult;
42  import org.apache.wss4j.dom.message.WSSecHeader;
43  import org.apache.wss4j.dom.message.WSSecSAMLToken;
44  
45  import org.junit.jupiter.api.Test;
46  import org.w3c.dom.Document;
47  
48  import static org.junit.jupiter.api.Assertions.assertFalse;
49  import static org.junit.jupiter.api.Assertions.assertTrue;
50  import static org.junit.jupiter.api.Assertions.fail;
51  
52  /**
53   * Some tests for SAML Authentication Assertions
54   */
55  public class SamlAuthnTest {
56      private static final org.slf4j.Logger LOG =
57          org.slf4j.LoggerFactory.getLogger(SamlAuthnTest.class);
58      private WSSecurityEngine secEngine = new WSSecurityEngine();
59  
60      public SamlAuthnTest() {
61          WSSConfig config = WSSConfig.getNewInstance();
62          config.setValidator(WSConstants.SAML_TOKEN, new CustomSamlAssertionValidator());
63          config.setValidator(WSConstants.SAML2_TOKEN, new CustomSamlAssertionValidator());
64          secEngine.setWssConfig(config);
65      }
66  
67      @Test
68      public void testSAML1AuthnAssertion() throws Exception {
69          SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
70          callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
71          callbackHandler.setIssuer("www.example.com");
72  
73          createAndVerifyMessage(callbackHandler, true);
74      }
75  
76      @Test
77      public void testSAML2AuthnAssertion() throws Exception {
78          SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
79          callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
80          callbackHandler.setIssuer("www.example.com");
81  
82          createAndVerifyMessage(callbackHandler, true);
83      }
84  
85      @Test
86      public void testSAML1FutureAuthnInstant() throws Exception {
87          SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
88          callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
89          callbackHandler.setIssuer("www.example.com");
90  
91          callbackHandler.setAuthenticationInstant(Instant.now().plus(Duration.ofMinutes(70)));
92  
93          createAndVerifyMessage(callbackHandler, false);
94      }
95  
96      @Test
97      public void testSAML2FutureAuthnInstant() throws Exception {
98          SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
99          callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
100         callbackHandler.setIssuer("www.example.com");
101 
102         callbackHandler.setAuthenticationInstant(Instant.now().plus(Duration.ofMinutes(70)));
103 
104         createAndVerifyMessage(callbackHandler, false);
105     }
106 
107     @Test
108     public void testSAML2StaleSessionNotOnOrAfter() throws Exception {
109         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
110         callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
111         callbackHandler.setIssuer("www.example.com");
112 
113         callbackHandler.setSessionNotOnOrAfter(Instant.now().minus(Duration.ofMinutes(70)));
114 
115         createAndVerifyMessage(callbackHandler, false);
116     }
117 
118     @Test
119     public void testSAML1ValidSubjectLocality() throws Exception {
120         SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
121         callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
122         callbackHandler.setIssuer("www.example.com");
123 
124         callbackHandler.setSubjectLocality("127.0.0.1", "xyz.ws.apache.org");   //NOPMD
125 
126         createAndVerifyMessage(callbackHandler, true);
127     }
128 
129     @Test
130     public void testSAML2ValidSubjectLocality() throws Exception {
131         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
132         callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
133         callbackHandler.setIssuer("www.example.com");
134 
135         callbackHandler.setSubjectLocality("127.0.0.1", "xyz.ws.apache.org");   //NOPMD
136 
137         createAndVerifyMessage(callbackHandler, true);
138     }
139 
140     @Test
141     public void testSAML1InvalidSubjectLocality() throws Exception {
142         SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
143         callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
144         callbackHandler.setIssuer("www.example.com");
145 
146         callbackHandler.setSubjectLocality("xyz.ws.apache.org", "xyz.ws.apache.org");
147 
148         createAndVerifyMessage(callbackHandler, false);
149     }
150 
151     @Test
152     public void testSAML2InalidSubjectLocality() throws Exception {
153         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
154         callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
155         callbackHandler.setIssuer("www.example.com");
156 
157         callbackHandler.setSubjectLocality("xyz.ws.apache.org", "xyz.ws.apache.org");
158 
159         createAndVerifyMessage(callbackHandler, false);
160     }
161 
162     private void createAndVerifyMessage(    //NOPMD - It incorrectly thinks this method isn't called
163         CallbackHandler samlCallbackHandler, boolean success
164     ) throws Exception {
165         SAMLCallback samlCallback = new SAMLCallback();
166         SAMLUtil.doSAMLCallback(samlCallbackHandler, samlCallback);
167         SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
168 
169         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
170         WSSecHeader secHeader = new WSSecHeader(doc);
171         secHeader.insertSecurityHeader();
172 
173         WSSecSAMLToken wsSign = new WSSecSAMLToken(secHeader);
174 
175         Document unsignedDoc = wsSign.build(samlAssertion);
176 
177         if (LOG.isDebugEnabled()) {
178             String outputString =
179                 XMLUtils.prettyDocumentToString(unsignedDoc);
180             LOG.debug(outputString);
181         }
182 
183         try {
184             verify(unsignedDoc);
185             if (!success) {
186                 fail("Failure expected in processing the SAML assertion");
187             }
188         } catch (WSSecurityException ex) {
189             assertFalse(success);
190             assertTrue(ex.getMessage().contains("SAML token security failure"));
191         }
192     }
193 
194     /**
195      * Verifies the soap envelope
196      * <p/>
197      *
198      * @param doc
199      * @throws Exception Thrown when there is a problem in verification
200      */
201     private WSHandlerResult verify(Document doc) throws Exception {
202         RequestData requestData = new RequestData();
203         requestData.setValidateSamlSubjectConfirmation(false);
204 
205         WSHandlerResult results = secEngine.processSecurityHeader(doc, requestData);
206         String outputString =
207             XMLUtils.prettyDocumentToString(doc);
208         assertTrue(outputString.indexOf("counter_port_type") > 0 ? true : false);
209         return results;
210     }
211 
212 }