Add MockIdp and test case
authorgilbert <gilbert@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Mon, 21 Nov 2005 20:15:16 +0000 (20:15 +0000)
committergilbert <gilbert@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Mon, 21 Nov 2005 20:15:16 +0000 (20:15 +0000)
git-svn-id: https://subversion.switch.ch/svn/shibboleth/java-idp/trunk@1912 ab3bd59b-922f-494d-bb5f-6f0a3c29deca

tests/edu/internet2/middleware/shibboleth/integration/FileAssertionTest.java
tests/edu/internet2/middleware/shibboleth/runner/MadSignertest.java
tests/edu/internet2/middleware/shibboleth/runner/ShibbolethRunner.java

index b4314db..c1224e5 100644 (file)
 
 package edu.internet2.middleware.shibboleth.integration;
 
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
 import java.util.Date;
 import java.util.Enumeration;
 import java.util.Iterator;
@@ -29,12 +34,17 @@ import junit.framework.TestCase;
 
 import org.apache.commons.codec.binary.Base64;
 import org.apache.log4j.Level;
+import org.opensaml.SAMLException;
 import org.opensaml.SAMLResponse;
 
+import edu.internet2.middleware.shibboleth.idp.provider.ShibbolethV1SSOHandler;
 import edu.internet2.middleware.shibboleth.resource.AuthenticationFilter;
+import edu.internet2.middleware.shibboleth.resource.FilterUtil;
 import edu.internet2.middleware.shibboleth.resource.FilterSupport.NewSessionData;
 import edu.internet2.middleware.shibboleth.runner.MadSignertest;
 import edu.internet2.middleware.shibboleth.runner.ShibbolethRunner;
+import edu.internet2.middleware.shibboleth.runner.MadSignertest.MockIdp;
+import edu.internet2.middleware.shibboleth.runner.ShibbolethRunner.IdpTestContext;
 import edu.internet2.middleware.shibboleth.serviceprovider.AssertionConsumerServlet;
 import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderConfig;
 import edu.internet2.middleware.shibboleth.serviceprovider.ServiceProviderContext;
@@ -68,6 +78,9 @@ public class FileAssertionTest extends TestCase {
     
     /**
      * TestCase setUp
+     * 
+     * <p>There is no IdP or SSO in this test. The IdP function
+     * is performed from assertion files.</p>
      */
     protected void setUp() throws Exception {
         super.setUp();
@@ -101,41 +114,32 @@ public class FileAssertionTest extends TestCase {
   
         newSessionData.applicationId=APPLICATIONID;
         newSessionData.providerId=SP_ENTITY;
-          
-        
-        // Create the static collection of Attributes that are 
-        // returned by the IdP for every principal.
-        // This could be done in each test, just as long as it
-        // is done before the SSO.
-        Attributes attributes = runner.getAttributesCollection();
-        attributes.put(new BasicAttribute("eduPersonAffiliation", AFFILIATION));
-        // scoped
-        attributes.put(new BasicAttribute("eduPersonScopedAffiliation", AFFILIATION));
-        attributes.put(new BasicAttribute("title", TITLE));
-        attributes.put(new BasicAttribute("givenName", GIVENNAME));
-        attributes.put(new BasicAttribute("surname", SURNAME));
-        // not in AAP
-        attributes.put(new BasicAttribute("unacceptable","nonsense"));
-        // not in ARP
-        attributes.put(new BasicAttribute("unreleasable","foolishness"));
+        
     }
     
     /**
-     * Test the Post Profile, Attribute Push
-     * <p>Run SSO, call AssertionConsumerServlet directly, then Run Filter</p>
+     * Test the Post Profile, Attribute Push from an XML Assertion file.
+     * 
+     * <p>Read an AttributePush assertion in from a file, resign it.
+     * Call AssertionConsumerServlet directly, then Run Filter</p>
      */
-    public void testAttributePush() throws Exception {
+    public void testFileAttributePush() throws Exception {
         
+        // Setup a signer with the Example.org keystore
         MadSignertest signer = new MadSignertest("src/conf/idp-example.jks","exampleorg");
+        
+        // Read in and resign a test SAML Response file.
         SAMLResponse samlresponse = 
             signer.signResponseFile("data/AttributePushAssertion.xml", 
-                    "tomcat", new Date());
-        
+                    "tomcat");
         
+        // Now feed the SAMLResponse into the AssertionConsumer
         String bin64assertion = new String(samlresponse.toBase64());
-        String assertion = new String(Base64.decodeBase64(bin64assertion.getBytes()));
-        
         newSessionData.SAMLResponse = bin64assertion; 
+        
+        // End of the Assertion-File part of the test, the rest is
+        // the same as with a real SSO.
+        
         newSessionData.target=TARGET;
         newSessionData.handlerURL=POST_SHIRE;
         
@@ -152,13 +156,6 @@ public class FileAssertionTest extends TestCase {
         filter.request.setMethod("GET");
         filter.testModule.doFilter();
         
-            /*
-             * Sanity Check: doFilter runs just the Filter itself. On 
-             * input there was a Request and Response. When done, there
-             * will be a replacement Request object created by the Filter
-             * wrapping the original request and adding features.
-             */
-
         checkFilter();
     }
     
@@ -201,9 +198,71 @@ public class FileAssertionTest extends TestCase {
     private void checkSession(Session session) {
         assertNotNull(session);
         assertEquals(APPLICATIONID,session.getApplicationId());
+    }
+    
+    /**
+     * Test Attribute Push using a Mock Idp
+     */
+    public void testMockIdp() throws SAMLException, KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException {
+        
+        
+        // Setup a signer with the Example.org keystore
+        MadSignertest signer = new MadSignertest("src/conf/idp-example.jks","exampleorg");
+        
+        // Now create a MockIdp from it
+        MockIdp mockIdp = signer.new MockIdp();
+        
+        // Tell the MockIdP how to respond to an SSO
+        mockIdp.ssoResponseFile = "data/AttributePushAssertion.xml";
+        
+        // Create an IdpTestContext using this MockIdp
+        IdpTestContext idp = runner.new IdpTestContext(mockIdp);
+        
+        // Set the URL suffix that triggers SSO processing
+        idp.resetRequest("SSO");
+        
+        // Add the WAYF/RM parameters
+        idp.testModule.addRequestParameter("target", TARGET);
+        idp.testModule.addRequestParameter("shire",POST_SHIRE);
+        idp.testModule.addRequestParameter("providerId", SP_ENTITY);
         
+        // Add a userid, as if provided by Basic Authentication or a Filter
+        idp.request.setRemoteUser(NETID);
         
+        // Force Attribute Push
+        ShibbolethV1SSOHandler.pushAttributeDefault=true;
         
+        // Call the IdP 
+        idp.testModule.doGet();
+        
+        String bin64assertion = (String) idp.request.getAttribute("assertion");
+        String assertion = new String(Base64.decodeBase64(bin64assertion.getBytes()));
+        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.
+            newSessionData.SAMLResponse = bin64assertion;  
+            newSessionData.target=targetURL;
+        newSessionData.handlerURL=handlerURL;
+        
+        // Create the session, extract pushed Attributes 
+        String sessionId = AssertionConsumerServlet.createSessionFromData(newSessionData);
+        
+        // Now get what was created in case you want to test it.
+        Session session = context.getSessionManager().findSession(sessionId, APPLICATIONID);
+        checkSession(session);
+        
+        // Pass the SessionId to the Filter, let it fetch the attributes
+        filter.resetRequest("test.txt");
+        filter.testModule.addRequestParameter(AuthenticationFilter.SESSIONPARM, sessionId);
+        filter.request.setMethod("GET");
+        filter.testModule.doFilter();
+        
+        checkFilter();
     }
     
+    
 }
index dfc188e..45ff9b8 100644 (file)
@@ -20,6 +20,7 @@ import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.PrintWriter;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
@@ -28,10 +29,20 @@ import java.util.Arrays;
 import java.util.Date;
 import java.util.Iterator;
 
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
 import org.apache.xml.security.signature.XMLSignature;
 import org.opensaml.SAMLAssertion;
+import org.opensaml.SAMLIdentifier;
 import org.opensaml.SAMLResponse;
 
+import com.mockrunner.mock.web.MockHttpServletRequest;
+import com.mockrunner.mock.web.MockHttpServletResponse;
+
 /**
  * Class that signs and resets the timestamps on SAML objects.
  * 
@@ -68,26 +79,47 @@ public class MadSignertest {
     
     /**
      * Sign the SAMLResponse in a test data xml file.
+     * 
+     * <p>SAML Assertions are good for 60 seconds, so
+     * if you want an assertion to be expired set the
+     * timestamp back at least a minute.</p>
+     * 
      * @param path Path to the input XML file.
      * @param alias Alias in the JKS of the signing key.
      * @param now Date to use for timestamps
+     * @param reidentify Option to change response/assertion IDs
+     * 
      * @return SAMLResponse now signed
      */
-    public SAMLResponse signResponseFile(String path, String alias, Date now) 
+    public SAMLResponse signResponseFile(
+            String path, 
+            String alias, 
+            Date now, 
+            boolean reidentify) 
         throws Exception {
+        
         InputStream in = new FileInputStream(path);
         
         if (now==null)
-            now = new Date();
+            now = new Date(); // default is current time
+        SAMLIdentifier defaultIDProvider = ShibbolethRunner.samlConfig.getDefaultIDProvider();
         
+        // Read in and parse the XML and turn it into a SAMLResponse
+        // [obviously it better be a SAML Response to begin with.]
         SAMLResponse r = new SAMLResponse(in);
         
+        if (reidentify)
+            r.setId(defaultIDProvider.getIdentifier());
+        
+        // Retimestamp and resign each assertions
         Iterator assertions = r.getAssertions();
         while (assertions.hasNext()) {
             SAMLAssertion assertion = (SAMLAssertion) assertions.next();
             assertion.setIssueInstant(now);
             assertion.setNotBefore(now);
             assertion.setNotOnOrAfter(new Date(now.getTime() + 60000));
+            if (reidentify)
+                assertion.setId(defaultIDProvider.getIdentifier());
             assertion.sign(
                     XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1,
                     ks.getKey(alias,passwd),
@@ -95,6 +127,8 @@ public class MadSignertest {
                     );
             
         }
+        
+        // Now resign the Response
         r.sign(
                 XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1,
                 ks.getKey(alias,passwd),
@@ -104,4 +138,64 @@ public class MadSignertest {
         return r;
     }
     
+    public SAMLResponse signResponseFile(
+            String path, 
+            String alias) throws Exception{
+        return signResponseFile(path,alias,null,true);
+    }
+    
+    
+    
+    /**
+     * A dummy Idp that can be used to create a ShibbolethRunner
+     * IdPTestContext when the response is to come from a file.
+     */
+    public class MockIdp extends HttpServlet {
+        
+        public String ssoResponseFile = null;
+        public String artifactResponseFile = null;
+        public String attributeResponseFile = null;
+        public String alias = "tomcat";
+        
+        public void init() {}
+
+        public void doGet(HttpServletRequest arg1, 
+                HttpServletResponse arg2) 
+            throws ServletException, IOException {
+            
+            MockHttpServletRequest request = (MockHttpServletRequest) arg1;
+            MockHttpServletResponse response = (MockHttpServletResponse) arg2;
+            
+            String uri = request.getRequestURI();
+            SAMLResponse r = null;
+            
+            
+            // A very simple test for how to respond.
+            
+            try {
+                if (uri.endsWith("SSO")){
+                    r=signResponseFile(ssoResponseFile, alias);
+                    request.setAttribute("assertion",new String(r.toBase64()));
+                    request.setAttribute("shire",request.getParameter("shire"));
+                    request.setAttribute("target",request.getParameter("target"));
+                    return;
+                }
+                if (uri.endsWith("AA")) {
+                    r=signResponseFile(attributeResponseFile, alias);
+                }
+                if (uri.endsWith("Artifact")) {
+                    r=signResponseFile(artifactResponseFile, alias);
+                }
+            } catch (Exception e) {
+                throw new ServletException("test file problem");
+            }
+            
+            response.setContentType("text/xml");
+            PrintWriter writer = response.getWriter();
+            writer.write(r.toString());
+            writer.close();
+            
+        }
+    }
+    
 }
index aff83e1..a844757 100644 (file)
@@ -18,6 +18,7 @@ package edu.internet2.middleware.shibboleth.runner;
 
 import javax.naming.directory.Attributes;
 import javax.naming.directory.BasicAttributes;
+import javax.servlet.http.HttpServlet;
 
 import org.apache.log4j.ConsoleAppender;
 import org.apache.log4j.Layout;
@@ -79,7 +80,7 @@ public class ShibbolethRunner {
     public static String RESOURCE_CONTEXT_URL = SCHEME+"://"+SP_SERVER_NAME+":"+RESOURCE_SERVER_PORT+RESOURCE_CONTEXT_PATH+"/";
     
     
-    private static SAMLConfig samlConfig; // See constructor for use
+    public static SAMLConfig samlConfig; // See constructor for use
 
     
     
@@ -389,7 +390,7 @@ public class ShibbolethRunner {
         
         
         // The IdP Servlet that processes SSO, AA, and Artifact requests
-        public IdPResponder idpServlet;
+        public HttpServlet idpServlet;
         
         /**
          * Construct new context and new IdP from the configuration file.
@@ -404,7 +405,7 @@ public class ShibbolethRunner {
          * and therefore only refresh the Mockrunner objects.
          * Otherwise, initialize a new instance of the IdP.
          */
-        public IdpTestContext(IdPResponder oldidp) {
+        public IdpTestContext(HttpServlet oldidp) {
             
             // ServletContext
             servletContext.setServletContextName("dummy IdP Context");
@@ -419,6 +420,7 @@ public class ShibbolethRunner {
             } else {
                 // reuse an existing initialized servlet
                 idpServlet=oldidp;
+                testModule.setServlet(idpServlet,false);
             }
         }