Setup validation for WAYF configuration files.
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / wayf / WayfService.java
1 package edu.internet2.middleware.shibboleth.wayf;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.net.URLEncoder;
6
7 import javax.servlet.RequestDispatcher;
8 import javax.servlet.ServletException;
9 import javax.servlet.UnavailableException;
10 import javax.servlet.http.HttpServlet;
11 import javax.servlet.http.HttpServletRequest;
12 import javax.servlet.http.HttpServletResponse;
13
14 import org.apache.log4j.Logger;
15 import org.xml.sax.SAXException;
16
17 /**
18  * A servlet implementation of the Shibboleth WAYF service.  Allows a browser user to 
19  * select from among a group of origin sites.  User selection is optionally cached 
20  * and the user is forwarded to the HandleService appropriate to his selection.
21  *
22  * @author Walter Hoehn wassa@columbia.edu
23  */
24
25 public class WayfService extends HttpServlet {
26
27         private String wayfConfigFileLocation;
28         private String siteConfigFileLocation;
29         private WayfConfig config;
30         private WayfOrigins originConfig;
31         private static Logger log = Logger.getLogger(WayfService.class.getName());
32
33         /**
34          * @see GenericServlet#init()
35          */
36         public void init() throws ServletException {
37
38                 super.init();
39                 log.info("Initializing WAYF.");
40                 loadInitParams();
41                 log.info("Loading configuration from file.");
42                 configure();
43                 initViewConfig();
44                 log.info("WAYF initialization completed.");
45         }
46
47         /**
48          * Populates WayfConfig and WayfOrigins objects from file contents.
49          */
50         private void configure() throws UnavailableException {
51
52                 InputStream is = getServletContext().getResourceAsStream(wayfConfigFileLocation);
53                 WayfConfigDigester digester = new WayfConfigDigester(getServletContext());
54                 InputStream siteIs = getServletContext().getResourceAsStream(siteConfigFileLocation);
55                 OriginSitesDigester siteDigester = new OriginSitesDigester(getServletContext());
56
57                 try {
58                         digester.setValidating(true);
59                         digester.setErrorHandler(new PassThruErrorHandler());
60                         config = (WayfConfig) digester.parse(is);
61
62                 } catch (SAXException se) {
63                         log.fatal("Error parsing WAYF configuration file.", se);
64                         throw new UnavailableException("Error parsing WAYF configuration file.");
65                 } catch (IOException ioe) {
66                         log.fatal("Error reading WAYF configuration file.", ioe);
67                         throw new UnavailableException("Error reading WAYF configuration file.");
68                 }
69
70                 try {
71                         siteDigester.setValidating(true);
72                         siteDigester.setErrorHandler(new PassThruErrorHandler());
73                         originConfig = (WayfOrigins) siteDigester.parse(siteIs);
74
75                 } catch (SAXException se) {
76                         log.fatal("Error parsing site file.", se);
77                         throw new UnavailableException("Error parsing site file.");
78                 } catch (IOException ioe) {
79                         log.fatal("Error reading site file.", ioe);
80                         throw new UnavailableException("Error reading site file.");
81                 }
82         }
83         /**
84          * Setup application-wide beans for view
85          */
86         private void initViewConfig() {
87                 getServletContext().setAttribute("originsets", originConfig.getOriginSets());
88                 getServletContext().setAttribute("supportContact", config.getSupportContact());
89                 getServletContext().setAttribute("helpText", config.getHelpText());
90                 getServletContext().setAttribute("searchResultEmptyText", config.getSearchResultEmptyText());
91                 getServletContext().setAttribute("logoLocation", config.getLogoLocation());
92         }
93
94         /**
95          * Reads parameters from web.xml <init-param /> construct.
96          */
97         private void loadInitParams() {
98
99                 wayfConfigFileLocation = getServletConfig().getInitParameter("WAYFConfigFileLocation");
100                 if (wayfConfigFileLocation == null) {
101                         log.warn("No WAYFConfigFileLocation parameter found... using default location.");
102                         wayfConfigFileLocation = "/WEB-INF/conf/wayfconfig.xml";
103                 }
104                 siteConfigFileLocation = getServletConfig().getInitParameter("SiteConfigFileLocation");
105                 if (siteConfigFileLocation == null) {
106                         log.warn("No SiteonfigFileLocation parameter found... using default location.");
107                         siteConfigFileLocation = "/WEB-INF/conf/sites.xml";
108                 }
109
110         }
111
112         /**
113          * @see HttpServlet#doGet(HttpServletRequest, HttpServletResponse)
114          */
115         public void doGet(HttpServletRequest req, HttpServletResponse res) {
116
117                 log.info("Handling WAYF request.");
118                 //Tell the browser not to cache the WAYF page
119                 res.setHeader("Cache-Control", "no-cache");
120                 res.setHeader("Pragma", "no-cache");
121                 res.setDateHeader("Expires", 0);
122
123                 //Decide how to route the request based on query string
124                 String requestType = req.getParameter("action");
125                 if (requestType == null) {
126                         requestType = "lookup";
127                 }
128                 try {
129                         if (requestType.equals("deleteFromCache")) {
130                                 log.debug("Deleting saved HS from cache");
131                                 WayfCacheFactory.getInstance(config.getCacheType()).deleteHsFromCache(req, res);
132                                 handleLookup(req, res);
133                         } else if (WayfCacheFactory.getInstance(config.getCacheType()).hasCachedHS(req)) {
134                                 handleRedirect(
135                                         req,
136                                         res,
137                                         WayfCacheFactory.getInstance(config.getCacheType()).getCachedHS(req));
138                         } else if (requestType.equals("search")) {
139                                 handleSearch(req, res);
140                         } else if (requestType.equals("selection")) {
141                                 handleSelection(req, res);
142                         } else {
143                                 handleLookup(req, res);
144                         }
145                 } catch (WayfException we) {
146                         handleError(req, res, we);
147                 }
148         }
149
150         private void handleLookup(HttpServletRequest req, HttpServletResponse res) throws WayfException {
151
152                 if ((getSHIRE(req) == null) || (getTarget(req) == null)) {
153                         throw new WayfException("Invalid or missing data from SHIRE");
154                 }
155                 req.setAttribute("shire", getSHIRE(req));
156                 req.setAttribute("target", getTarget(req));
157                 req.setAttribute("encodedShire", URLEncoder.encode(getSHIRE(req)));
158                 req.setAttribute("encodedTarget", URLEncoder.encode(getTarget(req)));
159
160                 log.debug("Displaying WAYF selection page.");
161                 RequestDispatcher rd = req.getRequestDispatcher("/wayf.jsp");
162                 try {
163                         rd.forward(req, res);
164                 } catch (IOException ioe) {
165                         throw new WayfException("Problem displaying WAYF UI." + ioe.toString());
166                 } catch (ServletException se) {
167                         throw new WayfException("Problem displaying WAYF UI." + se.toString());
168                 }
169         }
170
171         private void handleSearch(HttpServletRequest req, HttpServletResponse res) throws WayfException {
172
173                 if (req.getParameter("string") != null) {
174                         Origin[] origins = originConfig.seachForMatchingOrigins(req.getParameter("string"), config);
175                         if (origins.length != 0) {
176                                 req.setAttribute("searchresults", origins);
177                         } else {
178                                 req.setAttribute("searchResultsEmpty", "true");
179                         }
180                 }
181                 handleLookup(req, res);
182
183         }
184
185         private void handleSelection(HttpServletRequest req, HttpServletResponse res) throws WayfException {
186
187                 String handleService = originConfig.lookupHSbyName(req.getParameter("origin"));
188                 if (handleService == null) {
189                         handleLookup(req, res);
190                 } else {
191                         WayfCacheFactory.getInstance(config.getCacheType()).addHsToCache(handleService, req, res);
192                         handleRedirect(req, res, handleService);
193                 }
194
195         }
196
197         private void handleRedirect(HttpServletRequest req, HttpServletResponse res, String handleService)
198                 throws WayfException {
199
200                 String shire = getSHIRE(req);
201                 String target = getTarget(req);
202                 log.info("Redirecting to selected Handle Service");
203                 try {
204                         res.sendRedirect(
205                                 handleService
206                                         + "?target="
207                                         + URLEncoder.encode(target)
208                                         + "&shire="
209                                         + URLEncoder.encode(shire));
210                 } catch (IOException ioe) {
211                         throw new WayfException("Error forwarding to HS: " + ioe.toString());
212                 }
213
214         }
215
216         private void handleError(HttpServletRequest req, HttpServletResponse res, WayfException we) {
217
218                 log.error("WAYF Failure: " + we.toString());
219                 log.debug("Displaying WAYF error page.");
220                 req.setAttribute("errorText", we.toString());
221                 req.setAttribute("requestURL", req.getRequestURI().toString());
222                 RequestDispatcher rd = req.getRequestDispatcher("/wayferror.jsp");
223
224                 try {
225                         rd.forward(req, res);
226                 } catch (IOException ioe) {
227                         log.error("Problem trying to display WAYF error page: " + ioe.toString());
228                 } catch (ServletException se) {
229                         log.error("Problem trying to display WAYF error page: " + se.toString());
230                 }
231         }
232
233         private String getSHIRE(HttpServletRequest req) throws WayfException {
234
235                 String shire = (String) req.getAttribute("shire");
236                 if (req.getParameter("shire") != null) {
237                         shire = req.getParameter("shire");
238                 }
239                 if (shire == null) {
240                         throw new WayfException("Invalid data from SHIRE: No acceptance URL received.");
241                 }
242                 return shire;
243         }
244
245         private String getTarget(HttpServletRequest req) throws WayfException {
246
247                 String target = (String) req.getAttribute("target");
248                 if (req.getParameter("target") != null) {
249                         target = req.getParameter("target");
250                 }
251                 if (target == null) {
252                         throw new WayfException("Invalid data from SHIRE: No target URL received.");
253                 }
254                 return target;
255         }
256
257 }