/*
- * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/authenticator/BasicAuthenticator.java,v 1.1 2003/07/07 13:12:56 maxcooper Exp $
- * $Revision: 1.1 $
- * $Date: 2003/07/07 13:12:56 $
+ * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/authenticator/BasicAuthenticator.java,v 1.2 2003/07/14 18:55:14 maxcooper Exp $
+ * $Revision: 1.2 $
+ * $Date: 2003/07/14 18:55:14 $
*
* ====================================================================
* The SecurityFilter Software License, Version 1.1
*
* @author Daya Sharma (iamdaya@yahoo.com, billydaya@sbcglobal.net)
* @author Max Cooper (max@maxcooper.com)
- * @version $Revision: 1.1 $ $Date: 2003/07/07 13:12:56 $
+ * @version $Revision: 1.2 $ $Date: 2003/07/14 18:55:14 $
*/
public class BasicAuthenticator implements Authenticator {
- public static final String BASIC_WINDOW_SHOWN = "basic_window_shown";
- public static final String LOGIN_ATTEMPTS = "loginAttempts";
- protected static final String DUMMY_TOKEN = "dummyToken";
+ public static final String LOGIN_ATTEMPTS = BasicAuthenticator.class.getName() + ".LOGIN_ATTEMPTS";
- public static final Base64 base64Helper = new Base64();
-
- protected String tooManyIncorrectLogins;
+ // todo: allow this message to be configured, internationalized, etc.
+ public static final String LOGIN_FAILED_MESSAGE = "Sorry you are having problems logging in, please try again";
+ public static final int MAX_ATTEMPTS = 3;
protected SecurityRealmInterface realm;
+ protected String realmName;
+ protected Base64 base64Helper;
+
/**
* Initialize this Authenticator.
*/
public void init(FilterConfig filterConfig, SecurityConfig securityConfig) throws Exception {
realm = securityConfig.getRealm();
- tooManyIncorrectLogins = "Sorry you are having problems logging in, please try again";
+ realmName = securityConfig.getRealmName();
+ base64Helper = new Base64();
}
/**
* @return true if the filter should return after this method ends, false otherwise
*/
public boolean processLogin(SecurityRequestWrapper request, HttpServletResponse response) throws Exception {
- if (basicAuthentication(request)) {
- request.getSession().removeAttribute(BASIC_WINDOW_SHOWN);
- String username = parseUsername(request.getHeader("Authorization"));
- String password = parsePassword(request.getHeader("Authorization"));
- Principal principal = realm.authenticate(username, password);
- if (principal != null) {
- // login successful
- // invalidate old session if the user was already authenticated
- // NOTE: we may want to check if the user re-authenticated as the same user, currently
- // the session will be invalidated even if the user authenticates as the same user.
- request.setUserPrincipal(principal);
- String continueToURL = SecurityFilter.getContinueToURL(request);
- request.getSession().setAttribute(DUMMY_TOKEN, DUMMY_TOKEN);
- // This is the url that the user was initially accessing before being prompted for login.
- response.sendRedirect(response.encodeRedirectURL(continueToURL));
- } else {
- // login failed
- // show the basic authentication window again.
- showLogin(request.getCurrentRequest(), response);
+ if (request.getUserPrincipal() == null) {
+ // attempt to dig out authentication info only if the user has not yet been authenticated
+ String authorizationHeader = request.getHeader("Authorization");
+ HttpSession session = request.getSession();
+ if (authorizationHeader != null && session.getAttribute(LOGIN_ATTEMPTS) != null) {
+ String decoded = decodeBasicAuthorizationString(authorizationHeader);
+ String username = parseUsername(decoded);
+ String password = parsePassword(decoded);
+ Principal principal = realm.authenticate(username, password);
+ if (principal != null) {
+ // login successful
+ request.getSession().removeAttribute(LOGIN_ATTEMPTS);
+ request.setUserPrincipal(principal);
+ } else {
+ // login failed
+ // show the basic authentication window again.
+ showLogin(request.getCurrentRequest(), response);
+ return true;
+ }
}
}
return false;
}
/**
- * Returns true if this request includes BASIC auth info.
+ * All requests should be subject to security checking for BASIC authentication.
*
* @param request
- * @return
+ * @return always false -- check all requests
+ */
+ public boolean bypassSecurityForThisRequest(SecurityRequestWrapper request, URLPatternMatcher patternMatcher) {
+ return false;
+ }
+
+ /**
+ * Show the login page.
+ *
+ * @param request the current request
+ * @param response the current response
*/
- private boolean basicAuthentication(HttpServletRequest request) {
- return (
- request.getSession().getAttribute(BASIC_WINDOW_SHOWN) != null
- && request.getHeader("Authorization") != null
- );
+ public void showLogin(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ // save this request
+ SecurityFilter.saveRequestInformation(request);
+
+ // determine the number of login attempts
+ int loginAttempts;
+ if (request.getSession().getAttribute(LOGIN_ATTEMPTS) != null) {
+ loginAttempts = ((Integer) request.getSession().getAttribute(LOGIN_ATTEMPTS)).intValue();
+ loginAttempts += 1;
+ } else {
+ loginAttempts = 1;
+ }
+ request.getSession().setAttribute(LOGIN_ATTEMPTS, new Integer(loginAttempts));
+
+ if (loginAttempts <= MAX_ATTEMPTS) {
+ response.setHeader("WWW-Authenticate", "BASIC realm=\"" + realmName + "\"");
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ } else {
+ request.getSession().removeAttribute(LOGIN_ATTEMPTS);
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED, LOGIN_FAILED_MESSAGE);
+ }
}
/**
* Parse the username out of the BASIC authorization header string.
- * @param authorization
- * @return
+ * @param decoded
+ * @return username parsed out of decoded string
*/
- private String parseUsername(String authorization) {
- String unencoded = decodeBasicAuthorizationString(authorization);
- if (unencoded == null) {
+ private String parseUsername(String decoded) {
+ if (decoded == null) {
return null;
} else {
- int colon = unencoded.indexOf(':');
+ int colon = decoded.indexOf(':');
if (colon < 0) {
return null;
} else {
- return unencoded.substring(0, colon).trim();
+ return decoded.substring(0, colon).trim();
}
}
}
/**
- * Parse the password out of the BASIC authorization header string.
- * @param authorization
- * @return
+ * Parse the password out of the decoded BASIC authorization header string.
+ * @param decoded
+ * @return password parsed out of decoded string
*/
- private String parsePassword(String authorization) {
- String unencoded = decodeBasicAuthorizationString(authorization);
- if (unencoded == null) {
+ private String parsePassword(String decoded) {
+ if (decoded == null) {
return null;
} else {
- int colon = unencoded.indexOf(':');
+ int colon = decoded.indexOf(':');
if (colon < 0) {
return (null);
} else {
- return unencoded.substring(colon + 1).trim();
+ return decoded.substring(colon + 1).trim();
}
}
}
* Decode the BASIC authorization string.
*
* @param authorization
- * @return
+ * @return decoded string
*/
private String decodeBasicAuthorizationString(String authorization) {
if (authorization == null || !authorization.toLowerCase().startsWith("basic ")) {
return new String(base64Helper.decodeBase64(authorization.getBytes()));
}
}
-
- /**
- * Show the login page.
- *
- * @param request the current request
- * @param response the current response
- */
- public void showLogin(HttpServletRequest request, HttpServletResponse response) throws IOException {
- // save this request
- SecurityFilter.saveRequestInformation(request);
-
- // redirect to login page
- request.getSession().setAttribute(BASIC_WINDOW_SHOWN, "shown");
- int loginAttempts = 1;
- if (request.getSession().getAttribute(LOGIN_ATTEMPTS) != null) {
- loginAttempts = ((Integer) request.getSession().getAttribute(LOGIN_ATTEMPTS)).intValue();
- loginAttempts += 1;
- }
- // todo: we can put some useful message here, perhaps a internationlizable format of message.
- String loginAttemptMessage = "Login attempt number " + loginAttempts;
- String logo;
- if (loginAttempts <= 3) {
- String realm = String.valueOf(Math.random());
- if (loginAttempts < 2) {
- logo = "Basic Auth with Security Filter";
- } else {
- logo = loginAttemptMessage;
- }
- String blankLine = " ";
- logo = blankLine + blankLine + blankLine + logo + blankLine + blankLine;
- System.err.println("response.setHeader \"WWW-Authenticate\", \"BASIC realm=\"" + logo + realm + "\"");
- response.setHeader("WWW-Authenticate", "BASIC realm=\"" + realm + logo + "\"");
- response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
- request.getSession().setAttribute(LOGIN_ATTEMPTS, new Integer(loginAttempts));
- } else {
- request.getSession().removeAttribute(LOGIN_ATTEMPTS);
- response.sendError(HttpServletResponse.SC_UNAUTHORIZED, tooManyIncorrectLogins);
- }
- }
-
- /**
- * All requests should be subject to security checking for BASIC authentication.
- *
- * @param request
- * @return always false -- check all requests
- */
- public boolean bypassSecurityForThisRequest(SecurityRequestWrapper request, URLPatternMatcher patternMatcher) {
- return false;
- }
}
// ------------------------------------------------------------------------