HttpSessionAccessHandler.java
/*
* $Source$
* $Revision$
*
* Copyright (C) 2000 William Chesters
*
* Part of Melati (http://melati.org), a framework for the rapid
* development of clean, maintainable web applications.
*
* Melati is free software; Permission is granted to copy, distribute
* and/or modify this software under the terms either:
*
* a) the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version,
*
* or
*
* b) any version of the Melati Software License, as published
* at http://melati.org
*
* You should have received a copy of the GNU General Public License and
* the Melati Software License along with this program;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
* GNU General Public License and visit http://melati.org to obtain the
* Melati Software License.
*
* Feel free to contact the Developers of Melati (http://melati.org),
* if you would like to work out a different arrangement than the options
* outlined here. It is our intention to allow Melati to be used by as
* wide an audience as possible.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Contact details for copyright holder:
*
* William Chesters <williamc At paneris.org>
* http://paneris.org/~williamc
* Obrechtstraat 114, 2517VX Den Haag, The Netherlands
*/
package org.melati.login;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.melati.Melati;
import org.melati.poem.AccessPoemException;
import org.melati.poem.PoemThread;
import org.melati.poem.User;
import org.melati.util.HttpServletRequestParameters;
import org.melati.util.HttpUtil;
import org.melati.util.MD5Util;
import org.melati.util.ReconstructedHttpServletRequest;
import org.melati.util.ReconstructedHttpServletRequestMismatchException;
import org.melati.util.UTF8URLEncoder;
/**
* An {@link AccessHandler} which uses <code>Session</code> cookies to
* elicit and maintain the user's login and password.
*/
public class HttpSessionAccessHandler implements AccessHandler {
/** Class name. */
public static final String
OVERLAY_PARAMETERS =
"org.melati.login.HttpSessionAccessHandler.overlayParameters";
/** Class name. */
public static final String
USER =
"org.melati.login.HttpSessionAccessHandler.user";
/**
* The class name of the class implementing the login servlet. Unless
* overridden, this is <TT>org.melati.login.Login</TT>.
*
* @return the class name of login servlet
* @see org.melati.login.Login
*/
protected String loginPageServletClassName() {
return "org.melati.login.Login";
}
/**
* The URL of the login servlet. Unless overridden, this is computed by
* substituting {@link #loginPageServletClassName()} into the URL of the
* request being serviced.
*
* @param melati the current Melati
* @param request the request currently being serviced
*
* @return the login page url
* @see #loginPageServletClassName
*/
public String loginPageURL(Melati melati, HttpServletRequest request) {
StringBuffer url = new StringBuffer();
HttpUtil.appendRelativeZoneURL(url, request);
url.append('/');
url.append(loginPageServletClassName());
url.append('/');
url.append(melati.getPoemContext().getLogicalDatabase());
url.append('/');
return url.toString();
}
/**
* Store the current request and redirect to the login page.
*
* {@inheritDoc}
* @see org.melati.login.AccessHandler#handleAccessException
*/
public void handleAccessException(Melati melati,
AccessPoemException accessException)
throws Exception {
HttpServletRequest request = melati.getRequest();
HttpServletResponse response = melati.getResponse();
HttpSession session = request.getSession(true);
session.setAttribute(Login.TRIGGERING_REQUEST_PARAMETERS,
new HttpServletRequestParameters(request));
session.setAttribute(Login.TRIGGERING_EXCEPTION, accessException);
melati.getWriter().reset();
response.sendRedirect(loginPageURL(melati, request));
}
/**
* Set the Access token to be used for this request.
*
* The Access Token is either picked up from the session, or from a cookie.
* The cookie is keyed on the logical database and is used to
* retrieve the user's login.
* The login is used (with the logical database name) to retrieve an encoded
* password which is then checked.
*
* {@inheritDoc}
* @see org.melati.login.AccessHandler#establishUser(org.melati.Melati)
*/
public Melati establishUser(Melati melati) {
// now when we establish a user, we must also set the cookie
String ldb = melati.getPoemContext().getLogicalDatabase();
HttpSession session = melati.getSession();
synchronized (session) {
User user = (User)session.getAttribute(USER);
if (user == null) {
user = getUserFromCookie(melati,ldb);
if (user != null) {
String cookie = getCookieValue(melati,ldb+user.getLogin());
if (cookie == null ||
!cookie.equals(MD5Util.encode(user.getPassword())))
user = null;
}
}
logUsIn(melati,user);
}
return melati;
}
/**
* Set our AccessToken.
* NOTE Remember a User isa Token.
*
* @param melati the Melati to get our database from
* @param user the token to set
*/
protected void logUsIn(Melati melati, User user) {
PoemThread.setAccessToken(
user == null ? melati.getDatabase().guestAccessToken() : user);
}
/**
* Extract User via the cookie.
* @param melati our Melati
* @param key cookie key
* @return the found User or null
*/
User getUserFromCookie(Melati melati,String key) {
String login = getCookieValue(melati,key);
if (login == null) return null;
return (User)melati.getDatabase().getUserTable().getLoginColumn().
firstWhereEq(login);
}
/**
* Extract a value from the cookies.
*
* @param melati the Melati in which the Request and its cookies are stored
* @param key the key we need the value of
* @return the cookie value or null
*/
String getCookieValue(Melati melati,String key) {
// try and get from cookie
// Use default encoding, regardless of user's encoding
key = UTF8URLEncoder.encode(key);
Cookie[] cookies = melati.getRequest().getCookies();
if(cookies == null) return null;
for (int i=0; i<cookies.length; i++) {
Cookie c = cookies[i];
if (c.getName().equals(key))
return UTF8URLEncoder.decode(c.getValue());
}
return null;
}
/**
* If we are returning from a login rebuild the original request,
* otherwise do nothing.
*
* {@inheritDoc}
* @see org.melati.login.AccessHandler#buildRequest(org.melati.Melati)
*/
public void buildRequest(Melati melati)
throws ReconstructedHttpServletRequestMismatchException {
HttpSession session = melati.getSession();
// First off, is the user continuing after a login? If so, we want to
// recover any POSTed fields from the request that triggered it.
synchronized (session) {
HttpServletRequestParameters oldParams =
(HttpServletRequestParameters)session.getAttribute(OVERLAY_PARAMETERS);
if (oldParams != null) {
session.removeAttribute(OVERLAY_PARAMETERS);
// we don't want to create a new object here, rather we are simply
// going to set up the old request parameters
melati.setRequest(
new ReconstructedHttpServletRequest(oldParams,
melati.getRequest()));
}
}
}
}