672829647091be883a129f22f93cc1dfe235af89
[java-idp.git] / tests / edu / internet2 / middleware / shibboleth / integration / IntegrationTest.java
1 /*
2  * Copyright [2005] [University Corporation for Advanced Internet Development, Inc.]
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package edu.internet2.middleware.shibboleth.integration;
18
19 import java.io.UnsupportedEncodingException;
20 import java.net.URLDecoder;
21 import java.util.Enumeration;
22 import java.util.Map;
23
24 import javax.naming.directory.Attributes;
25 import javax.naming.directory.BasicAttribute;
26 import javax.servlet.http.HttpServletRequest;
27
28 import junit.framework.TestCase;
29
30 import org.apache.commons.codec.binary.Base64;
31 import org.apache.log4j.Level;
32 import org.opensaml.SAMLException;
33
34 import com.mockrunner.mock.web.MockHttpServletResponse;
35
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;
45
46 /**
47  * A JUnit test case that exercises the IdP, SP, and Filter
48  * @author Howard Gilbert
49  */
50 public class IntegrationTest extends TestCase {
51     
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";
62     
63     ShibbolethRunner runner;
64     ShibbolethRunner.IdpTestContext idp;
65     ShibbolethRunner.AuthenticationFilterContext filter;
66     private NewSessionData newSessionData = new NewSessionData();
67     ServiceProviderContext context;
68     ServiceProviderConfig config;
69     
70     
71     
72     protected void setUp() throws Exception {
73         super.setUp();
74
75         // Static call to set Log4J appenders and levels
76         ShibbolethRunner.loglevel = Level.DEBUG;
77         ShibbolethRunner.setupLogging();
78         
79         // Create the overall testing framework
80         runner = new ShibbolethRunner();
81         
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();
87         
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();
93         
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()
99         filter.setUp();
100   
101         newSessionData.applicationId=APPLICATIONID;
102         newSessionData.providerId=SP_ENTITY;
103           
104         
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));
111         // scoped
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));
116         // not in AAP
117         attributes.put(new BasicAttribute("unacceptable","nonsense"));
118         // not in ARP
119         attributes.put(new BasicAttribute("unreleasable","foolishness"));
120     }
121     
122     
123     public void testAttributePush() throws SAMLException {
124         
125         // Set the URL suffix that triggers SSO processing
126         idp.setRequestUrls("SSO");
127         
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);
132         
133         // Add a userid, as if provided by Basic Authentication or a Filter
134         idp.request.setRemoteUser(NETID);
135         
136         // Force Attribute Push
137         ShibbolethV1SSOHandler.pushAttributeDefault=true;
138         
139         // Call the IdP 
140         idp.testModule.doGet();
141         
142             /*
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.
149              */
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");
154         
155         
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;
162         
163         // Create the session, extract pushed Attributes 
164         String sessionId = AssertionConsumerServlet.createSessionFromData(newSessionData);
165         
166         // Now get what was created in case you want to test it.
167         Session session = context.getSessionManager().findSession(sessionId, APPLICATIONID);
168         checkSession(session);
169         
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();
174         
175             /*
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.
180              */
181
182         checkFilter();
183     }
184     
185     void checkFilter() {
186         // Get the Request Wrapper object created by the Filter
187         HttpServletRequest filteredRequest = 
188             (HttpServletRequest) filter.testModule.getFilteredRequest();
189         
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"));
195         
196         Map attributes = (Map) filteredRequest.getAttribute(AuthenticationFilter.SHIB_ATTRIBUTES_PREFIX);
197         
198         
199         
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 );
206         }
207     }
208     
209     void checkSession(Session session) {
210         assertNotNull(session);
211         assertEquals(APPLICATIONID,session.getApplicationId());
212         
213         
214         
215     }
216     
217     public void testAttributeQuery() throws SAMLException {
218         
219         // Set the URL suffix that triggers SSO processing
220         idp.setRequestUrls("SSO");
221         
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);
226         
227         // Add a userid, as if provided by Basic Authentication or a Filter
228         idp.request.setRemoteUser(NETID);
229         
230         // Block Attribute Push
231         ShibbolethV1SSOHandler.pushAttributeDefault=false;
232         
233         // Call the IdP 
234         idp.testModule.doGet();
235         
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");
240         
241         
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;
247         
248         // Create the Session
249         // Internally an AA Query will fetch the attributes through the 
250         // MockHTTPBindingProvider
251         String sessionId = AssertionConsumerServlet.createSessionFromData(newSessionData);
252         
253         
254         // Now get what was created in case you want to test it.
255         Session session = context.getSessionManager().findSession(sessionId, APPLICATIONID);
256         checkSession(session);
257         
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();
262         
263         checkFilter();
264         
265     }
266     
267     public void testArtifact() throws SAMLException, UnsupportedEncodingException {
268         
269         // Set the URL suffix that triggers SSO processing
270         idp.setRequestUrls("SSO");
271         
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);
276         
277         // Add a userid, as if provided by Basic Authentication or a Filter
278         idp.request.setRemoteUser(NETID);
279         
280         // Attribute Push is implied by Artifact
281         ShibbolethV1SSOHandler.pushAttributeDefault=false;
282         
283         // Call the IdP 
284         idp.testModule.doGet();
285         
286         MockHttpServletResponse response = idp.response;
287         // Get the redirection
288         assertTrue(response.wasRedirectSent());
289         String redirectURL = response.getHeader("Location");
290         
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");
296         }
297         
298         
299         
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;
305         
306         // Create the Session
307         // Internally an AA Query will fetch the attributes through the 
308         // MockHTTPBindingProvider
309         String sessionId = AssertionConsumerServlet.createSessionFromData(newSessionData);
310         
311         
312         // Now get what was created in case you want to test it.
313         Session session = context.getSessionManager().findSession(sessionId, APPLICATIONID);
314         checkSession(session);
315         
316         
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();
321
322         checkFilter();
323      }
324     
325 }