Importing WAYF code
authorwassa <wassa@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Wed, 29 May 2002 22:15:50 +0000 (22:15 +0000)
committerwassa <wassa@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Wed, 29 May 2002 22:15:50 +0000 (22:15 +0000)
git-svn-id: https://subversion.switch.ch/svn/shibboleth/java-idp/trunk@8 ab3bd59b-922f-494d-bb5f-6f0a3c29deca

build.xml
src/edu/internet2/middleware/shibboleth/wayf/Origin.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/wayf/OriginSet.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/wayf/WayfConfig.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/wayf/WayfConfigDigester.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/wayf/WayfException.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/wayf/WayfHandler.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/wayf/WayfOrigins.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/wayf/WayfTester.java [new file with mode: 0755]
webApplication/wayf.jsp [new file with mode: 0755]
webApplication/wayferror.jsp [new file with mode: 0755]

index 0a54273..1962771 100755 (executable)
--- a/build.xml
+++ b/build.xml
@@ -1,28 +1,56 @@
-<project name="shibboleth" default="dist" basedir=".">
-
-  <!-- set global properties for this build -->
-  <property name="src" value="."/>
-  <property name="build" value="build"/>
-  <property name="dist"  value="dist"/>
-  <target name="init">
-    <!-- Create the time stamp -->
-    <tstamp/>
-    <!-- Create the build directory structure used by compile -->
-    <mkdir dir="${build}" />
-  </target>
-
-  <target name="compile" depends="init">
-    <!-- Compile the java code from ${src} into ${build} -->
-    <javac srcdir="${src}" destdir="${build}" classpath=".:/usr/java/jdk1.3.1_02/lib/jre:/usr/local/shib/lib/shibboleth.jar:/usr/local/shib/lib/xmlParserAPIs.jar:/usr/local/shib/lib/xercesImpl.jar:/var/tomcat3/lib/common/servlet.jar:/var/tomcat3/lib/common/mm.mysql-2.0.8-bin.jar"/>
-  </target>
-  <target name="dist" depends="compile">
-    <war warfile="shibb.war" webxml="web.xml">
-      <classes dir="build"/>
-    </war>
-    <copy file="shibboleth.war" tofile="${dist}/shibboleth.war">
-    </copy>
-  </target>
+<project default="dist" basedir=".">
 
-</project>
+       <property name="distname" value="shibboleth"/>
+
+       <!-- set global properties for this build -->
+       <property name="root" value="."/>
+       <property name="src" value="${root}/source"/>
+       <property name="approot" value="${root}/webApplication"/>
+       <property name="build" value="${approot}/WEB-INF/classes"/>
+       <property name="libdir" value="${approot}/WEB-INF/lib"/>
+       <property name="buildlibs" value="${root}/buildlibs"/>
+       <property name="dist" value="${root}/dist"/>
+
+       <path id="build.path">
+               <pathelement path="${classpath}"/>
+               <pathelement location="${build}"/>
+               <fileset dir="${libdir}">
+                       <include name="**/*.jar"/>
+               </fileset>
+               <fileset dir="${buildlibs}">
+                       <include name="**/*.jar"/>
+               </fileset>
+
+       </path>
+
+       <!-- Prepare directory structure for project build-->
+       <target name="init">
+               <mkdir dir="${build}"/>
+               <mkdir dir="${dist}"/>
+       </target>
+
+       <!-- Compile classes and move them to ${build} -->
+       <target name="compile" depends="init">
+               <javac srcdir="${src}" destdir="${build}" includes="**/*.java" debug="on">
+                       <classpath refid="build.path"/>
+               </javac>
+       </target>
 
+       <target name="package">
+               <war warfile="${dist}/${distname}.war" webxml="${approot}/WEB-INF/web.xml" basedir="${approot}" update="no"/>
+       </target>
+
+       <target name="dist" depends="compile, package, clean-build"/>
+
+       <!-- Delete the ${build} and ${dist} directory trees -->
+       <target name="clean" depends="clean-build, clean-dist"/>
+
+       <target name="clean-build">
+               <delete dir="${build}"/>
+       </target>
+
+       <target name="clean-dist">
+               <delete dir="${dist}"/>
+       </target>
+
+</project>
diff --git a/src/edu/internet2/middleware/shibboleth/wayf/Origin.java b/src/edu/internet2/middleware/shibboleth/wayf/Origin.java
new file mode 100755 (executable)
index 0000000..28cc395
--- /dev/null
@@ -0,0 +1,103 @@
+package edu.internet2.middleware.shibboleth.wayf;
+
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.StringTokenizer;
+
+/**
+ * This class represents an Origin site in the shibboleth parlance.
+ * @author             Walter Hoehn
+ */
+
+public class Origin {
+
+    private String name;
+    private ArrayList aliases = new ArrayList();
+    private String handleService;
+
+    /**
+     * Gets the handleService for this origin.
+     * @return Returns a String
+     */
+    public String getHandleService() {
+        return handleService;
+    }
+
+    /**
+     * Sets the handleService for this origin.
+     * @param handleService The handleService to set
+     */
+    public void setHandleService(String handleService) {
+        this.handleService = handleService;
+    }
+
+    /**
+     * Gets the origin name.
+     * @return Returns a String
+     */
+    public String getName() {
+        return name;
+    }
+
+    public String getUrlEncodedName() {
+
+        return URLEncoder.encode(name);
+
+    }
+
+    /**
+     * Sets a name for this origin.
+     * @param name The name to set
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Gets all aliases for this origin.
+     * @return Returns a String[]
+     */
+    public String[] getAliases() {
+        return (String[]) aliases.toArray(new String[0]);
+    }
+
+    /**
+     * Adds an alias for this origin.
+     * @param alias The aliases to set
+     */
+    public void addAlias(String alias) {
+        aliases.add(alias);
+    }
+
+    /**
+     * Determines if a given string matches one of the registered names/aliases of this origin.
+     * @param str The string to match on
+     */
+    public boolean isMatch(String str) {
+
+        Enumeration input = new StringTokenizer(str);
+        while (input.hasMoreElements()) {
+            String currentToken = (String) input.nextElement();
+
+            if (WayfConfig.isIgnoredForMatch(currentToken)) {
+                continue;
+            }
+
+            if (getName().toLowerCase().indexOf(currentToken.toLowerCase()) > -1) {
+                return true;
+            }
+            Iterator aliasit = aliases.iterator();
+            while (aliasit.hasNext()) {
+                String alias = (String) aliasit.next();
+                if (alias.toLowerCase().indexOf(currentToken.toLowerCase()) > -1) {
+                    return true;
+                }
+            }
+
+        }
+        return false;
+    }
+
+}
\ No newline at end of file
diff --git a/src/edu/internet2/middleware/shibboleth/wayf/OriginSet.java b/src/edu/internet2/middleware/shibboleth/wayf/OriginSet.java
new file mode 100755 (executable)
index 0000000..33df22e
--- /dev/null
@@ -0,0 +1,50 @@
+package edu.internet2.middleware.shibboleth.wayf;
+
+import java.util.ArrayList;
+
+/**
+ * This class is used to create logical groupings of shibboleth Origin Sites.
+ * Each grouping is associated with a textual name that might be displayed 
+ * in a UI to accommodate user selection.
+ * @author Walter Hoehn
+ */
+
+public class OriginSet {
+
+       private ArrayList origins = new ArrayList();
+       ;
+       private String name;
+
+       /**
+        * Gets the name.
+        * @return Returns a String
+        */
+       public String getName() {
+               return name;
+       }
+
+       /**
+        * Sets the name.
+        * @param name The name to set
+        */
+       public void setName(String name) {
+               this.name = name;
+       }
+
+       /**
+        * Gets the origins.
+        * @return Returns a Origin[]
+        */
+       public Origin[] getOrigins() {
+               return (Origin[]) origins.toArray(new Origin[0]);
+       }
+
+       /**
+        * Sets the origins.
+        * @param origins The origins to set
+        */
+       public void addOrigin(Origin origin) {
+               origins.add(origin);
+       }
+
+}
diff --git a/src/edu/internet2/middleware/shibboleth/wayf/WayfConfig.java b/src/edu/internet2/middleware/shibboleth/wayf/WayfConfig.java
new file mode 100755 (executable)
index 0000000..6d46f1a
--- /dev/null
@@ -0,0 +1,197 @@
+package edu.internet2.middleware.shibboleth.wayf;
+
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.StringTokenizer;
+
+import javax.servlet.ServletContext;
+
+/**
+ * Class used by the  WAYF service to determine runtime options
+ * Most of the fields of this class should have reasonable defaults set
+ * @author        Walter Hoehn
+ */
+
+public class WayfConfig {
+
+    private static WayfOrigins wd;
+    private static String location;
+    private static String logoLocation = "images/internet2.gif";
+    private static String supportContact = "mailto:shib-support@internet2.org";
+    private static String helpText =
+        "In order to fulfill the request for the  web resource you "
+            + "have just chosen, information must first be obtained from "
+            + "your home institution. Please select the institution with "
+            + "which you are affiliated.";
+    private static String searchResultEmptyText =
+        "No institution found that matches your search " + "criteria, please try again.";
+    private static HashSet ignoredForMatch = new HashSet();
+
+    private static String cache = "SESSION";
+
+    private static ServletContext servletContext;
+
+    /**
+     * Constructor for WayfConfig.
+     */
+    public WayfConfig() {
+        super();
+    }
+
+    /**
+     * Gets the wd.
+     * @return Returns a WayfOrigins
+     */
+    public static WayfOrigins getWAYFData() {
+        return wd;
+    }
+
+    /**
+     * Sets the wd.
+     * @param wd The wd to set
+     */
+    public void setWAYFData(WayfOrigins wd) {
+        WayfConfig.wd = wd;
+    }
+
+    /**
+     * Gets the searchResultEmptyText.
+     * @return Returns a String
+     */
+    public static String getSearchResultEmptyText() {
+        return searchResultEmptyText;
+    }
+
+    /**
+     * Sets the searchResultEmptyText.
+     * @param searchResultEmptyText The searchResultEmptyText to set
+     */
+    public void setSearchResultEmptyText(String searchResultEmptyText) {
+        WayfConfig.searchResultEmptyText = searchResultEmptyText;
+    }
+
+    /**
+     * Gets the helpText.
+     * @return Returns a String
+     */
+    public static String getHelpText() {
+        return helpText;
+    }
+
+    /**
+     * Sets the helpText.
+     * @param helpText The helpText to set
+     */
+    public void setHelpText(String helpText) {
+        WayfConfig.helpText = helpText;
+    }
+
+    /**
+     * Gets the supportContact.
+     * @return Returns a String
+     */
+    public static String getSupportContact() {
+        return supportContact;
+    }
+
+    /**
+     * Sets the supportContact.
+     * @param supportContact The supportContact to set
+     */
+    public void setSupportContact(String supportContact) {
+        WayfConfig.supportContact = supportContact;
+    }
+
+    /**
+     * Gets the logoLocation.
+     * @return Returns a String
+     */
+    public static String getLogoLocation() {
+        return logoLocation;
+    }
+
+    /**
+     * Sets the logoLocation.
+     * @param logoLocation The logoLocation to set
+     */
+    public void setLogoLocation(String logoLocation) {
+        WayfConfig.logoLocation = logoLocation;
+    }
+
+    /**
+     * Gets the location.
+     * @return Returns a String
+     */
+    public static String getLocation() {
+        return location;
+    }
+
+    /**
+     * Sets the location.
+     * @param location The location to set
+     */
+    public void setLocation(String location) {
+        WayfConfig.location = location;
+    }
+
+    /**
+     * Determines if a particular string token should be used for matching when a user searches for origins.
+     * @param str The string to lookup
+     */
+    public static boolean isIgnoredForMatch(String str) {
+
+        if (ignoredForMatch.contains(str.toLowerCase())) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Sets the tokens that should be ignored when a user searches for an origin site.
+     * @param s The ignored tokens are passed as a single string, each separated by whitespace
+     */
+    public void addIgnoredForMatch(String s) {
+
+        ignoredForMatch.add(s.toLowerCase());
+    }
+
+    /**
+     * Gets the servletContext.
+     * @return Returns a ServletContext
+     */
+    public static ServletContext getServletContext() {
+        return servletContext;
+    }
+
+    /**
+     * Sets the servletContext.
+     * @param servletContext The servletContext to set
+     */
+    public static void setServletContext(ServletContext servletContext) {
+        WayfConfig.servletContext = servletContext;
+    }
+
+    /**
+     * Gets the cache.
+     * @return Returns a String
+     */
+    public static String getCache() {
+        return cache;
+    }
+
+    /**
+     * Sets the cache.
+     * @param cache The cache to set
+     */
+    public void setCache(String cache) {
+        if (cache.toUpperCase().equals("NONE")
+            || cache.toUpperCase().equals("SESSION")
+            || cache.toUpperCase().equals("COOKIES")) {
+            WayfConfig.cache = cache.toUpperCase();
+        } else {
+            getServletContext().log("Cache type :" + cache + ": not recognized, using default.");
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/src/edu/internet2/middleware/shibboleth/wayf/WayfConfigDigester.java b/src/edu/internet2/middleware/shibboleth/wayf/WayfConfigDigester.java
new file mode 100755 (executable)
index 0000000..cf1be3c
--- /dev/null
@@ -0,0 +1,126 @@
+package edu.internet2.middleware.shibboleth.wayf;
+
+import javax.xml.parsers.SAXParser;
+import org.apache.commons.digester.Digester;
+import org.xml.sax.XMLReader;
+
+/**
+ * This class is a jakarta Digester style parser for the WAYF configuration file.  
+ * It should populate the WayfConfig object during WAYF initilization. NOTE: It is
+ * assumed that the mutators of this class will only be called by a single thread during
+ * servlet initilization only (NOT thread safe)
+ * @author             Walter Hoehn
+ */
+
+public class WayfConfigDigester extends Digester {
+
+    protected String originClass = "edu.internet2.middleware.shibboleth.wayf.Origin";
+    protected String wayfDataClass = "edu.internet2.middleware.shibboleth.wayf.WayfOrigins";
+    protected String originSetClass = "edu.internet2.middleware.shibboleth.wayf.OriginSet";
+    protected String wayfConfigClass = "edu.internet2.middleware.shibboleth.wayf.WayfConfig";
+    private boolean configured = false;
+
+    /**
+     * Constructor for ShibbolethConfigDigester.
+     */
+    public WayfConfigDigester() {
+        super();
+        configure();
+    }
+
+    /**
+     * Constructor for ShibbolethConfigDigester.
+     * @param parser
+     */
+    public WayfConfigDigester(SAXParser parser) {
+        super(parser);
+        configure();
+    }
+
+    /**
+     * Constructor for ShibbolethConfigDigester.
+     * @param reader
+     */
+    public WayfConfigDigester(XMLReader reader) {
+        super(reader);
+        configure();
+    }
+
+    /**
+     * Gets the originClass.
+     * @return Returns a String
+     */
+    public String getOriginClass() {
+        return originClass;
+    }
+
+    /**
+     * Sets the originClass.
+     * @param originClass The originClass to set
+     */
+    public void setOriginClass(String originClass) {
+        this.originClass = originClass;
+    }
+
+    protected void configure() {
+
+        if (configured == true) {
+            return;
+        }
+        addObjectCreate("ShibbolethConfig", wayfConfigClass);
+        addSetProperties("ShibbolethConfig/WayfConfig");
+        addCallMethod("ShibbolethConfig/WayfConfig/HelpText", "setHelpText", 0);
+        addCallMethod("ShibbolethConfig/WayfConfig/SearchResultEmptyText", "setSearchResultEmptyText", 0);
+        addCallMethod("ShibbolethConfig/WayfConfig/SearchIgnore/String", "addIgnoredForMatch", 0);
+
+        addObjectCreate("ShibbolethConfig/CommonConfig", wayfDataClass);
+        addSetNext("ShibbolethConfig/CommonConfig", "setWAYFData", wayfDataClass);
+
+        addObjectCreate("ShibbolethConfig/CommonConfig/OriginSet", originSetClass);
+        addSetNext("ShibbolethConfig/CommonConfig/OriginSet", "addOriginSet", originSetClass);
+        addSetProperties("ShibbolethConfig/CommonConfig/OriginSet");
+
+        addObjectCreate("ShibbolethConfig/CommonConfig/OriginSet/Origin", originClass);
+        addSetNext("ShibbolethConfig/CommonConfig/OriginSet/Origin", "addOrigin", originClass);
+        addSetProperties("ShibbolethConfig/CommonConfig/OriginSet/Origin");
+
+        addCallMethod("ShibbolethConfig/CommonConfig/OriginSet/Origin/Alias", "addAlias", 1);
+        addCallParam("ShibbolethConfig/CommonConfig/OriginSet/Origin/Alias", 0, "name");
+
+        configured = true;
+
+    }
+
+    /**
+     * Gets the originSetClass.
+     * @return Returns a String
+     */
+    public String getOriginSetClass() {
+        return originSetClass;
+    }
+
+    /**
+     * Sets the originSetClass.
+     * @param originSetClass The originSetClass to set
+     */
+    public void setOriginSetClass(String originSetClass) {
+        this.originSetClass = originSetClass;
+    }
+
+    /**
+     * Gets the wayfDataClass.
+     * @return Returns a String
+     */
+    public String getWayfDataClass() {
+        return wayfDataClass;
+    }
+
+    /**
+     * Sets the wayfDataClass.
+     * @param wayfDataClass The wayfDataClass to set
+     */
+    public void setWayfDataClass(String wayfDataClass) {
+        this.wayfDataClass = wayfDataClass;
+    }
+
+}
diff --git a/src/edu/internet2/middleware/shibboleth/wayf/WayfException.java b/src/edu/internet2/middleware/shibboleth/wayf/WayfException.java
new file mode 100755 (executable)
index 0000000..311bfe0
--- /dev/null
@@ -0,0 +1,13 @@
+package edu.internet2.middleware.shibboleth.wayf;
+
+/**
+ * @author             Walter Hoehn
+ */
+
+public class WayfException extends Exception {
+
+       public WayfException(String message) {
+
+               super(message);
+       }
+}
\ No newline at end of file
diff --git a/src/edu/internet2/middleware/shibboleth/wayf/WayfHandler.java b/src/edu/internet2/middleware/shibboleth/wayf/WayfHandler.java
new file mode 100755 (executable)
index 0000000..10557d4
--- /dev/null
@@ -0,0 +1,288 @@
+package edu.internet2.middleware.shibboleth.wayf;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URLEncoder;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.xml.sax.SAXException;
+
+/**
+ * This is the main handler servlet for the WAYF service.  It configures itself, chooses among 
+ * several handler methods for each request, populates some beans (model), and then passes to an
+ * appropriate jsp page.
+ *
+ * @author             Walter Hoehn
+ */
+
+public class WayfHandler extends HttpServlet {
+
+    private String wayfConfigFileLocation;
+
+    public void init() throws ServletException {
+
+        super.init();
+
+        WayfConfig.setServletContext(getServletContext());
+        loadInitParams();
+        //initialize configuration from file
+        InputStream is = getServletContext().getResourceAsStream(wayfConfigFileLocation);
+        WayfConfigDigester digester = new WayfConfigDigester();
+        try {
+            digester.parse(is);
+            //If the config file cannot be read then we will not be able to start the WAYF... bail out!
+        } catch (SAXException se) {
+            getServletContext().log("Error parsing WAYF configuration file.", se);
+            System.err.println("Error parsing WAYF configuration file: " + se);
+            throw new ServletException("Error parsing WAYF configuration file.", se);
+        } catch (IOException ioe) {
+            getServletContext().log("Error reading WAYF configuration file.", ioe);
+            System.err.println("Error reading WAYF configuration file: " + ioe);
+            throw new ServletException("Error reading WAYF configuration file.", ioe);
+        }
+
+        //Setup appliation-wide beans from config
+        getServletContext().setAttribute("originsets", WayfConfig.getWAYFData().getOriginSets());
+        String wayfLocation = WayfConfig.getLocation();
+        if (wayfLocation == null) {
+            wayfLocation = "WAYF";
+        }
+        getServletContext().setAttribute("wayfLocation", wayfLocation);
+        getServletContext().setAttribute("supportContact", WayfConfig.getSupportContact());
+        getServletContext().setAttribute("helpText", WayfConfig.getHelpText());
+        getServletContext().setAttribute("searchResultEmptyText", WayfConfig.getSearchResultEmptyText());
+        getServletContext().setAttribute("logoLocation", WayfConfig.getLogoLocation());
+    }
+
+    public void doGet(HttpServletRequest req, HttpServletResponse res) {
+
+        //Tell the browser not to cache the WAYF page
+        res.setHeader("Cache-Control", "no-cache");
+        res.setHeader("Pragma", "no-cache");
+
+        //Decide how to route the request based on query string
+        String requestType = req.getParameter("action");
+        if (requestType == null) {
+            requestType = "lookup";
+        }
+        try {
+            if (requestType.equals("deleteFromCache")) {
+                handleDeleteFromCache(req, res);
+            } else if (hasCachedHS(req)) {
+                handleRedirect(req, res, getCachedHS(req));
+            } else if (requestType.equals("search")) {
+                handleSearch(req, res);
+            } else if (requestType.equals("selection")) {
+                handleSelection(req, res);
+            } else {
+                handleLookup(req, res);
+            }
+        } catch (WayfException we) {
+            handleError(req, res, we);
+        }
+    }
+
+    private void loadInitParams() {
+
+        wayfConfigFileLocation = getServletConfig().getInitParameter("WAYFConfigFileLocation");
+        if (wayfConfigFileLocation == null) {
+            wayfConfigFileLocation = "/WEB-INF/conf/shibboleth.xml";
+        }
+
+    }
+
+    private void handleLookup(HttpServletRequest req, HttpServletResponse res) throws WayfException {
+
+        if ((getSHIRE(req) == null) || (getTarget(req) == null)) {
+            throw new WayfException("Invalid or missing data from SHIRE");
+        }
+        req.setAttribute("shire", getSHIRE(req));
+        req.setAttribute("target", getTarget(req));
+        req.setAttribute("encodedShire", URLEncoder.encode(getSHIRE(req)));
+        req.setAttribute("encodedTarget", URLEncoder.encode(getTarget(req)));
+
+        RequestDispatcher rd = req.getRequestDispatcher("/wayf.jsp");
+        try {
+            rd.forward(req, res);
+        } catch (IOException ioe) {
+            throw new WayfException("Problem displaying WAYF UI." + ioe.toString());
+        } catch (ServletException se) {
+            throw new WayfException("Problem displaying WAYF UI." + se.toString());
+        }
+    }
+
+    private void handleSearch(HttpServletRequest req, HttpServletResponse res) throws WayfException {
+
+        if (req.getParameter("string") != null) {
+            Origin[] origins = WayfConfig.getWAYFData().seachForMatchingOrigins(req.getParameter("string"));
+            if (origins.length != 0) {
+                req.setAttribute("searchresults", origins);
+            } else {
+                req.setAttribute("searchResultsEmpty", "true");
+            }
+        }
+        handleLookup(req, res);
+
+    }
+
+    private void handleDeleteFromCache(HttpServletRequest req, HttpServletResponse res) throws WayfException {
+
+        if (WayfConfig.getCache().equals("SESSION")) {
+
+            HttpSession session = req.getSession(false);
+            if (session != null) {
+                session.removeAttribute("selectedHandleService");
+            }
+
+        } else if (WayfConfig.getCache().equals("COOKIES")) {
+            System.out.println("writing with cookes");
+
+            Cookie[] cookies = req.getCookies();
+            for (int i = 0; i < cookies.length; i++) {
+                if (cookies[i].getName().equals("selectedHandleService")) {
+                    cookies[i].setMaxAge(0);
+                    res.addCookie(cookies[i]);
+                }
+            }
+
+        }
+
+        handleLookup(req, res);
+
+    }
+
+    private void handleSelection(HttpServletRequest req, HttpServletResponse res) throws WayfException {
+
+        String handleService = WayfConfig.getWAYFData().lookupHSbyName(req.getParameter("origin"));
+        if (handleService == null) {
+            handleLookup(req, res);
+        } else {
+            addHsToCache(req, res, handleService);
+            handleRedirect(req, res, handleService);
+        }
+
+    }
+
+    private void addHsToCache(HttpServletRequest req, HttpServletResponse res, String handleService) {
+
+        if (WayfConfig.getCache().equals("NONE")) {
+            return;
+        } else if (WayfConfig.getCache().equals("SESSION")) {
+
+            HttpSession session = req.getSession(true);
+            session.setMaxInactiveInterval(7200);
+            session.setAttribute("selectedHandleService", handleService);
+        } else if (WayfConfig.getCache().equals("COOKIES")) {
+
+            Cookie cacheCookie = new Cookie("selectedHandleService", handleService);
+            cacheCookie.setComment("Used to cache selection of a user's Handle Service");
+
+            //Should probably get this stuff from config
+            /**     
+             cacheCookie.setMaxAge();
+             cacheCookie.setDomain();
+             **/
+            res.addCookie(cacheCookie);
+
+        } else {
+            WayfConfig.getServletContext().log("Invalid Cache type specified: running with cache type NONE.");
+        }
+    }
+
+    private void handleRedirect(HttpServletRequest req, HttpServletResponse res, String handleService)
+        throws WayfException {
+
+        String shire = getSHIRE(req);
+        String target = getTarget(req);
+
+        try {
+            res.sendRedirect(
+                handleService + "?target=" + URLEncoder.encode(target) + "&shire=" + URLEncoder.encode(shire));
+        } catch (IOException ioe) {
+            throw new WayfException("Error forwarding to HS: " + ioe.toString());
+        }
+
+    }
+
+    private void handleError(HttpServletRequest req, HttpServletResponse res, WayfException we) {
+
+        getServletContext().log("WAYF Failure: " + we.toString());
+        req.setAttribute("errorText", we.toString());
+        RequestDispatcher rd = req.getRequestDispatcher("/wayferror.jsp");
+
+        try {
+            rd.forward(req, res);
+        } catch (IOException ioe) {
+            getServletContext().log("Problem trying to display WAYF error page: " + ioe.toString());
+            System.err.println("Problem trying to display WAYF error page: " + ioe.toString());
+        } catch (ServletException se) {
+            getServletContext().log("Problem trying to display WAYF error page: " + se.toString());
+            System.err.println("Problem trying to display WAYF error page: " + se.toString());
+        }
+    }
+
+    private String getSHIRE(HttpServletRequest req) throws WayfException {
+
+        String shire = (String) req.getAttribute("shire");
+        if (req.getParameter("shire") != null) {
+            shire = req.getParameter("shire");
+        }
+        if (shire == null) {
+            throw new WayfException("Invalid data from SHIRE: No acceptance URL received.");
+        }
+        return shire;
+    }
+
+    private String getTarget(HttpServletRequest req) throws WayfException {
+
+        String target = (String) req.getAttribute("target");
+        if (req.getParameter("target") != null) {
+            target = req.getParameter("target");
+        }
+        if (target == null) {
+            throw new WayfException("Invalid data from SHIRE: No target URL received.");
+        }
+        return target;
+    }
+
+    private boolean hasCachedHS(HttpServletRequest req) {
+
+        if (getCachedHS(req) == null) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+    private String getCachedHS(HttpServletRequest req) {
+
+        if (WayfConfig.getCache().equals("NONE")) {
+            return null;
+        } else if (WayfConfig.getCache().equals("SESSION")) {
+            HttpSession session = req.getSession(false);
+            if (session == null) {
+                return null;
+            }
+            return (String) session.getAttribute("selectedHandleService");
+
+        } else if (WayfConfig.getCache().equals("COOKIES")) {
+
+            Cookie[] cookies = req.getCookies();
+            for (int i = 0; i < cookies.length; i++) {
+                if (cookies[i].getName().equals("selectedHandleService")) {
+                    return cookies[i].getValue();
+                }
+            }
+
+        }
+        WayfConfig.getServletContext().log("Invalid Cache type specified: running with cache type NONE.");
+        return null;
+
+    }
+
+}
\ No newline at end of file
diff --git a/src/edu/internet2/middleware/shibboleth/wayf/WayfOrigins.java b/src/edu/internet2/middleware/shibboleth/wayf/WayfOrigins.java
new file mode 100755 (executable)
index 0000000..7dab51b
--- /dev/null
@@ -0,0 +1,60 @@
+package edu.internet2.middleware.shibboleth.wayf;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+
+/**
+ * This class is a container for OriginSets, allowing lookup and searching of the same.
+ * @author             Walter Hoehn
+ */
+
+public class WayfOrigins {
+
+       private ArrayList originSets = new ArrayList();
+
+       public OriginSet[] getOriginSets() {
+               return (OriginSet[]) originSets.toArray(new OriginSet[0]);
+       }
+
+       public void addOriginSet(OriginSet originSet) {
+               originSets.add(originSet);
+       }
+
+       public String lookupHSbyName(String originName) {
+               if (originName != null) {
+                       Iterator originSetIt = originSets.iterator();
+                       while (originSetIt.hasNext()) {
+
+                               OriginSet originSet = (OriginSet) originSetIt.next();
+                               Origin[] origins = originSet.getOrigins();
+                               for (int i = 0;(i < origins.length); i++) {
+                                       if (originName.equals(origins[i].getName())) {
+                                               return origins[i].getHandleService();
+                                       }
+                               }
+                       }
+
+               }
+               return null;
+
+       }
+
+       public Origin[] seachForMatchingOrigins(String searchString) {
+
+               Iterator originSetIt = originSets.iterator();
+               HashSet searchResults = new HashSet();
+               while (originSetIt.hasNext()) {
+
+                       OriginSet originSet = (OriginSet) originSetIt.next();
+                       Origin[] origins = originSet.getOrigins();
+                       for (int i = 0;(i < origins.length); i++) {
+                               if (origins[i].isMatch(searchString)) {
+                                       searchResults.add(origins[i]);
+                               }
+                       }
+               }
+               return (Origin[]) searchResults.toArray(new Origin[0]);
+       }
+
+}
diff --git a/src/edu/internet2/middleware/shibboleth/wayf/WayfTester.java b/src/edu/internet2/middleware/shibboleth/wayf/WayfTester.java
new file mode 100755 (executable)
index 0000000..b63ed3c
--- /dev/null
@@ -0,0 +1,34 @@
+package edu.internet2.middleware.shibboleth.wayf;
+
+import java.io.IOException;
+import java.net.URLEncoder;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/*
+ * This class is simply redirects to hardcoded URL for the WAYF.  Created for testing during 
+ * development.  Should probably delete later and replace with a proper testing environment.
+ */
+
+public class WayfTester extends HttpServlet {
+
+       private String acceptanceURL = "http://localhost/wayf/SHIRE";
+       private String targetURL = "http://localhost/wayf/success.html";
+
+       public void doGet(HttpServletRequest req, HttpServletResponse res) {
+
+               
+               try {
+                       res.sendRedirect(
+                               "WAYF" + "?target=" + URLEncoder.encode(targetURL) + "&shire=" + URLEncoder.encode(acceptanceURL));
+               } catch (IOException ioe) {
+                       System.out.println("WAYF Tester Error");
+               }
+
+       }
+
+}
diff --git a/webApplication/wayf.jsp b/webApplication/wayf.jsp
new file mode 100755 (executable)
index 0000000..f9217a5
--- /dev/null
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html 
+       PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
+       "DTD/xhtml1-strict.dtd">
+       <%@ taglib uri="/WEB-INF/tlds/struts-logic.tld" prefix="logic" %>
+       <%@ taglib uri="/WEB-INF/tlds/struts-bean.tld" prefix="bean" %>
+       <jsp:useBean id="originsets" scope="application" class="edu.internet2.middleware.shibboleth.wayf.OriginSet[]"/>
+       <jsp:useBean id="wayfLocation" scope="application" class="java.lang.String"/>
+       <jsp:useBean id="helpText" scope="application" class="java.lang.String"/>
+       <jsp:useBean id="supportContact" scope="application" class="java.lang.String"/>
+       <jsp:useBean id="shire" scope="request" class="java.lang.String"/>
+       <jsp:useBean id="target" scope="request" class="java.lang.String"/>
+       <jsp:useBean id="encodedShire" scope="request" class="java.lang.String"/>
+       <jsp:useBean id="encodedTarget" scope="request" class="java.lang.String"/>
+       <jsp:useBean id="searchResultEmptyText" scope="application" class="java.lang.String"/>
+       <jsp:useBean id="logoLocation" scope="application" class="java.lang.String"/>
+       <logic:present name="searchresults" scope="request">
+               <jsp:useBean id="searchresults" scope="request" class="edu.internet2.middleware.shibboleth.wayf.Origin[]"/>
+       </logic:present>
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+       <link rel="stylesheet" type="text/css" href="main.css" />
+       <title>Access Request</title>
+</head>
+
+<body>
+
+<div class="head">
+
+<img src="<bean:write name="logoLocation" />" alt="Logo" />
+<h1>Inter-institutional Access Request</h1>
+<p class="text"><bean:write name="helpText" /></p>
+</div>
+
+<div class="search">
+
+       <logic:present name="searchResultsEmpty" scope="request">
+               <p class="error"><bean:write name="searchResultEmptyText" /></p>
+       </logic:present>
+       
+       <logic:present name="searchresults" scope="request">
+               <ul>
+               <logic:iterate id="currResult" name="searchresults">
+                       <li>
+                       <a href="<bean:write name="wayfLocation" />?action=selection&amp;origin=<jsp:getProperty name="currResult" property="urlEncodedName" />&amp;shire=<bean:write name="encodedShire" />&amp;target=<bean:write name="encodedTarget" />"><jsp:getProperty name="currResult" property="name" /></a>
+                       </li>
+               </logic:iterate>
+               </ul>           
+       </logic:present>
+       <form method="get" action="<bean:write name="wayfLocation" />">
+               <p>
+                       <input type="hidden" name="shire" value="<bean:write name="shire" />" />
+                       <input type="hidden" name="target" value="<bean:write name="target" />" />
+                       <input type="hidden" name="action" value="search" />
+                       <input type="text" name="string" />
+                       <input type="submit" value="Search" />
+               </p>
+       </form>
+       
+</div>
+
+<div class="list">
+
+<logic:iterate id="originset" name="originsets">
+<h2><jsp:getProperty name="originset" property="name" /></h2>
+<form method="get" action="<bean:write name="wayfLocation" />">
+<p>
+<input type="hidden" name="shire" value="<bean:write name="shire" />" />
+<input type="hidden" name="target" value="<bean:write name="target" />" />
+<input type="hidden" name="action" value="selection" />
+<select name="origin">
+       <logic:iterate id="origin" name="originset" property="origins">
+               <option value="<jsp:getProperty name="origin" property="name" />">
+               <jsp:getProperty name="origin" property="name" />
+               </option>
+       </logic:iterate>
+</select>
+<input type="submit" value="Select" />
+</p>
+</form>
+</logic:iterate>
+
+</div>
+
+<p class="text">Need assistance? Send mail to <a href="<bean:write name="supportContact" />"><bean:write name="supportContact" /></a> with description.</p>
+
+
+</body>
+</html>
\ No newline at end of file
diff --git a/webApplication/wayferror.jsp b/webApplication/wayferror.jsp
new file mode 100755 (executable)
index 0000000..f288a27
--- /dev/null
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html 
+       PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
+       "DTD/xhtml1-strict.dtd">
+       <%@ taglib uri="/WEB-INF/tlds/struts-logic.tld" prefix="logic" %>
+       <%@ taglib uri="/WEB-INF/tlds/struts-bean.tld" prefix="bean" %>
+       
+       <jsp:useBean id="wayfLocation" scope="application" class="java.lang.String"/>
+       <jsp:useBean id="errorText" scope="request" class="java.lang.String"/>
+       <jsp:useBean id="supportContact" scope="application" class="java.lang.String"/>
+       <jsp:useBean id="logoLocation" scope="application" class="java.lang.String"/>
+       
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+       <link rel="stylesheet" type="text/css" href="main.css" />
+       <title>Access System Failure</title>
+</head>
+
+<body>
+<div class="head">
+<img src="<bean:write name="logoLocation" />" alt="Logo" />
+<h1>Inter-institutional Access System Failure</h1>
+</div>
+
+<p>The inter-institutional access system experienced a technical failure.</p>
+
+<p>Please email <a href="mailto:<bean:write name="supportContact" />"><bean:write name="supportContact" /></a> and include the following error message:</p>
+
+<p class="error">WAYF failure at (<bean:write name="wayfLocation" />)</p>
+
+<p><bean:write name="errorText" /></p>
+
+
+</body>
+</html>
\ No newline at end of file