Moved custom error handler into matching digester class.
[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                         config = (WayfConfig) digester.parse(is);
60
61                 } catch (SAXException se) {
62                         log.fatal("Error parsing WAYF configuration file.", se);
63                         throw new UnavailableException("Error parsing WAYF configuration file.");
64                 } catch (IOException ioe) {
65                         log.fatal("Error reading WAYF configuration file.", ioe);
66                         throw new UnavailableException("Error reading WAYF configuration file.");
67                 }
68
69                 try {
70                         siteDigester.setValidating(true);
71                         originConfig = (WayfOrigins) siteDigester.parse(siteIs);
72
73                 } catch (SAXException se) {
74                         log.fatal("Error parsing site file.", se);
75                         throw new UnavailableException("Error parsing site file.");
76                 } catch (IOException ioe) {
77                         log.fatal("Error reading site file.", ioe);
78                         throw new UnavailableException("Error reading site file.");
79                 }
80         }
81         /**
82          * Setup application-wide beans for view
83          */
84         private void initViewConfig() {
85                 getServletContext().setAttribute("originsets", originConfig.getOriginSets());
86                 getServletContext().setAttribute("supportContact", config.getSupportContact());
87                 getServletContext().setAttribute("helpText", config.getHelpText());
88                 getServletContext().setAttribute("searchResultEmptyText", config.getSearchResultEmptyText());
89                 getServletContext().setAttribute("logoLocation", config.getLogoLocation());
90         }
91
92         /**
93          * Reads parameters from web.xml <init-param /> construct.
94          */
95         private void loadInitParams() {
96
97                 wayfConfigFileLocation = getServletConfig().getInitParameter("WAYFConfigFileLocation");
98                 if (wayfConfigFileLocation == null) {
99                         log.warn("No WAYFConfigFileLocation parameter found... using default location.");
100                         wayfConfigFileLocation = "/WEB-INF/conf/wayfconfig.xml";
101                 }
102                 siteConfigFileLocation = getServletConfig().getInitParameter("SiteConfigFileLocation");
103                 if (siteConfigFileLocation == null) {
104                         log.warn("No SiteonfigFileLocation parameter found... using default location.");
105                         siteConfigFileLocation = "/WEB-INF/conf/sites.xml";
106                 }
107
108         }
109
110         /**
111          * @see HttpServlet#doGet(HttpServletRequest, HttpServletResponse)
112          */
113         public void doGet(HttpServletRequest req, HttpServletResponse res) {
114
115                 log.info("Handling WAYF request.");
116                 //Tell the browser not to cache the WAYF page
117                 res.setHeader("Cache-Control", "no-cache");
118                 res.setHeader("Pragma", "no-cache");
119                 res.setDateHeader("Expires", 0);
120
121                 //Decide how to route the request based on query string
122                 String requestType = req.getParameter("action");
123                 if (requestType == null) {
124                         requestType = "lookup";
125                 }
126                 try {
127                         if (requestType.equals("deleteFromCache")) {
128                                 log.debug("Deleting saved HS from cache");
129                                 WayfCacheFactory.getInstance(config.getCacheType()).deleteHsFromCache(req, res);
130                                 handleLookup(req, res);
131                         } else if (WayfCacheFactory.getInstance(config.getCacheType()).hasCachedHS(req)) {
132                                 handleRedirect(
133                                         req,
134                                         res,
135                                         WayfCacheFactory.getInstance(config.getCacheType()).getCachedHS(req));
136                         } else if (requestType.equals("search")) {
137                                 handleSearch(req, res);
138                         } else if (requestType.equals("selection")) {
139                                 handleSelection(req, res);
140                         } else {
141                                 handleLookup(req, res);
142                         }
143                 } catch (WayfException we) {
144                         handleError(req, res, we);
145                 }
146         }
147
148         private void handleLookup(HttpServletRequest req, HttpServletResponse res) throws WayfException {
149
150                 if ((getSHIRE(req) == null) || (getTarget(req) == null)) {
151                         throw new WayfException("Invalid or missing data from SHIRE");
152                 }
153                 req.setAttribute("shire", getSHIRE(req));
154                 req.setAttribute("target", getTarget(req));
155                 req.setAttribute("encodedShire", URLEncoder.encode(getSHIRE(req)));
156                 req.setAttribute("encodedTarget", URLEncoder.encode(getTarget(req)));
157
158                 log.debug("Displaying WAYF selection page.");
159                 RequestDispatcher rd = req.getRequestDispatcher("/wayf.jsp");
160                 try {
161                         rd.forward(req, res);
162                 } catch (IOException ioe) {
163                         throw new WayfException("Problem displaying WAYF UI." + ioe.toString());
164                 } catch (ServletException se) {
165                         throw new WayfException("Problem displaying WAYF UI." + se.toString());
166                 }
167         }
168
169         private void handleSearch(HttpServletRequest req, HttpServletResponse res) throws WayfException {
170
171                 if (req.getParameter("string") != null) {
172                         Origin[] origins = originConfig.seachForMatchingOrigins(req.getParameter("string"), config);
173                         if (origins.length != 0) {
174                                 req.setAttribute("searchresults", origins);
175                         } else {
176                                 req.setAttribute("searchResultsEmpty", "true");
177                         }
178                 }
179                 handleLookup(req, res);
180
181         }
182
183         private void handleSelection(HttpServletRequest req, HttpServletResponse res) throws WayfException {
184
185                 String handleService = originConfig.lookupHSbyName(req.getParameter("origin"));
186                 if (handleService == null) {
187                         handleLookup(req, res);
188                 } else {
189                         WayfCacheFactory.getInstance(config.getCacheType()).addHsToCache(handleService, req, res);
190                         handleRedirect(req, res, handleService);
191                 }
192
193         }
194
195         private void handleRedirect(HttpServletRequest req, HttpServletResponse res, String handleService)
196                 throws WayfException {
197
198                 String shire = getSHIRE(req);
199                 String target = getTarget(req);
200                 log.info("Redirecting to selected Handle Service");
201                 try {
202                         res.sendRedirect(
203                                 handleService
204                                         + "?target="
205                                         + URLEncoder.encode(target)
206                                         + "&shire="
207                                         + URLEncoder.encode(shire));
208                 } catch (IOException ioe) {
209                         throw new WayfException("Error forwarding to HS: " + ioe.toString());
210                 }
211
212         }
213
214         private void handleError(HttpServletRequest req, HttpServletResponse res, WayfException we) {
215
216                 log.error("WAYF Failure: " + we.toString());
217                 log.debug("Displaying WAYF error page.");
218                 req.setAttribute("errorText", we.toString());
219                 req.setAttribute("requestURL", req.getRequestURI().toString());
220                 RequestDispatcher rd = req.getRequestDispatcher("/wayferror.jsp");
221
222                 try {
223                         rd.forward(req, res);
224                 } catch (IOException ioe) {
225                         log.error("Problem trying to display WAYF error page: " + ioe.toString());
226                 } catch (ServletException se) {
227                         log.error("Problem trying to display WAYF error page: " + se.toString());
228                 }
229         }
230
231         private String getSHIRE(HttpServletRequest req) throws WayfException {
232
233                 String shire = (String) req.getAttribute("shire");
234                 if (req.getParameter("shire") != null) {
235                         shire = req.getParameter("shire");
236                 }
237                 if (shire == null) {
238                         throw new WayfException("Invalid data from SHIRE: No acceptance URL received.");
239                 }
240                 return shire;
241         }
242
243         private String getTarget(HttpServletRequest req) throws WayfException {
244
245                 String target = (String) req.getAttribute("target");
246                 if (req.getParameter("target") != null) {
247                         target = req.getParameter("target");
248                 }
249                 if (target == null) {
250                         throw new WayfException("Invalid data from SHIRE: No target URL received.");
251                 }
252                 return target;
253         }
254
255 }