View Javadoc

1   /*
2    * Copyright (c) 2004 UNINETT FAS
3    *
4    * This program is free software; you can redistribute it and/or modify it
5    * under the terms of the GNU General Public License as published by the Free
6    * Software Foundation; either version 2 of the License, or (at your option)
7    * any later version.
8    *
9    * This program is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11   * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12   * more details.
13   *
14   * You should have received a copy of the GNU General Public License along with
15   * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16   * Place - Suite 330, Boston, MA 02111-1307, USA.
17   *
18   * $Id: LogoutServlet.java,v 1.17 2006/01/30 17:17:55 catoolsen Exp $
19   */
20  
21  package no.feide.moria.servlet;
22  
23  import java.util.Properties;
24  import java.util.ResourceBundle;
25  
26  import javax.servlet.RequestDispatcher;
27  import javax.servlet.http.Cookie;
28  import javax.servlet.http.HttpServlet;
29  import javax.servlet.http.HttpServletRequest;
30  import javax.servlet.http.HttpServletResponse;
31  
32  import no.feide.moria.controller.IllegalInputException;
33  import no.feide.moria.controller.InoperableStateException;
34  import no.feide.moria.controller.MoriaController;
35  import no.feide.moria.log.MessageLogger;
36  
37  /***
38   * This servlet handles logout request. It will invalidate the SSO ticket in the
39   * underlying store and remove the cookie from the client. <p/> It uses two
40   * properties from the config:
41   * <dl>
42   * <dt>no.feide.moria.web.sso_cookie.name</dt>
43   * <dd>The the cookie name</dd>
44   * <dt>no.feide.moria.web.logout.url_param</dt>
45   * <dd>The name of the optional parameter in the request holding the redirect
46   * url.</dd>
47   * </dl>
48   * @author Lars Preben S. Arnesen &lt;lars.preben.arnesen@conduct.no&gt;
49   * @version $Revision: 1.17 $
50   */
51  public final class LogoutServlet
52  extends HttpServlet {
53  
54      /***
55       * Serial version UID.
56       */
57      private static final long serialVersionUID = 5494943294819992935L;
58  
59      /***
60       * The message logger used in this class.
61       */
62      private MessageLogger messageLogger;
63  
64      /***
65       * The default redirect parameter name.<br>
66       * <br>
67       * Current value is <code>"redirect"</code>.
68       */
69      private static final String defaultRedirectParameterName = "redirect";
70  
71      /***
72       * Default SSO cookie name, if not set in configuration.<br>
73       * <br>
74       * Current value is <code>"MoriaSSOCookie"</code>.
75       */
76      private static final String DEFAULT_SSO_COOKIE = "MoriaSSOCookie";
77  
78  
79      /***
80       * Intitiates the servlet.
81       */
82      public void init() {
83  
84          messageLogger = new MessageLogger(LogoutServlet.class);
85      }
86  
87  
88      /***
89       * Handles the GET requests.
90       * @param request
91       *            The HTTP request object.
92       * @param response
93       *            The HTTP response object.
94       */
95      public void doGet(final HttpServletRequest request,
96                        final HttpServletResponse response) {
97  
98          final Properties config = RequestUtil.getConfig(getServletContext());
99  
100         // Check for SSO cookie name.
101         String ssoCookieName = config.getProperty(RequestUtil.PROP_COOKIE_SSO);
102 
103         if (ssoCookieName == null || ssoCookieName.equals("")) {
104             ssoCookieName = DEFAULT_SSO_COOKIE;
105             messageLogger.logWarn("Parameter '" + RequestUtil.PROP_COOKIE_SSO + "' not set in config; using default value '" + ssoCookieName + "'");
106         }
107 
108         // Get session from cookie and remove it.
109         final Cookie[] cookies = request.getCookies();
110         String cookieValue = null;
111         if (cookies != null)
112             cookieValue = RequestUtil.getCookieValue(ssoCookieName, cookies);
113         
114         // Handle logout of unknown session.
115         if ((cookies == null) ||
116             (cookieValue == null)) {
117             messageLogger.logWarn("Attempted logout of non-existing SSO session from host " + request.getRemoteAddr());
118             respond(config, request, response);
119             return;  // We're done.
120         }
121         
122         // Remove cookie.
123         final Cookie ssoCookie = RequestUtil.createCookie(config.getProperty(RequestUtil.PROP_COOKIE_SSO), cookieValue, 0);
124         response.addCookie(ssoCookie);
125 
126         // Invalidate session.
127         boolean controllerFailed = false;
128         try {
129             MoriaController.invalidateSSOTicket(cookieValue);
130         } catch (InoperableStateException ise) {
131             messageLogger.logWarn("Controller in inoperable state", cookieValue, ise);
132             controllerFailed = true;
133         } catch (IllegalInputException e) {
134             messageLogger.logWarn("Illegal SSO ticket value", cookieValue, e);
135         }
136         if (controllerFailed) {
137             final RequestDispatcher requestDispatcher = getServletContext().getNamedDispatcher("JSP-Error.JSP");
138 
139             try {
140                 requestDispatcher.forward(request, response);
141             } catch (Exception e) {
142                 messageLogger.logCritical("Dispatch to JSP error JSP failed", cookieValue, e);
143             }
144             // If everything fails there's not much to do but return.
145             return;
146         }
147 
148         // Respond normally.
149         respond(config, request, response);
150     }
151 
152 
153     /***
154      * Handles POST requests. Just calls doGet().
155      * @param request
156      *            The HTTP request object.
157      * @param response
158      *            The HTTP response object.
159      */
160     public void doPost(final HttpServletRequest request,
161                        final HttpServletResponse response) {
162 
163         doGet(request, response);
164     }
165 
166 
167     /***
168      * If the redirect URL is given in the request, redirect the user to the
169      * given URL. Otherwise display the default logout page.
170      * @param config
171      *            The web module configuration.
172      * @param request
173      *            The original request.
174      * @param response
175      *            The response.
176      */
177     public void respond(final Properties config,
178                          final HttpServletRequest request,
179                          final HttpServletResponse response) {
180         
181         // Do we have a redirect URL parameter?
182         String urlParam = config.getProperty(RequestUtil.PROP_LOGOUT_URL_PARAM);
183         if (urlParam == null) {
184             urlParam = defaultRedirectParameterName;
185             messageLogger.logWarn("Parameter '" + RequestUtil.PROP_LOGOUT_URL_PARAM + "' not set in config; using default value '" + urlParam + "'");
186         }
187 
188         // Redirect or vanilla logout page?
189         final String url = request.getParameter(urlParam);
190         if (url != null) {
191             
192             // Redirect to URL requested by service.
193             response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
194             response.addHeader("Location", url);
195             
196         } else {
197             
198             // Dispatch request to JSP, with proper language selection.
199             String langFromCookie = null;
200             if (request.getCookies() != null)
201                 langFromCookie = RequestUtil.getCookieValue((String) RequestUtil.getConfig(getServletContext()).get(RequestUtil.PROP_COOKIE_LANG), request.getCookies());
202             final ResourceBundle bundle = RequestUtil.getBundle("logout", request.getParameter("lang"), langFromCookie, null, request.getHeader("Accept-Language"), "en");
203             request.setAttribute("bundle", bundle);
204             final RequestDispatcher requestDispatcher = getServletContext().getNamedDispatcher("Logout.JSP");
205             try {
206                 requestDispatcher.forward(request, response);
207             } catch (Exception e) {
208                 messageLogger.logCritical("Dispatch to Logout JSP failed", e);
209             }
210         }
211     }
212 }