2 * Copyright [2005] [University Corporation for Advanced Internet Development, Inc.]
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package edu.internet2.middleware.shibboleth.integration;
19 import java.io.UnsupportedEncodingException;
20 import java.net.URLDecoder;
21 import java.util.Enumeration;
23 import javax.naming.directory.Attributes;
24 import javax.naming.directory.BasicAttribute;
25 import javax.servlet.http.HttpServletRequest;
26 import javax.servlet.http.HttpServletResponse;
28 import junit.framework.TestCase;
30 import org.apache.commons.codec.binary.Base64;
31 import org.apache.log4j.Level;
32 import org.opensaml.SAMLException;
34 import com.mockrunner.mock.web.MockHttpServletResponse;
36 import edu.internet2.middleware.shibboleth.idp.provider.ShibbolethV1SSOHandler;
37 import edu.internet2.middleware.shibboleth.resource.FilterUtil;
38 import edu.internet2.middleware.shibboleth.resource.FilterSupport.NewSessionData;
39 import edu.internet2.middleware.shibboleth.runner.ShibbolethRunner;
40 import edu.internet2.middleware.shibboleth.serviceprovider.AssertionConsumerServlet;
41 import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderContext;
42 import edu.internet2.middleware.shibboleth.serviceprovider.Session;
43 import edu.internet2.middleware.shibboleth.serviceprovider.SessionManager;
46 * A JUnit test case that exercises the IdP, SP, and Filter
47 * @author Howard Gilbert
49 public class IntegrationTest extends TestCase {
51 ShibbolethRunner runner;
52 ShibbolethRunner.IdpTestContext idp;
53 ShibbolethRunner.AuthenticationFilterContext filter;
57 protected void setUp() throws Exception {
60 // Static call to set Log4J appenders and levels
61 ShibbolethRunner.loglevel = Level.DEBUG;
62 ShibbolethRunner.setupLogging();
64 // Create the overall testing framework
65 runner = new ShibbolethRunner();
67 // Initialize the Idp, create the Mockrunner
68 // objects to do SSO, AA, and Artifact calls, and
69 // configure SAML to use the MockHTTPBindingProvider
70 runner.setIdpConfigFileName("/basicIdpHome/idpconfig.xml");
71 idp = runner.getIdp();
73 // Initialize the SP with the default config file.
74 runner.setSpConfigFileName("/basicSpHome/spconfig.xml");
75 runner.initializeSP();
77 // Initialize the Filter and create its separate
78 // Mockrunner simulated context.
79 filter= runner.getFilter();
80 // Note: If you are going to change the Filter init-param
81 // values, do it here before calling setUp()
84 // Create the static collection of Attributes that are
85 // returned by the IdP for every principal.
86 // This could be done in each test, just as long as it
87 // is done before the SSO.
88 Attributes attributes = runner.getAttributesCollection();
89 attributes.put(new BasicAttribute("eduPersonAffiliation", "member"));
90 attributes.put(new BasicAttribute("eduPersonScopedAffiliation", "member"));
91 attributes.put(new BasicAttribute("title", "clown"));
92 attributes.put(new BasicAttribute("givenName", "bozo"));
93 attributes.put(new BasicAttribute("surname", "Clown"));
97 public void testAttributePush() throws SAMLException {
99 // Set the URL suffix that triggers SSO processing
100 idp.setRequestUrls("SSO");
102 // Add the WAYF/RM parameters
103 idp.testModule.addRequestParameter("target", "https://nonsense");
104 idp.testModule.addRequestParameter("shire","https://sp.example.org/Shibboleth.sso/SAML/POST");
105 idp.testModule.addRequestParameter("providerId", "https://sp.example.org/shibboleth");
107 // Add a userid, as if provided by Basic Authentication or a Filter
108 idp.request.setRemoteUser("BozoTClown");
110 // Force Attribute Push
111 ShibbolethV1SSOHandler.pushAttributeDefault=true;
114 idp.testModule.doGet();
117 * Sanity check: The IdP normally ends by transferring control to a
118 * JSP page that generates the FORM. However, we have not set up
119 * Mockrunner to perform the transfer, because the form would just
120 * create parsing work. Rather, the following code extracts the
121 * information from the request attributes that the JSP would have
122 * used as its source.
124 String bin64assertion = (String) idp.request.getAttribute("assertion");
125 String assertion = new String(Base64.decodeBase64(bin64assertion.getBytes()));
126 String handlerURL = (String) idp.request.getAttribute("shire");
127 String targetURL = (String) idp.request.getAttribute("target");
130 // Build the parameter for Session creation
131 NewSessionData data = new NewSessionData();
132 FilterUtil.sessionDataFromRequest(data,idp.request);
133 // there was no real redirect, so the next two fields are not
134 // in the places that sessionDataFromRequest expects.
135 data.SAMLResponse = bin64assertion;
136 data.target=targetURL;
137 data.applicationId="default";
138 data.handlerURL=handlerURL;
139 data.providerId="https://sp.example.org/shibboleth";
141 // Create the session, extract pushed Attributes
142 String sessionId = AssertionConsumerServlet.createSessionFromData(data);
144 // Now get what was created in case you want to test it.
145 ServiceProviderContext context = ServiceProviderContext.getInstance();
146 Session session = context.getSessionManager().findSession(sessionId, "default");
148 // Pass the SessionId to the Filter, let it fetch the attributes
149 filter.testModule.addRequestParameter("ShibbolethSessionId", sessionId);
150 filter.setRequestUrls("test.txt");
151 filter.testModule.doFilter();
154 * Sanity Check: doFilter runs just the Filter itself. On
155 * input there was a Request and Response. When done, there
156 * will be a replacement Request object created by the Filter
157 * wrapping the original request and adding features.
160 // Get the Request Wrapper object created by the Filter
161 HttpServletRequest filteredRequest =
162 (HttpServletRequest) filter.testModule.getFilteredRequest();
164 // Now do something that uses Filter supplied logic
165 Enumeration headerNames = filteredRequest.getHeaderNames();
166 while (headerNames.hasMoreElements()) {
167 String name = (String) headerNames.nextElement();
168 String value = (String) filteredRequest.getHeader(name);
169 System.out.println(name+ "-"+value );
175 public void testAttributeQuery() throws SAMLException {
177 // Set the URL suffix that triggers SSO processing
178 idp.setRequestUrls("SSO");
180 // Add the WAYF/RM parameters
181 idp.testModule.addRequestParameter("target", "https://nonsense");
182 idp.testModule.addRequestParameter("shire","https://sp.example.org/Shibboleth.sso/SAML/POST");
183 idp.testModule.addRequestParameter("providerId", "https://sp.example.org/shibboleth");
185 // Add a userid, as if provided by Basic Authentication or a Filter
186 idp.request.setRemoteUser("BozoTClown");
188 // Block Attribute Push
189 ShibbolethV1SSOHandler.pushAttributeDefault=false;
192 idp.testModule.doGet();
194 String bin64assertion = (String) idp.request.getAttribute("assertion");
195 String assertion = new String(Base64.decodeBase64(bin64assertion.getBytes()));
196 String handlerURL = (String) idp.request.getAttribute("shire");
197 String targetURL = (String) idp.request.getAttribute("target");
200 // Build the parameter for Session creation
201 NewSessionData data = new NewSessionData();
202 FilterUtil.sessionDataFromRequest(data,idp.request);
203 data.SAMLResponse = bin64assertion; // test logic
204 data.target=targetURL;
205 data.applicationId="default";
206 data.handlerURL=handlerURL;
207 data.providerId="https://sp.example.org/shibboleth";
209 // Create the Session
210 // Internally an AA Query will fetch the attributes through the
211 // MockHTTPBindingProvider
212 String sessionId = AssertionConsumerServlet.createSessionFromData(data);
215 // Now get what was created in case you want to test it.
216 ServiceProviderContext context = ServiceProviderContext.getInstance();
217 Session session = context.getSessionManager().findSession(sessionId, "default");
218 StringBuffer buffer = SessionManager.dumpAttributes(session);
219 System.out.println(buffer.toString());
221 // Pass the SessionId to the Filter, let it fetch the attributes
222 filter.testModule.addRequestParameter("ShibbolethSessionId", sessionId);
223 filter.setRequestUrls("test.txt"); // need any URL
224 filter.testModule.doFilter();
226 // Get the Request Wrapper object created by the Filter
227 HttpServletRequest filteredRequest = (HttpServletRequest) filter.testModule.getFilteredRequest();
229 // Now do something that uses Filter supplied logic
230 Enumeration headerNames = filteredRequest.getHeaderNames();
231 while (headerNames.hasMoreElements()) {
232 String name = (String) headerNames.nextElement();
233 String value = (String) filteredRequest.getHeader(name);
234 System.out.println(name+ "-"+value );
238 public void testArtifact() throws SAMLException, UnsupportedEncodingException {
240 // Set the URL suffix that triggers SSO processing
241 idp.setRequestUrls("SSO");
243 // Add the WAYF/RM parameters
244 idp.testModule.addRequestParameter("target", "https://nonsense");
245 idp.testModule.addRequestParameter("shire","https://sp.example.org/Shibboleth.sso/SAML/Artifact");
246 idp.testModule.addRequestParameter("providerId", "https://sp.example.org/shibboleth");
248 // Add a userid, as if provided by Basic Authentication or a Filter
249 idp.request.setRemoteUser("BozoTClown");
251 // Attribute Push is implied by Artifact
252 ShibbolethV1SSOHandler.pushAttributeDefault=false;
255 idp.testModule.doGet();
257 MockHttpServletResponse response = idp.response;
258 String redirectURL = response.getHeader("Location");
260 String[] splits = redirectURL.split("\\&SAMLart=");
261 assertTrue(splits.length>0);
262 String[] samlArt = new String[splits.length-1];
263 for (int i=0;i<samlArt.length;i++) {
264 samlArt[i]=URLDecoder.decode(splits[i+1],"UTF-8");
269 // Build the parameter for Session creation
270 NewSessionData data = new NewSessionData();
271 FilterUtil.sessionDataFromRequest(data,idp.request);
272 data.SAMLArt=samlArt;
273 data.target="https://nonsense";
274 data.applicationId="default";
275 data.handlerURL="https://sp.example.org/Shibboleth.sso/SAML/Artifact";
276 data.providerId="https://sp.example.org/shibboleth";
278 // Create the Session
279 // Internally an AA Query will fetch the attributes through the
280 // MockHTTPBindingProvider
281 String sessionId = AssertionConsumerServlet.createSessionFromData(data);
284 // Now get what was created in case you want to test it.
285 ServiceProviderContext context = ServiceProviderContext.getInstance();
286 Session session = context.getSessionManager().findSession(sessionId, "default");
287 StringBuffer buffer = SessionManager.dumpAttributes(session);
288 System.out.println(buffer.toString());
290 // Pass the SessionId to the Filter, let it fetch the attributes
291 filter.testModule.addRequestParameter("ShibbolethSessionId", sessionId);
292 filter.setRequestUrls("test.txt"); // need any URL
293 filter.testModule.doFilter();
295 // Get the Request Wrapper object created by the Filter
296 HttpServletRequest filteredRequest = (HttpServletRequest) filter.testModule.getFilteredRequest();
298 // Now do something that uses Filter supplied logic
299 Enumeration headerNames = filteredRequest.getHeaderNames();
300 while (headerNames.hasMoreElements()) {
301 String name = (String) headerNames.nextElement();
302 String value = (String) filteredRequest.getHeader(name);
303 System.out.println(name+ "-"+value );