Add SP MockRunner interface class, code an example of its use, improve comments
authorgilbert <gilbert@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Wed, 9 Nov 2005 18:46:50 +0000 (18:46 +0000)
committergilbert <gilbert@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Wed, 9 Nov 2005 18:46:50 +0000 (18:46 +0000)
git-svn-id: https://subversion.switch.ch/svn/shibboleth/java-idp/trunk@1901 ab3bd59b-922f-494d-bb5f-6f0a3c29deca

src/edu/internet2/middleware/shibboleth/serviceprovider/SessionManager.java
tests/edu/internet2/middleware/shibboleth/integration/IntegrationTest.java
tests/edu/internet2/middleware/shibboleth/runner/MockHTTPBindingProvider.java
tests/edu/internet2/middleware/shibboleth/runner/ShibbolethRunner.java

index baccca4..c2caff6 100644 (file)
@@ -399,7 +399,7 @@ reserveSession(
                         Iterator values = attribute.getValues();
                         while (values.hasNext()){
                             String val = (String) values.next();
-                            sb.append(name+" "+namespace+" "+val);
+                            sb.append(name+" - "+" "+val+"\n");
                         }
                     }
                 }
index 6728296..f62702e 100644 (file)
@@ -49,26 +49,30 @@ import edu.internet2.middleware.shibboleth.serviceprovider.Session;
  */
 public class IntegrationTest extends TestCase {
     
+    // Create some constants, both as parameters and to test responses
     private static final String GIVENNAME = "Bozo";
     public static final String SURNAME = "Clown";
     private static final String TITLE = "clown";
     public static final String AFFILIATION = "member";
     public static final String SP_ENTITY = "https://sp.example.org/shibboleth";
-    public static final String POST_SHIRE = "https://sp.example.org/Shibboleth.sso/SAML/POST";
-    public static final String ARTIFACT_SHIRE = "https://sp.example.org/Shibboleth.sso/SAML/Artifact";
+    public static final String POST_SHIRE = "https://sp.example.org/shibboleth-sp/Shibboleth.sso/SAML/POST";
+    public static final String ARTIFACT_SHIRE = "https://sp.example.org/shibboleth-sp/Shibboleth.sso/SAML/Artifact";
     public static final String TARGET = "https://nonsense";
     public static final String NETID = "BozoTClown";
     public static final String APPLICATIONID = "default";
     
     ShibbolethRunner runner;
     ShibbolethRunner.IdpTestContext idp;
+    ShibbolethRunner.SPTestContext consumer;
     ShibbolethRunner.AuthenticationFilterContext filter;
     private NewSessionData newSessionData = new NewSessionData();
     ServiceProviderContext context;
     ServiceProviderConfig config;
     
     
-    
+    /**
+     * TestCase setUp
+     */
     protected void setUp() throws Exception {
         super.setUp();
 
@@ -87,7 +91,13 @@ public class IntegrationTest extends TestCase {
         
         // Initialize the SP with the default config file.
         runner.setSpConfigFileName("/basicSpHome/spconfig.xml"); // default value
-        runner.initializeSP();
+        
+        // Use one of two forms to initialize the SP
+        // If only calling AssertionConsumerServlet.createSessionFromData directly
+            //runner.initializeSP(); 
+        // If calling AssertionConsumerServlet through MockRunner
+            consumer = ShibbolethRunner.consumer = runner.new SPTestContext();
+        
         context=ServiceProviderContext.getInstance();
         config = context.getServiceProviderConfig();
         
@@ -119,7 +129,10 @@ public class IntegrationTest extends TestCase {
         attributes.put(new BasicAttribute("unreleasable","foolishness"));
     }
     
-    
+    /**
+     * Test the Post Profile, Attribute Push
+     * <p>Run SSO, call AssertionConsumerServlet directly, then Run Filter</p>
+     */
     public void testAttributePush() throws SAMLException {
         
         // Set the URL suffix that triggers SSO processing
@@ -152,7 +165,7 @@ public class IntegrationTest extends TestCase {
         String handlerURL = (String) idp.request.getAttribute("shire");
         String targetURL = (String) idp.request.getAttribute("target");
         
-        
+        // Create the session directly without MockRunner
         FilterUtil.sessionDataFromRequest(newSessionData,idp.request);
             // there was no real redirect, so the next two fields are not
             // in the places that sessionDataFromRequest expects.
@@ -182,7 +195,11 @@ public class IntegrationTest extends TestCase {
         checkFilter();
     }
     
-    void checkFilter() {
+    /**
+     * Verify correct operation of Filter and wrapped Request object,
+     * including attributes and headers.
+     */
+    private void checkFilter() {
         // Get the Request Wrapper object created by the Filter
         HttpServletRequest filteredRequest = 
             (HttpServletRequest) filter.testModule.getFilteredRequest();
@@ -196,8 +213,6 @@ public class IntegrationTest extends TestCase {
         Map attributes = (Map) filteredRequest.getAttribute(AuthenticationFilter.SHIB_ATTRIBUTES_PREFIX);
         
         
-        
-        // Now do something that uses Filter supplied logic
         Enumeration headerNames = filteredRequest.getHeaderNames();
         while (headerNames.hasMoreElements()) {
             String name = (String) headerNames.nextElement();
@@ -206,7 +221,10 @@ public class IntegrationTest extends TestCase {
         }
     }
     
-    void checkSession(Session session) {
+    /**
+     * Add Session object checking here.
+     */
+    private void checkSession(Session session) {
         assertNotNull(session);
         assertEquals(APPLICATIONID,session.getApplicationId());
         
@@ -214,6 +232,10 @@ public class IntegrationTest extends TestCase {
         
     }
     
+    /**
+     * Test the Post Profile with Attribute Query
+     * <p>Run SSO, Run AssertionConsumerServlet, then Run Filter</p>
+     */
     public void testAttributeQuery() throws SAMLException {
         
         // Set the URL suffix that triggers SSO processing
@@ -237,19 +259,23 @@ public class IntegrationTest extends TestCase {
         String assertion = new String(Base64.decodeBase64(bin64assertion.getBytes()));
         String handlerURL = (String) idp.request.getAttribute("shire");
         String targetURL = (String) idp.request.getAttribute("target");
+
+        // Simulate the POST to the SP Context using MockRunner
+        consumer.testModule.addRequestParameter("SAMLResponse",bin64assertion);
+        consumer.testModule.addRequestParameter("TARGET",targetURL);
+        consumer.setRequestUrls("Shibboleth.sso/SAML/POST");
+        consumer.testModule.doPost();
+        
+        // Now check up on what the AssertionConsumerServlet did with the POST
+        MockHttpServletResponse response = consumer.response;
+        assertTrue(response.wasRedirectSent());
+        String redirectURL = response.getHeader("Location");
         
-        
-        // Build the parameter for Session creation
-        FilterUtil.sessionDataFromRequest(newSessionData,idp.request);
-        newSessionData.SAMLResponse = bin64assertion; // test logic 
-        newSessionData.target=targetURL;
-        newSessionData.handlerURL=handlerURL;
-        
-        // Create the Session
-        // Internally an AA Query will fetch the attributes through the 
-        // MockHTTPBindingProvider
-        String sessionId = AssertionConsumerServlet.createSessionFromData(newSessionData);
-        
+        // The SessionId is on the end of the redirected URL
+        int pos = redirectURL.indexOf(AssertionConsumerServlet.SESSIONPARM);
+        assertTrue(pos>0);
+        String sessionId = redirectURL.substring(
+                pos+AssertionConsumerServlet.SESSIONPARM.length()+1);
         
         // Now get what was created in case you want to test it.
         Session session = context.getSessionManager().findSession(sessionId, APPLICATIONID);
@@ -264,6 +290,10 @@ public class IntegrationTest extends TestCase {
         
     }
     
+    /**
+     * Test Artifact
+     * <p>Run SSO, call AssertionConsumerServlet directly, then Run Filter</p>
+     */
     public void testArtifact() throws SAMLException, UnsupportedEncodingException {
         
         // Set the URL suffix that triggers SSO processing
@@ -283,29 +313,27 @@ public class IntegrationTest extends TestCase {
         // Call the IdP 
         idp.testModule.doGet();
         
+        // Now check the response from the IdP
         MockHttpServletResponse response = idp.response;
-        // Get the redirection
         assertTrue(response.wasRedirectSent());
         String redirectURL = response.getHeader("Location");
         
+        // The artifacts were appended to the end of the Redirect URL
         String[] splits = redirectURL.split("\\&SAMLart=");
         assertTrue(splits.length>1);
-        String[] samlArt = new String[splits.length-1];
-        for (int i=0;i<samlArt.length;i++) {
-            samlArt[i]=URLDecoder.decode(splits[i+1],"UTF-8");
+        String[] artifactArray = new String[splits.length-1];
+        for (int i=0;i<artifactArray.length;i++) {
+            artifactArray[i]=URLDecoder.decode(splits[i+1],"UTF-8");
         }
         
-        
-        
         // Build the parameter for Session creation
         FilterUtil.sessionDataFromRequest(newSessionData,idp.request);
-        newSessionData.SAMLArt=samlArt;
+        newSessionData.SAMLArt=artifactArray;
         newSessionData.target=TARGET;
         newSessionData.handlerURL=ARTIFACT_SHIRE;
         
         // Create the Session
-        // Internally an AA Query will fetch the attributes through the 
-        // MockHTTPBindingProvider
+        // Under the covers, SAML will see the Artifact and fetch the Assertion
         String sessionId = AssertionConsumerServlet.createSessionFromData(newSessionData);
         
         
index 4046f68..2a49bda 100644 (file)
@@ -33,8 +33,6 @@ import org.apache.xml.security.c14n.CanonicalizationException;
 import org.apache.xml.security.c14n.Canonicalizer;
 import org.apache.xml.security.c14n.InvalidCanonicalizerException;
 import org.opensaml.BindingException;
-import org.opensaml.SAMLBinding;
-import org.opensaml.SAMLConfig;
 import org.opensaml.SAMLException;
 import org.opensaml.SAMLRequest;
 import org.opensaml.SAMLResponse;
index cea0e07..e3f1abe 100644 (file)
@@ -37,8 +37,7 @@ import com.mockrunner.servlet.ServletTestModule;
 import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
 import edu.internet2.middleware.shibboleth.idp.IdPResponder;
 import edu.internet2.middleware.shibboleth.resource.AuthenticationFilter;
-import edu.internet2.middleware.shibboleth.resource.FilterSupport;
-import edu.internet2.middleware.shibboleth.resource.FilterSupport.RMAppInfo;
+import edu.internet2.middleware.shibboleth.serviceprovider.AssertionConsumerServlet;
 import edu.internet2.middleware.shibboleth.serviceprovider.FilterSupportImpl;
 import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderConfig;
 import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderContext;
@@ -58,15 +57,18 @@ public class ShibbolethRunner {
     
     
     public static int SERVER_PORT = 443;
-    public static String SERVER_NAME = "idp.example.org";
+    public static int RESOURCE_SERVER_PORT = 9443;
+    public static String IDP_SERVER_NAME = "idp.example.org";
+    public static String SP_SERVER_NAME = "sp.example.org";
     public static String SCHEME = "https";
     public static String PROTOCOL = "HTTP/1.1";
-    public static String CONTEXT_PATH = "/shibboleth-idp";
-    public static String REMOTE_ADDR = "127.0.0.1";
+    public static String IDP_CONTEXT_PATH = "/shibboleth-idp";
+    public static String SP_CONTEXT_PATH = "/shibboleth-sp";
     public static String RESOURCE_CONTEXT_PATH = "/secure";
-    public static int RESOURCE_SERVER_PORT = 9443;
-    public static String CONTEXT_URL = SCHEME+"://"+SERVER_NAME+CONTEXT_PATH+"/";
-    public static String RESOURCE_CONTEXT_URL = SCHEME+"://"+SERVER_NAME+":"+RESOURCE_SERVER_PORT+RESOURCE_CONTEXT_PATH+"/";
+    public static String REMOTE_ADDR = "127.0.0.1";
+    public static String IDP_CONTEXT_URL = SCHEME+"://"+IDP_SERVER_NAME+IDP_CONTEXT_PATH+"/";
+    public static String SP_CONTEXT_URL = SCHEME+"://"+SP_SERVER_NAME+SP_CONTEXT_PATH+"/";
+    public static String RESOURCE_CONTEXT_URL = SCHEME+"://"+SP_SERVER_NAME+":"+RESOURCE_SERVER_PORT+RESOURCE_CONTEXT_PATH+"/";
     
     
     private static SAMLConfig samlConfig; 
@@ -174,9 +176,15 @@ public class ShibbolethRunner {
     }
     
     private static boolean SPinitialized = false; // don't do it twice
+    public static SPTestContext consumer = null;
     
     /**
-     * Load an SP configuration file.
+     * Load an SP configuration file if you are not using SPTestContext.
+     * 
+     * <p>Calling this routine does not create a MockRunner context
+     * to call the AssertionConsumerServlet. However, you can still
+     * create sessions by directly calling SessionManager.</p>
+     * 
      * @throws ShibbolethConfigurationException  if bad config file
      */
     public void initializeSP() 
@@ -190,9 +198,77 @@ public class ShibbolethRunner {
         ServiceProviderConfig config = new ServiceProviderConfig();
         context.setServiceProviderConfig(config);
         config.loadConfigObjects(spConfigFileName);
+        
+        // Plug an instance of FilterSupportImpl into the Filter
+        FilterSupportImpl service = new FilterSupportImpl();
+        AuthenticationFilter.setFilterSupport(service);
+        
     }
     
+    
+    /**
+     * A MockRunner context for the AssertionConsumerServlet.
+     */
+    public class SPTestContext {
 
+        // The Factory creates the Request, Response, Session, etc.
+        public WebMockObjectFactory factory = new WebMockObjectFactory();
+        
+        // The TestModule runs the Servlet and Filter methods in the simulated container
+        public ServletTestModule testModule = new ServletTestModule(factory);
+        
+        // Now simulated Servlet API objects
+        public MockServletContext servletContext= factory.getMockServletContext();
+        public MockFilterConfig filterConfig= factory.getMockFilterConfig();
+        public MockHttpServletResponse response = factory.getMockResponse();
+        public MockHttpServletRequest request = factory.getMockRequest();
+        
+        
+        // The Servlet object is created by Mockrunner
+        public AssertionConsumerServlet spServlet;
+        
+        
+        /**
+         * Construct the related objects
+         */
+        public SPTestContext() {
+            
+            // ServletContext
+            servletContext.setServletContextName("dummy SP Context");
+            servletContext.setInitParameter("ServiceProviderConfigFile", spConfigFileName);
+            
+            
+            // Create instance of Filter class, add to chain, call its init()
+            // NOTE: The SP reads its configuration file and initializes
+            // itself within this call.
+            spServlet = (AssertionConsumerServlet) testModule.createServlet(AssertionConsumerServlet.class);
+            SPinitialized=true;
+            
+            // Unchanging properties of the HttpServletRequest
+            request.setRemoteAddr(REMOTE_ADDR);
+            request.setContextPath(SP_CONTEXT_PATH);
+            request.setProtocol(PROTOCOL);
+            request.setScheme(SCHEME);
+            request.setServerName(SP_SERVER_NAME);
+            request.setServerPort(SERVER_PORT);
+            
+        }
+        
+        /**
+         * Set the fields of the request that depend on a suffix,
+         */
+        public void setRequestUrls(String suffix) {
+            request.setRequestURI(SP_CONTEXT_URL+suffix);
+            request.setRequestURL(SP_CONTEXT_URL+suffix);
+            request.setServletPath(SP_CONTEXT_PATH+"/"+suffix);
+        }
+        
+    }
+
+    
+    
+    
+    
     
     /*
      * Setup the IdP interface object
@@ -294,10 +370,10 @@ public class ShibbolethRunner {
             
             // Unchanging properties of the HttpServletRequest
             request.setRemoteAddr(REMOTE_ADDR);
-            request.setContextPath(CONTEXT_PATH);
+            request.setContextPath(IDP_CONTEXT_PATH);
             request.setProtocol(PROTOCOL);
             request.setScheme(SCHEME);
-            request.setServerName(SERVER_NAME);
+            request.setServerName(IDP_SERVER_NAME);
             request.setServerPort(SERVER_PORT);
             
         }
@@ -307,9 +383,9 @@ public class ShibbolethRunner {
          * normally SSO, AA, or Artifact
          */
         public void setRequestUrls(String suffix) {
-            request.setRequestURI(CONTEXT_URL+suffix);
-            request.setRequestURL(CONTEXT_URL+suffix);
-            request.setServletPath(CONTEXT_PATH+"/"+suffix);
+            request.setRequestURI(IDP_CONTEXT_URL+suffix);
+            request.setRequestURL(IDP_CONTEXT_URL+suffix);
+            request.setServletPath(IDP_CONTEXT_PATH+"/"+suffix);
         }
         
     }
@@ -397,10 +473,6 @@ public class ShibbolethRunner {
         // Filter objects
         private AuthenticationFilter filter;
         
-        // SP configuration objects
-        private FilterSupport service;
-        private RMAppInfo rmAppInfo;
-
        public AuthenticationFilterContext() {
             
             // ServletContext (argument to Filters and Servlets)
@@ -426,18 +498,12 @@ public class ShibbolethRunner {
             // Note: if the SP is already initialized, this noops.
             initializeSP();
             
-            // Plug an instance of FilterSupportImpl into the Filter
-            service = new FilterSupportImpl();
-            AuthenticationFilter.setFilterSupport(service);
-
-            // Get our own copy of SP Config info for Assert statements
-            rmAppInfo = service.getRMAppInfo("default");
 
             request.setRemoteAddr(REMOTE_ADDR);
             request.setContextPath(RESOURCE_CONTEXT_PATH);
             request.setProtocol(PROTOCOL);
             request.setScheme(SCHEME);
-            request.setServerName(SERVER_NAME);
+            request.setServerName(SP_SERVER_NAME);
             request.setServerPort(RESOURCE_SERVER_PORT);
         }