001: /* Copyright 2001 The JA-SIG Collaborative. All rights reserved.
002: * See license distributed with this file and
003: * available online at http://www.uportal.org/license.html
004: */
005:
006: package org.jasig.portal;
007:
008: import java.io.IOException;
009: import java.util.Enumeration;
010: import java.util.HashMap;
011: import java.util.Properties;
012:
013: import javax.servlet.ServletException;
014: import javax.servlet.http.HttpServlet;
015: import javax.servlet.http.HttpServletRequest;
016: import javax.servlet.http.HttpServletResponse;
017: import javax.servlet.http.HttpSession;
018:
019: import org.jasig.portal.events.EventPublisherLocator;
020: import org.jasig.portal.events.support.UserLoggedOutPortalEvent;
021: import org.jasig.portal.security.IPerson;
022: import org.jasig.portal.security.ISecurityContext;
023: import org.jasig.portal.security.PersonManagerFactory;
024: import org.apache.commons.logging.Log;
025: import org.apache.commons.logging.LogFactory;
026: import org.jasig.portal.utils.ResourceLoader;
027:
028: /**
029: * Simple servlet to handle user logout. When a user
030: * logs out, their session gets invalidated and they
031: * are returned to the guest page.
032: * @author Ken Weiner, kweiner@unicon.net
033: * @author Don Fracapane, df7@columbia.edu
034: * @version $Revision: 36546 $
035: */
036: public class LogoutServlet extends HttpServlet {
037:
038: private static final Log log = LogFactory
039: .getLog(LogoutServlet.class);
040:
041: private static boolean INITIALIZED = false;
042: private static String DEFAULT_REDIRECT;
043: private static HashMap REDIRECT_MAP;
044:
045: /**
046: * Initialize the LogoutServlet
047: * @throws ServletException
048: */
049: public void init() throws ServletException {
050: if (!INITIALIZED) {
051: String upFile = UPFileSpec.RENDER_URL_ELEMENT
052: + UPFileSpec.PORTAL_URL_SEPARATOR
053: + UserInstance.USER_LAYOUT_ROOT_NODE
054: + UPFileSpec.PORTAL_URL_SEPARATOR
055: + UPFileSpec.PORTAL_URL_SUFFIX;
056: HashMap rdHash = new HashMap(1);
057: try {
058: upFile = UPFileSpec.buildUPFile(null,
059: UPFileSpec.RENDER_METHOD,
060: UserInstance.USER_LAYOUT_ROOT_NODE, null, null);
061: // We retrieve the redirect strings for each context
062: // from the security properties file.
063: String key;
064: Properties props = ResourceLoader
065: .getResourceAsProperties(LogoutServlet.class,
066: "/properties/security.properties");
067: Enumeration propNames = props.propertyNames();
068: while (propNames.hasMoreElements()) {
069: String propName = (String) propNames.nextElement();
070: String propValue = props.getProperty(propName);
071: if (propName.startsWith("logoutRedirect.")) {
072: key = propName.substring(15);
073: key = (key.startsWith("root.") ? key
074: .substring(5) : key);
075: if (log.isDebugEnabled()) {
076: log.debug("LogoutServlet::initializer()"
077: + " Redirect key = " + key);
078: log.debug("LogoutServlet::initializer()"
079: + " Redirect value = " + propValue);
080: }
081:
082: rdHash.put(key, propValue);
083: }
084: }
085: } catch (PortalException pe) {
086: log.error("LogoutServlet::static ", pe);
087: } catch (IOException ioe) {
088: log.error("LogoutServlet::static", ioe);
089: }
090: REDIRECT_MAP = rdHash;
091: DEFAULT_REDIRECT = upFile;
092: INITIALIZED = true;
093: }
094: }
095:
096: /**
097: * Process the incoming request and response.
098: * @param request HttpServletRequest object
099: * @param response HttpServletResponse object
100: * @throws ServletException
101: * @throws IOException
102: */
103: public void doGet(HttpServletRequest request,
104: HttpServletResponse response) throws ServletException,
105: IOException {
106: init();
107: String redirect = getRedirectionUrl(request);
108: HttpSession session = request.getSession(false);
109:
110: if (session != null) {
111: // Record that an authenticated user is requesting to log out
112: try {
113: IPerson person = PersonManagerFactory
114: .getPersonManagerInstance().getPerson(request);
115: if (person != null
116: && person.getSecurityContext()
117: .isAuthenticated()) {
118: EventPublisherLocator
119: .getApplicationEventPublisher()
120: .publishEvent(
121: new UserLoggedOutPortalEvent(this ,
122: person));
123: }
124: } catch (Exception e) {
125: log.error("Exception recording logout "
126: + "associated with request " + request, e);
127: }
128:
129: // Clear out the existing session for the user
130: try {
131: session.invalidate();
132: } catch (IllegalStateException ise) {
133: // IllegalStateException indicates session was already invalidated.
134: // This is fine. LogoutServlet is looking to guarantee the logged out session is invalid;
135: // it need not insist that it be the one to perform the invalidating.
136: if (log.isTraceEnabled()) {
137: log
138: .trace(
139: "LogoutServlet encountered IllegalStateException invalidating a presumably already-invalidated session.",
140: ise);
141: }
142: }
143: }
144:
145: // Send the user back to the guest page
146: response.sendRedirect(redirect);
147: }
148:
149: /**
150: * The redirect is determined based upon the context that passed authentication
151: * The LogoutServlet looks at each authenticated context and determines if a
152: * redirect exists for that context in the REDIRECT_MAP variable (loaded from
153: * security.properties file). The redirect is returned for the first authenticated
154: * context that has an associated redirect string. If such a context is not found,
155: * we use the default DEFAULT_REDIRECT that was originally setup.
156: *
157: * NOTE:
158: * This will work or not work based upon the logic in the root context. At this time,
159: * all known security contexts extend the ChainingSecurityContext class. If a context
160: * has the variable stopWhenAuthenticated set to false, the user may be logged into
161: * multiple security contexts. If this is the case, the logout process currently
162: * implemented does not accommodate multiple logouts. As a reference implemention,
163: * the current implementation assumes only one security context has been authenticated.
164: * Modifications to perform multiple logouts should be considered when a concrete
165: * need arises and can be handled by this class or through a change in the
166: * ISecurityConext API where a context knows how to perform it's own logout.
167: *
168: * @param request
169: * @return String representing the redirection URL
170: */
171: private String getRedirectionUrl(HttpServletRequest request) {
172: String redirect = null;
173: String defaultRedirect = request.getContextPath() + '/'
174: + DEFAULT_REDIRECT;
175: IPerson person = null;
176: if (REDIRECT_MAP == null) {
177: return defaultRedirect;
178: }
179: try {
180: // Get the person object associated with the request
181: person = PersonManagerFactory.getPersonManagerInstance()
182: .getPerson(request);
183: // Retrieve the security context for the user
184: ISecurityContext securityContext = person
185: .getSecurityContext();
186: if (securityContext.isAuthenticated()) {
187: if (log.isDebugEnabled())
188: log
189: .debug("LogoutServlet::getRedirectionUrl()"
190: + " Looking for redirect string for the root context");
191: redirect = (String) REDIRECT_MAP.get("root");
192: if (redirect != null && !redirect.equals("")) {
193: return redirect;
194: }
195: }
196: Enumeration subCtxNames = securityContext
197: .getSubContextNames();
198: while (subCtxNames.hasMoreElements()) {
199: String subCtxName = (String) subCtxNames.nextElement();
200: if (log.isDebugEnabled())
201: log.debug("LogoutServlet::getRedirectionUrl() "
202: + " subCtxName = " + subCtxName);
203: // strip off "root." part of name
204: ISecurityContext sc = securityContext
205: .getSubContext(subCtxName);
206: if (log.isDebugEnabled())
207: log.debug("LogoutServlet::getRedirectionUrl()"
208: + " subCtxName isAuth = "
209: + sc.isAuthenticated());
210: if (sc.isAuthenticated()) {
211: if (log.isDebugEnabled())
212: log
213: .debug("LogoutServlet::getRedirectionUrl()"
214: + " Looking for redirect string for subCtxName = "
215: + subCtxName);
216: redirect = (String) REDIRECT_MAP.get(subCtxName);
217: if (redirect != null && !redirect.equals("")) {
218: if (log.isDebugEnabled())
219: log
220: .debug("LogoutServlet::getRedirectionUrl()"
221: + " subCtxName redirect = "
222: + redirect);
223: break;
224: }
225: }
226: }
227: } catch (Exception e) {
228: // Log the exception
229: log.error("LogoutServlet::getRedirectionUrl() Error:", e);
230: }
231: if (redirect == null) {
232: redirect = defaultRedirect;
233: }
234: if (log.isDebugEnabled())
235: log.debug("LogoutServlet::getRedirectionUrl()"
236: + " redirectionURL = " + redirect);
237: return redirect;
238: }
239: }
|