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;
24 import javax.naming.directory.Attributes;
25 import javax.naming.directory.BasicAttribute;
26 import javax.servlet.http.HttpServletRequest;
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.AuthenticationFilter;
38 import edu.internet2.middleware.shibboleth.resource.FilterUtil;
39 import edu.internet2.middleware.shibboleth.resource.FilterSupport.NewSessionData;
40 import edu.internet2.middleware.shibboleth.runner.ShibbolethRunner;
41 import edu.internet2.middleware.shibboleth.serviceprovider.AssertionConsumerServlet;
42 import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderConfig;
43 import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderContext;
44 import edu.internet2.middleware.shibboleth.serviceprovider.Session;
47 * A JUnit test case that exercises the IdP, SP, and Filter
48 * @author Howard Gilbert
50 public class IntegrationTest extends TestCase {
52 private static final String GIVENNAME = "Bozo";
53 public static final String SURNAME = "Clown";
54 private static final String TITLE = "clown";
55 public static final String AFFILIATION = "member";
56 public static final String SP_ENTITY = "https://sp.example.org/shibboleth";
57 public static final String POST_SHIRE = "https://sp.example.org/Shibboleth.sso/SAML/POST";
58 public static final String ARTIFACT_SHIRE = "https://sp.example.org/Shibboleth.sso/SAML/Artifact";
59 public static final String TARGET = "https://nonsense";
60 public static final String NETID = "BozoTClown";
61 public static final String APPLICATIONID = "default";
63 ShibbolethRunner runner;
64 ShibbolethRunner.IdpTestContext idp;
65 ShibbolethRunner.AuthenticationFilterContext filter;
66 private NewSessionData newSessionData = new NewSessionData();
67 ServiceProviderContext context;
68 ServiceProviderConfig config;
72 protected void setUp() throws Exception {
75 // Static call to set Log4J appenders and levels
76 ShibbolethRunner.loglevel = Level.DEBUG;
77 ShibbolethRunner.setupLogging();
79 // Create the overall testing framework
80 runner = new ShibbolethRunner();
82 // Initialize the Idp, create the Mockrunner
83 // objects to do SSO, AA, and Artifact calls, and
84 // configure SAML to use the MockHTTPBindingProvider
85 runner.setIdpConfigFileName("/basicIdpHome/idpconfig.xml"); // default value
86 idp = runner.getIdp();
88 // Initialize the SP with the default config file.
89 runner.setSpConfigFileName("/basicSpHome/spconfig.xml"); // default value
90 runner.initializeSP();
91 context=ServiceProviderContext.getInstance();
92 config = context.getServiceProviderConfig();
94 // Initialize the Filter and create its separate
95 // Mockrunner simulated context.
96 filter= runner.getFilter();
97 // Note: If you are going to change the Filter init-param
98 // values, do it here before calling setUp()
101 newSessionData.applicationId=APPLICATIONID;
102 newSessionData.providerId=SP_ENTITY;
105 // Create the static collection of Attributes that are
106 // returned by the IdP for every principal.
107 // This could be done in each test, just as long as it
108 // is done before the SSO.
109 Attributes attributes = runner.getAttributesCollection();
110 attributes.put(new BasicAttribute("eduPersonAffiliation", AFFILIATION));
112 attributes.put(new BasicAttribute("eduPersonScopedAffiliation", AFFILIATION));
113 attributes.put(new BasicAttribute("title", TITLE));
114 attributes.put(new BasicAttribute("givenName", GIVENNAME));
115 attributes.put(new BasicAttribute("surname", SURNAME));
117 attributes.put(new BasicAttribute("unacceptable","nonsense"));
119 attributes.put(new BasicAttribute("unreleasable","foolishness"));
123 public void testAttributePush() throws SAMLException {
125 // Set the URL suffix that triggers SSO processing
126 idp.setRequestUrls("SSO");
128 // Add the WAYF/RM parameters
129 idp.testModule.addRequestParameter("target", TARGET);
130 idp.testModule.addRequestParameter("shire",POST_SHIRE);
131 idp.testModule.addRequestParameter("providerId", SP_ENTITY);
133 // Add a userid, as if provided by Basic Authentication or a Filter
134 idp.request.setRemoteUser(NETID);
136 // Force Attribute Push
137 ShibbolethV1SSOHandler.pushAttributeDefault=true;
140 idp.testModule.doGet();
143 * Sanity check: The IdP normally ends by transferring control to a
144 * JSP page that generates the FORM. However, we have not set up
145 * Mockrunner to perform the transfer, because the form would just
146 * create parsing work. Rather, the following code extracts the
147 * information from the request attributes that the JSP would have
148 * used as its source.
150 String bin64assertion = (String) idp.request.getAttribute("assertion");
151 String assertion = new String(Base64.decodeBase64(bin64assertion.getBytes()));
152 String handlerURL = (String) idp.request.getAttribute("shire");
153 String targetURL = (String) idp.request.getAttribute("target");
156 FilterUtil.sessionDataFromRequest(newSessionData,idp.request);
157 // there was no real redirect, so the next two fields are not
158 // in the places that sessionDataFromRequest expects.
159 newSessionData.SAMLResponse = bin64assertion;
160 newSessionData.target=targetURL;
161 newSessionData.handlerURL=handlerURL;
163 // Create the session, extract pushed Attributes
164 String sessionId = AssertionConsumerServlet.createSessionFromData(newSessionData);
166 // Now get what was created in case you want to test it.
167 Session session = context.getSessionManager().findSession(sessionId, APPLICATIONID);
168 checkSession(session);
170 // Pass the SessionId to the Filter, let it fetch the attributes
171 filter.testModule.addRequestParameter(AuthenticationFilter.SESSIONPARM, sessionId);
172 filter.setRequestUrls("test.txt");
173 filter.testModule.doFilter();
176 * Sanity Check: doFilter runs just the Filter itself. On
177 * input there was a Request and Response. When done, there
178 * will be a replacement Request object created by the Filter
179 * wrapping the original request and adding features.
186 // Get the Request Wrapper object created by the Filter
187 HttpServletRequest filteredRequest =
188 (HttpServletRequest) filter.testModule.getFilteredRequest();
190 assertEquals(NETID,filteredRequest.getRemoteUser());
191 assertEquals(NETID,filteredRequest.getHeader("REMOTE_USER"));
192 assertEquals(SURNAME,filteredRequest.getHeader("Shib-Person-surname"));
193 assertEquals(GIVENNAME,filteredRequest.getHeader("Shib-InetOrgPerson-givenName"));
194 assertEquals(TITLE,filteredRequest.getHeader("Shib-OrgPerson-title"));
196 Map attributes = (Map) filteredRequest.getAttribute(AuthenticationFilter.SHIB_ATTRIBUTES_PREFIX);
200 // Now do something that uses Filter supplied logic
201 Enumeration headerNames = filteredRequest.getHeaderNames();
202 while (headerNames.hasMoreElements()) {
203 String name = (String) headerNames.nextElement();
204 String value = (String) filteredRequest.getHeader(name);
205 System.out.println(name+ "-"+value );
209 void checkSession(Session session) {
210 assertNotNull(session);
211 assertEquals(APPLICATIONID,session.getApplicationId());
217 public void testAttributeQuery() throws SAMLException {
219 // Set the URL suffix that triggers SSO processing
220 idp.setRequestUrls("SSO");
222 // Add the WAYF/RM parameters
223 idp.testModule.addRequestParameter("target", TARGET);
224 idp.testModule.addRequestParameter("shire",POST_SHIRE);
225 idp.testModule.addRequestParameter("providerId", SP_ENTITY);
227 // Add a userid, as if provided by Basic Authentication or a Filter
228 idp.request.setRemoteUser(NETID);
230 // Block Attribute Push
231 ShibbolethV1SSOHandler.pushAttributeDefault=false;
234 idp.testModule.doGet();
236 String bin64assertion = (String) idp.request.getAttribute("assertion");
237 String assertion = new String(Base64.decodeBase64(bin64assertion.getBytes()));
238 String handlerURL = (String) idp.request.getAttribute("shire");
239 String targetURL = (String) idp.request.getAttribute("target");
242 // Build the parameter for Session creation
243 FilterUtil.sessionDataFromRequest(newSessionData,idp.request);
244 newSessionData.SAMLResponse = bin64assertion; // test logic
245 newSessionData.target=targetURL;
246 newSessionData.handlerURL=handlerURL;
248 // Create the Session
249 // Internally an AA Query will fetch the attributes through the
250 // MockHTTPBindingProvider
251 String sessionId = AssertionConsumerServlet.createSessionFromData(newSessionData);
254 // Now get what was created in case you want to test it.
255 Session session = context.getSessionManager().findSession(sessionId, APPLICATIONID);
256 checkSession(session);
258 // Pass the SessionId to the Filter, let it fetch the attributes
259 filter.testModule.addRequestParameter(AuthenticationFilter.SESSIONPARM, sessionId);
260 filter.setRequestUrls("test.txt"); // need any URL
261 filter.testModule.doFilter();
267 public void testArtifact() throws SAMLException, UnsupportedEncodingException {
269 // Set the URL suffix that triggers SSO processing
270 idp.setRequestUrls("SSO");
272 // Add the WAYF/RM parameters
273 idp.testModule.addRequestParameter("target", TARGET);
274 idp.testModule.addRequestParameter("shire",ARTIFACT_SHIRE);
275 idp.testModule.addRequestParameter("providerId", SP_ENTITY);
277 // Add a userid, as if provided by Basic Authentication or a Filter
278 idp.request.setRemoteUser(NETID);
280 // Attribute Push is implied by Artifact
281 ShibbolethV1SSOHandler.pushAttributeDefault=false;
284 idp.testModule.doGet();
286 MockHttpServletResponse response = idp.response;
287 // Get the redirection
288 assertTrue(response.wasRedirectSent());
289 String redirectURL = response.getHeader("Location");
291 String[] splits = redirectURL.split("\\&SAMLart=");
292 assertTrue(splits.length>1);
293 String[] samlArt = new String[splits.length-1];
294 for (int i=0;i<samlArt.length;i++) {
295 samlArt[i]=URLDecoder.decode(splits[i+1],"UTF-8");
300 // Build the parameter for Session creation
301 FilterUtil.sessionDataFromRequest(newSessionData,idp.request);
302 newSessionData.SAMLArt=samlArt;
303 newSessionData.target=TARGET;
304 newSessionData.handlerURL=ARTIFACT_SHIRE;
306 // Create the Session
307 // Internally an AA Query will fetch the attributes through the
308 // MockHTTPBindingProvider
309 String sessionId = AssertionConsumerServlet.createSessionFromData(newSessionData);
312 // Now get what was created in case you want to test it.
313 Session session = context.getSessionManager().findSession(sessionId, APPLICATIONID);
314 checkSession(session);
317 // Pass the SessionId to the Filter, let it fetch the attributes
318 filter.testModule.addRequestParameter(AuthenticationFilter.SESSIONPARM, sessionId);
319 filter.setRequestUrls("test.txt"); // need any URL
320 filter.testModule.doFilter();