From bacb5b925aad479671df5d19ad47277444de6aac Mon Sep 17 00:00:00 2001 From: shaper Date: Thu, 2 May 2002 19:10:34 +0000 Subject: [PATCH] Revamped user login authentication to use a pluggable Authenticator allowing applications to perform authentication as they see fit. git-svn-id: https://samskivert.googlecode.com/svn/trunk@727 6335cc39-0255-0410-8fd6-9bcaacd3b74c --- .../user/AuthenticationFailedException.java | 32 +++++ .../servlet/user/Authenticator.java | 49 ++++++++ .../user/InvalidPasswordException.java | 4 +- .../servlet/user/NoSuchUserException.java | 4 +- .../samskivert/servlet/user/UserManager.java | 118 +++++++++--------- 5 files changed, 142 insertions(+), 65 deletions(-) create mode 100644 projects/samskivert/src/java/com/samskivert/servlet/user/AuthenticationFailedException.java create mode 100644 projects/samskivert/src/java/com/samskivert/servlet/user/Authenticator.java diff --git a/projects/samskivert/src/java/com/samskivert/servlet/user/AuthenticationFailedException.java b/projects/samskivert/src/java/com/samskivert/servlet/user/AuthenticationFailedException.java new file mode 100644 index 00000000..b1b2ae16 --- /dev/null +++ b/projects/samskivert/src/java/com/samskivert/servlet/user/AuthenticationFailedException.java @@ -0,0 +1,32 @@ +// +// $Id: AuthenticationFailedException.java,v 1.1 2002/05/02 19:10:34 shaper Exp $ +// +// samskivert library - useful routines for java programs +// Copyright (C) 2002 Walter Korman +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.samskivert.servlet.user; + +/** + * Thrown when a user authentication attempt failed. + */ +public class AuthenticationFailedException extends Exception +{ + public AuthenticationFailedException (String message) + { + super(message); + } +} diff --git a/projects/samskivert/src/java/com/samskivert/servlet/user/Authenticator.java b/projects/samskivert/src/java/com/samskivert/servlet/user/Authenticator.java new file mode 100644 index 00000000..39d1bdad --- /dev/null +++ b/projects/samskivert/src/java/com/samskivert/servlet/user/Authenticator.java @@ -0,0 +1,49 @@ +// +// $Id: Authenticator.java,v 1.1 2002/05/02 19:10:34 shaper Exp $ +// +// samskivert library - useful routines for java programs +// Copyright (C) 2002 Walter Korman +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.samskivert.servlet.user; + +/** + * Provides a means for applications to use their own application-specific + * authentication schemes for validating a user by constructing their own + * authenticator and passing it to {@link UserManager#login}. + */ +public interface Authenticator +{ + /** + * Checks whether the user should be authenticated based on the + * supplied user record and the specified user information. Throws an + * {@link AuthenticationFailedException} if the user fails to pass the + * authentication check for some reason. + * + * @param user the definitive user record loaded from the persistent + * repository against which the user-supplied data is to be checked. + * @param username the username supplied by the user. + * @param password the plaintext password supplied by the user. + * @param persist if true, the cookie will expire in one month, if + * false, the cookie will expire in 24 hours. + * + * @throws AuthenticationFailedException if the user failed to pass + * the authentication check. + */ + public void authenticateUser ( + User user, String username, String password, boolean persist) + throws AuthenticationFailedException; +} diff --git a/projects/samskivert/src/java/com/samskivert/servlet/user/InvalidPasswordException.java b/projects/samskivert/src/java/com/samskivert/servlet/user/InvalidPasswordException.java index dac36025..d56b6720 100644 --- a/projects/samskivert/src/java/com/samskivert/servlet/user/InvalidPasswordException.java +++ b/projects/samskivert/src/java/com/samskivert/servlet/user/InvalidPasswordException.java @@ -1,5 +1,5 @@ // -// $Id: InvalidPasswordException.java,v 1.3 2001/08/12 01:34:31 mdb Exp $ +// $Id: InvalidPasswordException.java,v 1.4 2002/05/02 19:10:34 shaper Exp $ // // samskivert library - useful routines for java programs // Copyright (C) 2001 Michael Bayne @@ -23,7 +23,7 @@ package com.samskivert.servlet.user; /** * Thrown during authentication when an invalid password is supplied. */ -public class InvalidPasswordException extends Exception +public class InvalidPasswordException extends AuthenticationFailedException { public InvalidPasswordException (String message) { diff --git a/projects/samskivert/src/java/com/samskivert/servlet/user/NoSuchUserException.java b/projects/samskivert/src/java/com/samskivert/servlet/user/NoSuchUserException.java index 49750a59..f8c98b7a 100644 --- a/projects/samskivert/src/java/com/samskivert/servlet/user/NoSuchUserException.java +++ b/projects/samskivert/src/java/com/samskivert/servlet/user/NoSuchUserException.java @@ -1,5 +1,5 @@ // -// $Id: NoSuchUserException.java,v 1.3 2001/08/12 01:34:31 mdb Exp $ +// $Id: NoSuchUserException.java,v 1.4 2002/05/02 19:10:34 shaper Exp $ // // samskivert library - useful routines for java programs // Copyright (C) 2001 Michael Bayne @@ -23,7 +23,7 @@ package com.samskivert.servlet.user; /** * Thrown when a user cannot be located in the user database. */ -public class NoSuchUserException extends Exception +public class NoSuchUserException extends AuthenticationFailedException { public NoSuchUserException (String message) { diff --git a/projects/samskivert/src/java/com/samskivert/servlet/user/UserManager.java b/projects/samskivert/src/java/com/samskivert/servlet/user/UserManager.java index 2b2f7c29..3797032c 100644 --- a/projects/samskivert/src/java/com/samskivert/servlet/user/UserManager.java +++ b/projects/samskivert/src/java/com/samskivert/servlet/user/UserManager.java @@ -1,5 +1,5 @@ // -// $Id: UserManager.java,v 1.12 2002/05/02 01:15:09 shaper Exp $ +// $Id: UserManager.java,v 1.13 2002/05/02 19:10:34 shaper Exp $ // // samskivert library - useful routines for java programs // Copyright (C) 2001 Michael Bayne @@ -38,6 +38,48 @@ import com.samskivert.util.*; */ public class UserManager { + /** An instance of the insecure authenticator for general-purpose use. */ + public static final Authenticator AUTH_INSECURE = + new InsecureAuthenticator(); + + /** An instance of the password authenticator for general-purpose use. */ + public static final Authenticator AUTH_PASSWORD = + new PasswordAuthenticator(); + + /** + * A totally insecure authenticator that authenticates any user. + * Note: Applications that make use of this authenticator + * should make sure the user has already been authenticated through + * some other means. + */ + public static class InsecureAuthenticator implements Authenticator + { + // documentation inherited + public void authenticateUser ( + User user, String username, String password, boolean persist) + throws InvalidPasswordException + { + // don't care + } + } + + /** + * An authenticator that requires that the user-supplied password + * match the actual user password. + */ + public static class PasswordAuthenticator implements Authenticator + { + // documentation inherited + public void authenticateUser ( + User user, String username, String password, boolean persist) + throws AuthenticationFailedException + { + if (!user.passwordsMatch(password)) { + throw new InvalidPasswordException("error.invalid_password"); + } + } + } + /** * A user manager must be supplied with a {@link UserRepository} * through which it loads and saves user records. @@ -148,40 +190,6 @@ public class UserManager return user; } - /** - * Authenticates the requester and initiates an authenticated session - * for them. Note: The caller should make sure the user has - * been authenticated through some other means before calling this - * method. An authenticated session involves their receiving a cookie - * that proves them to be authenticated and an entry in the session - * database being created that maps their information to their - * userid. If this call completes, the session was established and the - * proper cookies were set in the supplied response object. If some - * other error occurs, an exception will be thrown. - * - * @param username The username supplied by the user. - * @param persist If true, the cookie will expire in one month, if - * false, the cookie will expire in 24 hours. - * @param rsp the response in which the cookie is to be set. - * - * @return the user object of the authenticated user. - */ - public User login (String username, boolean persist, - HttpServletResponse rsp) - throws PersistenceException, NoSuchUserException - { - // load up the requested user - User user = _repository.loadUser(username); - if (user == null) { - throw new NoSuchUserException("error.no_such_user"); - } - - // generate a session and set the user's auth cookie - generateSession(user, persist, rsp); - - return user; - } - /** * Attempts to authenticate the requester and initiate an * authenticated session for them. An authenticated session involves @@ -196,44 +204,25 @@ public class UserManager * @param password The plaintext password supplied by the user. * @param persist If true, the cookie will expire in one month, if * false, the cookie will expire in 24 hours. - * @param rsp the response in which the cookie is to be set. + * @param rsp The response in which the cookie is to be set. + * @param auth The authenticator used to check whether the user should + * be authenticated. * * @return the user object of the authenticated user. */ public User login (String username, String password, boolean persist, - HttpServletResponse rsp) - throws PersistenceException, NoSuchUserException, - InvalidPasswordException + HttpServletResponse rsp, Authenticator auth) + throws PersistenceException, AuthenticationFailedException { // load up the requested user User user = _repository.loadUser(username); if (user == null) { throw new NoSuchUserException("error.no_such_user"); } - if (!user.passwordsMatch(password)) { - throw new InvalidPasswordException("error.invalid_password"); - } - // generate a session and set the user's auth cookie - generateSession(user, persist, rsp); + // run the user through the authentication gamut + auth.authenticateUser(user, username, password, persist); - return user; - } - - /** - * Creates a new session for the specified user in the session - * database table and sets an authentication cookie in the supplied - * servlet response. - * - * @param user the user for whom a session is to be generated. - * @param persist If true, the cookie will expire in one month, if - * false, the cookie will expire in 24 hours. - * @param rsp the response in which the cookie is to be set. - */ - protected void generateSession (User user, boolean persist, - HttpServletResponse rsp) - throws PersistenceException - { // generate a new session for this user String authcode = _repository.createNewSession(user, persist); // stick it into a cookie for their browsing convenience @@ -245,6 +234,8 @@ public class UserManager acookie.setMaxAge(24*60*60); // expire in 24 hours } rsp.addCookie(acookie); + + return user; } public void logout (HttpServletRequest req, HttpServletResponse rsp) @@ -277,11 +268,16 @@ public class UserManager return null; } + /** The user repository. */ protected UserRepository _repository; + + /** The interval id for the user session pruning interval. */ protected int _prunerid = -1; + /** The URL for the user login page. */ protected String _loginURL; + /** The user authentication cookie name. */ protected static final String USERAUTH_COOKIE = "id_"; /** Prune the session table every hour. */