/*
* Copyright 2003-2006 Rick Knowles <winstone-devel at lists sourceforge net>
* Distributed under the terms of either:
* - the common development and distribution license (CDDL), v1.0; or
* - the GNU Lesser General Public License, v2.1 or later
*/
package winstone.auth;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.w3c.dom.Node;
import winstone.AuthenticationHandler;
import winstone.AuthenticationRealm;
import winstone.Logger;
import winstone.WebAppConfiguration;
import winstone.WinstoneResourceBundle;
/**
* Base class for managers of authentication within Winstone. This class also
* acts as a factory, loading the appropriate subclass for the requested auth
* type.
*
* @author mailto: <a href="rick_knowles@hotmail.com">Rick Knowles</a>
* @version $Id: BaseAuthenticationHandler.java,v 1.6 2006/02/28 07:32:47 rickknowles Exp $
*/
public abstract class BaseAuthenticationHandler implements
AuthenticationHandler {
static final String ELEM_REALM_NAME = "realm-name";
protected SecurityConstraint constraints[];
protected AuthenticationRealm realm;
protected String realmName;
public final static WinstoneResourceBundle AUTH_RESOURCES = new WinstoneResourceBundle("winstone.auth.LocalStrings");
/**
* Factory method - this parses the web.xml nodes and builds the correct
* subclass for handling that auth type.
*/
protected BaseAuthenticationHandler(Node loginConfigNode,
List constraintNodes, Set rolesAllowed,
AuthenticationRealm realm) {
this.realm = realm;
for (int m = 0; m < loginConfigNode.getChildNodes().getLength(); m++) {
Node loginElm = loginConfigNode.getChildNodes().item(m);
if (loginElm.getNodeType() != Node.ELEMENT_NODE)
continue;
else if (loginElm.getNodeName().equals(ELEM_REALM_NAME))
realmName = WebAppConfiguration.getTextFromNode(loginElm);
}
// Build security constraints
this.constraints = new SecurityConstraint[constraintNodes.size()];
for (int n = 0; n < constraints.length; n++)
this.constraints[n] = new SecurityConstraint((Node) constraintNodes
.get(n), rolesAllowed, n);
}
/**
* Evaluates any authentication constraints, intercepting if auth is
* required. The relevant authentication handler subclass's logic is used to
* actually authenticate.
*
* @return A boolean indicating whether to continue after this request
*/
public boolean processAuthentication(ServletRequest inRequest,
ServletResponse inResponse, String pathRequested)
throws IOException, ServletException {
Logger.log(Logger.FULL_DEBUG, AUTH_RESOURCES,
"BaseAuthenticationHandler.StartAuthCheck");
HttpServletRequest request = (HttpServletRequest) inRequest;
HttpServletResponse response = (HttpServletResponse) inResponse;
// Give previous attempts a chance to be validated
if (!validatePossibleAuthenticationResponse(request, response, pathRequested)) {
return false;
} else {
return doRoleCheck(request, response, pathRequested);
}
}
protected boolean doRoleCheck(HttpServletRequest request,
HttpServletResponse response, String pathRequested)
throws IOException, ServletException {
// Loop through constraints
boolean foundApplicable = false;
for (int n = 0; (n < this.constraints.length) && !foundApplicable; n++) {
Logger.log(Logger.FULL_DEBUG, AUTH_RESOURCES,
"BaseAuthenticationHandler.EvalConstraint",
this.constraints[n].getName());
// Find one that applies, then
if (this.constraints[n].isApplicable(pathRequested, request.getMethod())) {
Logger.log(Logger.FULL_DEBUG, AUTH_RESOURCES,
"BaseAuthenticationHandler.ApplicableConstraint",
this.constraints[n].getName());
foundApplicable = true;
if (this.constraints[n].needsSSL() && !request.isSecure()) {
Logger.log(Logger.DEBUG, AUTH_RESOURCES,
"BaseAuthenticationHandler.ConstraintNeedsSSL",
this.constraints[n].getName());
response.sendError(HttpServletResponse.SC_FORBIDDEN,
AUTH_RESOURCES.getString("BaseAuthenticationHandler.ConstraintNeedsSSL",
this.constraints[n].getName()));
return false;
}
else if (!this.constraints[n].isAllowed(request)) {
// Logger.log(Logger.FULL_DEBUG, "Not allowed - requesting auth");
requestAuthentication(request, response, pathRequested);
return false;
} else {
// Logger.log(Logger.FULL_DEBUG, "Allowed - authorization accepted");
// Ensure that secured resources are not cached
setNoCache(response);
}
}
}
// If we made it this far without a check being run, there must be none applicable
Logger.log(Logger.FULL_DEBUG, AUTH_RESOURCES, "BaseAuthenticationHandler.PassedAuthCheck");
return true;
}
protected void setNoCache(HttpServletResponse response) {
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "No-cache");
response.setDateHeader("Expires", 1);
}
/**
* The actual auth request implementation.
*/
protected abstract void requestAuthentication(HttpServletRequest request,
HttpServletResponse response, String pathRequested)
throws IOException, ServletException;
/**
* Handling the (possible) response
*/
protected abstract boolean validatePossibleAuthenticationResponse(
HttpServletRequest request, HttpServletResponse response,
String pathRequested) throws ServletException, IOException;
}