Refactor and add comments to explain testing without the real IdP
[java-idp.git] / tests / edu / internet2 / middleware / shibboleth / integration / FileAssertionTest.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.FileNotFoundException;
20 import java.io.IOException;
21 import java.security.KeyStoreException;
22 import java.security.NoSuchAlgorithmException;
23 import java.security.cert.CertificateException;
24 import java.util.Enumeration;
25 import java.util.Iterator;
26 import java.util.Map;
27
28 import javax.servlet.http.HttpServletRequest;
29
30 import junit.framework.TestCase;
31
32 import org.apache.commons.codec.binary.Base64;
33 import org.apache.log4j.Level;
34 import org.opensaml.SAMLException;
35 import org.opensaml.SAMLResponse;
36
37 import edu.internet2.middleware.shibboleth.idp.provider.ShibbolethV1SSOHandler;
38 import edu.internet2.middleware.shibboleth.resource.AuthenticationFilter;
39 import edu.internet2.middleware.shibboleth.resource.FilterUtil;
40 import edu.internet2.middleware.shibboleth.resource.FilterSupport.NewSessionData;
41 import edu.internet2.middleware.shibboleth.runner.MadSignertest;
42 import edu.internet2.middleware.shibboleth.runner.ShibbolethRunner;
43 import edu.internet2.middleware.shibboleth.runner.MadSignertest.MockIdp;
44 import edu.internet2.middleware.shibboleth.runner.ShibbolethRunner.IdpTestContext;
45 import edu.internet2.middleware.shibboleth.serviceprovider.AssertionConsumerServlet;
46 import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderConfig;
47 import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderContext;
48 import edu.internet2.middleware.shibboleth.serviceprovider.Session;
49
50 /**
51  * JUnit tests that do not use an instance of the IdP.
52  * Files containing assertions are read from /data and are
53  * processed directly to the SP or else fed back from a 
54  * file driven MockIdp. Tests of this form can be used
55  * to generate non-standard input that the real IdP would
56  * not generate.
57  * 
58  * @author Howard Gilbert
59  */
60 public class FileAssertionTest extends TestCase {
61     
62     // Create some constants, both as parameters and to test responses
63     private static final String GIVENNAME = "Bozo";
64     public static final String SURNAME = "Clown";
65     private static final String TITLE = "clown";
66     public static final String AFFILIATION = "member";
67     public static final String SP_ENTITY = "https://sp.example.org/shibboleth";
68     public static final String POST_SHIRE = "https://sp.example.org/shibboleth-sp/Shibboleth.sso/SAML/POST";
69     public static final String ARTIFACT_SHIRE = "https://sp.example.org/shibboleth-sp/Shibboleth.sso/SAML/Artifact";
70     public static final String TARGET = "https://nonsense";
71     public static final String NETID = "BozoTClown";
72     public static final String APPLICATIONID = "default";
73     
74     ShibbolethRunner runner;
75     ShibbolethRunner.SPTestContext consumer;
76     ShibbolethRunner.AuthenticationFilterContext filter;
77     private NewSessionData newSessionData = new NewSessionData();
78     ServiceProviderContext context;
79     ServiceProviderConfig config;
80     
81     /*********** Services to replace the IdP ****************************/
82     MadSignertest signer;
83     MockIdp mockIdp;
84     IdpTestContext idp;
85     
86     
87     /**
88      * TestCase setUp
89      * 
90      * <p>There is no IdP instance or configuration file.
91      * A MockSignertest object will modify static assertion files,
92      * and a MockIdP can be used to respond to SSO or other requests.</p>
93      */
94     protected void setUp() throws Exception {
95         super.setUp();
96
97         // Static call to set Log4J appenders and levels
98         ShibbolethRunner.loglevel = Level.DEBUG;
99         ShibbolethRunner.setupLogging();
100         
101         // Create the overall testing framework
102         runner = new ShibbolethRunner();
103         
104         /************** MockIdp Setup ***********************************/
105         
106         // Setup a signer with the Example.org keystore
107         signer = new MadSignertest("src/conf/idp-example.jks","exampleorg");
108         
109         // Now create a MockIdp from it
110         mockIdp = signer.new MockIdp();
111         
112         // Create an IdpTestContext using this MockIdp
113         idp = runner.new IdpTestContext(mockIdp);
114         
115         // Make sure it can be found by the MockHttpBindingProvider
116         ShibbolethRunner.idp = idp;
117         
118         /************** end MockIdp setup *******************************/
119         
120         // Initialize the SP with the default config file.
121         runner.setSpConfigFileName("/basicSpHome/spconfig.xml"); 
122         
123         // Use one of two forms to initialize the SP
124         // Only calling AssertionConsumerServlet.createSessionFromData
125             //runner.initializeSP(); 
126         // Using either MockRunner or direct call to SP
127             consumer = ShibbolethRunner.consumer = runner.new SPTestContext();
128         
129         context=ServiceProviderContext.getInstance();
130         config = context.getServiceProviderConfig();
131         
132         // Initialize the Filter and create its separate
133         // Mockrunner simulated context. 
134         filter= runner.getFilter();
135             // Note: If you are going to change the Filter init-param
136             // values, do it here before calling setUp()
137         filter.setUp();
138   
139         newSessionData.applicationId=APPLICATIONID;
140         newSessionData.providerId=SP_ENTITY;
141         
142     }
143     
144     /**
145      * Test the Post Profile, Attribute Push from an XML Assertion file.
146      * 
147      * <p>This test does not use the real IdP or the MockIdp. 
148      * It reads the assertion in directly from a file, and uses
149      * the MadSignertest class directly to change its XML Id fields,
150      * and timestamps and then resign it.
151      * Call AssertionConsumerServlet directly, then Run Filter</p>
152      */
153     public void testFileAttributePush() throws Exception {
154         
155         
156         /**************** Replace IdP with File *************************/
157         // Read in and resign a test SAML Response file.
158         SAMLResponse samlresponse = 
159             signer.signResponseFile("data/AttributePushAssertion.xml", 
160                     "tomcat");
161         
162         // Now feed the SAMLResponse into the AssertionConsumer
163         String bin64assertion = new String(samlresponse.toBase64());
164         newSessionData.SAMLResponse = bin64assertion; 
165         /**************** end of IdP replacement ************************/
166         
167         newSessionData.target=TARGET;
168         newSessionData.handlerURL=POST_SHIRE;
169         
170         // Create the session, extract pushed Attributes 
171         String sessionId = AssertionConsumerServlet.createSessionFromData(newSessionData);
172         
173         // Now get what was created in case you want to test it.
174         Session session = context.getSessionManager().findSession(sessionId, APPLICATIONID);
175         checkSession(session);
176         
177         // Pass the SessionId to the Filter, let it fetch the attributes
178         filter.resetRequest("test.txt");
179         filter.testModule.addRequestParameter(AuthenticationFilter.SESSIONPARM, sessionId);
180         filter.request.setMethod("GET");
181         filter.testModule.doFilter();
182         
183         checkFilter();
184     }
185     
186     /**
187      * Verify correct operation of Filter and wrapped Request object,
188      * including attributes and headers.
189      */
190     private void checkFilter() {
191         // Get the Request Wrapper object created by the Filter
192         HttpServletRequest filteredRequest = 
193             (HttpServletRequest) filter.testModule.getFilteredRequest();
194         
195         assertEquals(NETID,filteredRequest.getRemoteUser());
196         assertEquals(NETID,filteredRequest.getHeader("REMOTE_USER"));
197         assertEquals(SURNAME,filteredRequest.getHeader("Shib-Person-surname"));
198         assertEquals(GIVENNAME,filteredRequest.getHeader("Shib-InetOrgPerson-givenName"));
199         assertEquals(TITLE,filteredRequest.getHeader("Shib-OrgPerson-title"));
200         
201         Map attributes = (Map) filteredRequest.getAttribute(AuthenticationFilter.SHIB_ATTRIBUTES_PREFIX);
202         Iterator iterator = attributes.entrySet().iterator();
203         while (iterator.hasNext()) {
204             Map.Entry entry = (Map.Entry) iterator.next();
205             String key = (String) entry.getKey();
206             String value = (String) entry.getValue();
207             System.out.println(key+" : "+value);
208         }
209         
210         
211         Enumeration headerNames = filteredRequest.getHeaderNames();
212         while (headerNames.hasMoreElements()) {
213             String name = (String) headerNames.nextElement();
214             String value = (String) filteredRequest.getHeader(name);
215             System.out.println(name+ " : "+value );
216         }
217     }
218     
219     /**
220      * Add Session object checking here.
221      */
222     private void checkSession(Session session) {
223         assertNotNull(session);
224         assertEquals(APPLICATIONID,session.getApplicationId());
225     }
226     
227     /**
228      * Test Attribute Push using a Mock Idp.
229      * 
230      * <p>The MockIdp responds to Mockrunner calls for SSO, AA, or
231      * Artifact, but you have to provide a path to a file with a
232      * response you want sent back.
233      */
234     public void testMockIdp() throws SAMLException, KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException {
235         
236         /*********** Use MockIdp instead of real IdP ********************/
237         // Tell the MockIdP how to respond to an SSO
238         mockIdp.ssoResponseFile = "data/AttributePushAssertion.xml";
239         // In attribute push, there will not be an AA query.
240         /*********** That's it!, the rest is standard code **************/
241         
242         
243         // Set the URL suffix that triggers SSO processing
244         idp.resetRequest("SSO");
245         
246         // Add the WAYF/RM parameters
247         idp.testModule.addRequestParameter("target", TARGET);
248         idp.testModule.addRequestParameter("shire",POST_SHIRE);
249         idp.testModule.addRequestParameter("providerId", SP_ENTITY);
250         
251         // Add a userid, as if provided by Basic Authentication or a Filter
252         idp.request.setRemoteUser(NETID);
253         
254         // Force Attribute Push
255         ShibbolethV1SSOHandler.pushAttributeDefault=true;
256         
257         // Call the IdP 
258         idp.testModule.doGet();
259         
260         String bin64assertion = (String) idp.request.getAttribute("assertion");
261         String assertion = new String(Base64.decodeBase64(bin64assertion.getBytes()));
262         String handlerURL = (String) idp.request.getAttribute("shire");
263         String targetURL = (String) idp.request.getAttribute("target");
264         
265         // Create the session directly without MockRunner
266         FilterUtil.sessionDataFromRequest(newSessionData,idp.request);
267             // there was no real redirect, so the next two fields are not
268             // in the places that sessionDataFromRequest expects.
269             newSessionData.SAMLResponse = bin64assertion;  
270             newSessionData.target=targetURL;
271         newSessionData.handlerURL=handlerURL;
272         
273         // Create the session, extract pushed Attributes 
274         String sessionId = AssertionConsumerServlet.createSessionFromData(newSessionData);
275         
276         // Now get what was created in case you want to test it.
277         Session session = context.getSessionManager().findSession(sessionId, APPLICATIONID);
278         checkSession(session);
279         
280         // Pass the SessionId to the Filter, let it fetch the attributes
281         filter.resetRequest("test.txt");
282         filter.testModule.addRequestParameter(AuthenticationFilter.SESSIONPARM, sessionId);
283         filter.request.setMethod("GET");
284         filter.testModule.doFilter();
285         
286         checkFilter();
287     }
288     
289     
290 }