/*
* Authenticate.java
*
* Version: $Revision: 4753 $
*
* Date: $Date: 2010-02-08 21:48:34 +0000 (Mon, 08 Feb 2010) $
*
* Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts
* Institute of Technology. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Hewlett-Packard Company nor the name of the
* Massachusetts Institute of Technology nor the names of their
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.dspace.app.webui.util;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.Locale;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.jsp.jstl.core.Config;
import org.apache.log4j.Logger;
import org.dspace.authenticate.AuthenticationManager;
import org.dspace.authenticate.AuthenticationMethod;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.dspace.core.ConfigurationManager;
import org.dspace.eperson.EPerson;
/**
* Methods for authenticating the user. This is DSpace platform code, as opposed
* to the site-specific authentication code, that resides in implementations of
* the <code>org.dspace.eperson.AuthenticationMethod</code> interface.
*
* @author Robert Tansley
* @version $Revision: 4753 $
*/
public class Authenticate
{
/** log4j category */
private static Logger log = Logger.getLogger(Authenticate.class);
/**
* Return the request that the system should be dealing with, given the
* request that the browse just sent. If the incoming request is from a
* redirect resulting from successful authentication, a request object
* corresponding to the original request that prompted authentication is
* returned. Otherwise, the request passed in is returned.
*
* @param request
* the incoming HTTP request
* @return the HTTP request the DSpace system should deal with
*/
public static HttpServletRequest getRealRequest(HttpServletRequest request)
{
HttpSession session = request.getSession();
if (session.getAttribute("resuming.request") != null)
{
// Get info about the interrupted request
RequestInfo requestInfo = (RequestInfo) session
.getAttribute("interrupted.request.info");
HttpServletRequest actualRequest;
if (requestInfo == null)
{
// Can't find the wrapped request information.
// FIXME: Proceed with current request - correct?
actualRequest = request;
}
else
{
/*
* Wrap the current request to make it look like the interruped
* one
*/
actualRequest = requestInfo.wrapRequest(request);
}
// Remove the info from the session so it isn't resumed twice
session.removeAttribute("resuming.request");
session.removeAttribute("interrupted.request.info");
session.removeAttribute("interrupted.request.url");
// Return the wrapped request
return actualRequest;
}
else
{
return request;
}
}
/**
* Resume a previously interrupted request. This is invoked when a user has
* been successfully authenticated. The request which led to authentication
* will be resumed.
*
* @param request
* <em>current</em> HTTP request
* @param response
* HTTP response
*/
public static void resumeInterruptedRequest(HttpServletRequest request,
HttpServletResponse response) throws IOException
{
HttpSession session = request.getSession();
String originalURL = (String) session
.getAttribute("interrupted.request.url");
if (originalURL == null)
{
// If for some reason we don't have the original URL, redirect
// to My DSpace
originalURL = request.getContextPath() + "/mydspace";
}
else
{
// Set the flag in the session, so that when the redirect is
// followed, we'll know to resume the interrupted request
session.setAttribute("resuming.request", new Boolean(true));
}
// Send the redirect
response.sendRedirect(response.encodeRedirectURL(originalURL));
}
/**
* Start the authentication process. This packages up the request that led
* to authentication being required, and then invokes the site-specific
* authentication method.
*
* If it returns true, the user was authenticated without any
* redirection (e.g. by an X.509 certificate or other implicit method) so
* the process that called this can continue and send its own response.
* A "false" result means this method has sent its own redirect.
*
* @param context
* current DSpace context
* @param request
* current HTTP request - the one that prompted authentication
* @param response
* current HTTP response
*
* @return true if authentication is already finished (implicit method)
*/
public static boolean startAuthentication(Context context,
HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
HttpSession session = request.getSession();
/*
* Authenticate:
* 1. try implicit methods first, since that may work without
* a redirect. return true if no redirect needed.
* 2. if those fail, redirect to enter credentials.
* return false.
*/
if (AuthenticationManager.authenticateImplicit(context, null, null,
null, request) == AuthenticationMethod.SUCCESS)
{
loggedIn(context, request, context.getCurrentUser());
log.info(LogManager.getHeader(context, "login", "type=implicit"));
return true;
}
else
{
// Since we may be doing a redirect, make sure the redirect is not
// cached
response.addDateHeader("expires", 1);
response.addHeader("Pragma", "no-cache");
response.addHeader("Cache-control", "no-store");
// Store the data from the request that led to authentication
RequestInfo info = new RequestInfo(request);
session.setAttribute("interrupted.request.info", info);
// Store the URL of the request that led to authentication
session.setAttribute("interrupted.request.url", UIUtil
.getOriginalURL(request));
/*
* Grovel over authentication methods, counting the
* ones with a "redirect" login page -- if there's only one,
* go directly there. If there is a choice, go to JSP chooser.
*/
Iterator ai = AuthenticationManager.authenticationMethodIterator();
AuthenticationMethod am;
int count = 0;
String url = null;
while (ai.hasNext())
{
String s;
am = (AuthenticationMethod)ai.next();
if ((s = am.loginPageURL(context, request, response)) != null)
{
url = s;
++count;
}
}
if (count == 1)
response.sendRedirect(url);
else
JSPManager.showJSP(request, response, "/login/chooser.jsp");
}
return false;
}
/**
* Store information about the current user in the request and context
*
* @param context
* DSpace context
* @param request
* HTTP request
* @param eperson
* the eperson logged in
*/
public static void loggedIn(Context context,
HttpServletRequest request,
EPerson eperson)
{
HttpSession session = request.getSession();
// For security reasons after login, give the user a new session
if ((!session.isNew()) && (session.getAttribute("dspace.current.user.id") == null))
{
// Keep the user's locale setting if set
Locale sessionLocale = UIUtil.getSessionLocale(request);
// Invalidate session unless dspace.cfg says not to
if(ConfigurationManager.getBooleanProperty("webui.session.invalidate", true))
{
session.invalidate();
}
// Give the user a new session
session = request.getSession();
// Restore the session locale
if (sessionLocale != null)
{
Config.set(request.getSession(), Config.FMT_LOCALE, sessionLocale);
}
}
context.setCurrentUser(eperson);
boolean isAdmin = false;
try
{
isAdmin = AuthorizeManager.isAdmin(context);
}
catch (SQLException se)
{
log.warn("Unable to use AuthorizeManager " + se);
}
finally
{
request.setAttribute("is.admin", new Boolean(isAdmin));
}
// We store the current user in the request as an EPerson object...
request.setAttribute("dspace.current.user", eperson);
// and in the session as an ID
session.setAttribute("dspace.current.user.id", new Integer(eperson
.getID()));
// and the remote IP address to compare against later requests
// so we can detect session hijacking.
session.setAttribute("dspace.current.remote.addr",
request.getRemoteAddr());
}
/**
* Log the user out
*
* @param context
* DSpace context
* @param request
* HTTP request
*/
public static void loggedOut(Context context, HttpServletRequest request)
{
HttpSession session = request.getSession();
context.setCurrentUser(null);
request.removeAttribute("is.admin");
request.removeAttribute("dspace.current.user");
session.removeAttribute("dspace.current.user.id");
// Keep the user's locale setting if set
Locale sessionLocale = UIUtil.getSessionLocale(request);
// Invalidate session unless dspace.cfg says not to
if(ConfigurationManager.getBooleanProperty("webui.session.invalidate", true))
{
session.invalidate();
}
// Restore the session locale
if (sessionLocale != null)
{
Config.set(request.getSession(), Config.FMT_LOCALE, sessionLocale);
}
}
}