001: /*
002: * Copyright 2003-2006 Rick Knowles <winstone-devel at lists sourceforge net>
003: * Distributed under the terms of either:
004: * - the common development and distribution license (CDDL), v1.0; or
005: * - the GNU Lesser General Public License, v2.1 or later
006: */
007: package winstone.auth;
008:
009: import java.io.IOException;
010: import java.util.List;
011: import java.util.Set;
012:
013: import javax.servlet.ServletException;
014: import javax.servlet.ServletRequest;
015: import javax.servlet.ServletResponse;
016: import javax.servlet.http.HttpServletRequest;
017: import javax.servlet.http.HttpServletRequestWrapper;
018: import javax.servlet.http.HttpServletResponse;
019: import javax.servlet.http.HttpSession;
020:
021: import org.w3c.dom.Node;
022:
023: import winstone.AuthenticationPrincipal;
024: import winstone.AuthenticationRealm;
025: import winstone.Logger;
026: import winstone.WebAppConfiguration;
027: import winstone.WinstoneRequest;
028:
029: /**
030: * Handles FORM based authentication configurations. Fairly simple ... it just
031: * redirects any unauthorized requests to the login page, and any bad logins to
032: * the error page. The auth values are stored in the session in a special slot.
033: *
034: * @author <a href="mailto:rick_knowles@hotmail.com">Rick Knowles</a>
035: * @version $Id: FormAuthenticationHandler.java,v 1.7 2006/12/13 14:07:43 rickknowles Exp $
036: */
037: public class FormAuthenticationHandler extends
038: BaseAuthenticationHandler {
039: private static final String ELEM_FORM_LOGIN_CONFIG = "form-login-config";
040: private static final String ELEM_FORM_LOGIN_PAGE = "form-login-page";
041: private static final String ELEM_FORM_ERROR_PAGE = "form-error-page";
042: private static final String FORM_ACTION = "j_security_check";
043: private static final String FORM_USER = "j_username";
044: private static final String FORM_PASS = "j_password";
045: private static final String AUTHENTICATED_USER = "winstone.auth.FormAuthenticationHandler.AUTHENTICATED_USER";
046: private static final String CACHED_REQUEST = "winstone.auth.FormAuthenticationHandler.CACHED_REQUEST";
047:
048: private String loginPage;
049: private String errorPage;
050:
051: /**
052: * Constructor for the FORM authenticator
053: *
054: * @param realm
055: * The realm against which we are authenticating
056: * @param constraints
057: * The array of security constraints that might apply
058: * @param resources
059: * The list of resource strings for messages
060: * @param realmName
061: * The name of the realm this handler claims
062: */
063: public FormAuthenticationHandler(Node loginConfigNode,
064: List constraintNodes, Set rolesAllowed,
065: AuthenticationRealm realm) {
066: super (loginConfigNode, constraintNodes, rolesAllowed, realm);
067:
068: for (int n = 0; n < loginConfigNode.getChildNodes().getLength(); n++) {
069: Node loginElm = loginConfigNode.getChildNodes().item(n);
070: if (loginElm.getNodeName().equals(ELEM_FORM_LOGIN_CONFIG)) {
071: for (int k = 0; k < loginElm.getChildNodes()
072: .getLength(); k++) {
073: Node formElm = loginElm.getChildNodes().item(k);
074: if (formElm.getNodeType() != Node.ELEMENT_NODE)
075: continue;
076: else if (formElm.getNodeName().equals(
077: ELEM_FORM_LOGIN_PAGE))
078: loginPage = WebAppConfiguration
079: .getTextFromNode(formElm);
080: else if (formElm.getNodeName().equals(
081: ELEM_FORM_ERROR_PAGE))
082: errorPage = WebAppConfiguration
083: .getTextFromNode(formElm);
084: }
085: }
086: }
087: Logger.log(Logger.DEBUG, AUTH_RESOURCES,
088: "FormAuthenticationHandler.Initialised", realmName);
089: }
090:
091: /**
092: * Evaluates any authentication constraints, intercepting if auth is
093: * required. The relevant authentication handler subclass's logic is used to
094: * actually authenticate.
095: *
096: * @return A boolean indicating whether to continue after this request
097: */
098: public boolean processAuthentication(ServletRequest request,
099: ServletResponse response, String pathRequested)
100: throws IOException, ServletException {
101: if (pathRequested.equals(this .loginPage)
102: || pathRequested.equals(this .errorPage)) {
103: return true;
104: } else {
105: return super .processAuthentication(request, response,
106: pathRequested);
107: }
108: }
109:
110: /**
111: * Call this once we know that we need to authenticate
112: */
113: protected void requestAuthentication(HttpServletRequest request,
114: HttpServletResponse response, String pathRequested)
115: throws ServletException, IOException {
116: // Save the critical details of the request into the session map
117: ServletRequest unwrapped = request;
118: while (unwrapped instanceof HttpServletRequestWrapper) {
119: unwrapped = ((HttpServletRequestWrapper) unwrapped)
120: .getRequest();
121: }
122: HttpSession session = request.getSession(true);
123: session.setAttribute(CACHED_REQUEST, new RetryRequestParams(
124: unwrapped));
125:
126: // Forward on to the login page
127: Logger.log(Logger.FULL_DEBUG, AUTH_RESOURCES,
128: "FormAuthenticationHandler.GoToLoginPage");
129: javax.servlet.RequestDispatcher rdLogin = request
130: .getRequestDispatcher(this .loginPage);
131: setNoCache(response);
132: rdLogin.forward(request, response);
133: }
134:
135: /**
136: * Check the response - is it a response to the login page ?
137: *
138: * @return A boolean indicating whether to continue with the request or not
139: */
140: protected boolean validatePossibleAuthenticationResponse(
141: HttpServletRequest request, HttpServletResponse response,
142: String pathRequested) throws ServletException, IOException {
143: // Check if this is a j_security_check uri
144: if (pathRequested.endsWith(FORM_ACTION)) {
145: String username = request.getParameter(FORM_USER);
146: String password = request.getParameter(FORM_PASS);
147:
148: // Send to error page if invalid
149: AuthenticationPrincipal principal = this .realm
150: .authenticateByUsernamePassword(username, password);
151: if (principal == null) {
152: javax.servlet.RequestDispatcher rdError = request
153: .getRequestDispatcher(this .errorPage);
154: rdError.forward(request, response);
155: }
156:
157: // Send to stashed request
158: else {
159: // Iterate back as far as we can
160: ServletRequest wrapperCheck = request;
161: while (wrapperCheck instanceof HttpServletRequestWrapper) {
162: wrapperCheck = ((HttpServletRequestWrapper) wrapperCheck)
163: .getRequest();
164: }
165:
166: // Get the stashed request
167: WinstoneRequest actualRequest = null;
168: if (wrapperCheck instanceof WinstoneRequest) {
169: actualRequest = (WinstoneRequest) wrapperCheck;
170: actualRequest.setRemoteUser(principal);
171: } else {
172: Logger.log(Logger.WARNING, AUTH_RESOURCES,
173: "FormAuthenticationHandler.CantSetUser",
174: wrapperCheck.getClass().getName());
175: }
176: HttpSession session = request.getSession(true);
177: String previousLocation = this .loginPage;
178: RetryRequestParams cachedRequest = (RetryRequestParams) session
179: .getAttribute(CACHED_REQUEST);
180: if ((cachedRequest != null) && (actualRequest != null)) {
181: // Repopulate this request from the params we saved
182: request = new RetryRequestWrapper(request,
183: cachedRequest);
184: previousLocation = (request.getServletPath() == null ? ""
185: : request.getServletPath())
186: + (request.getPathInfo() == null ? ""
187: : request.getPathInfo());
188: } else {
189: Logger
190: .log(Logger.DEBUG, AUTH_RESOURCES,
191: "FormAuthenticationHandler.NoCachedRequest");
192: }
193:
194: // do role check, since we don't know that this user has permission
195: if (doRoleCheck(request, response, previousLocation)) {
196: principal.setAuthType(HttpServletRequest.FORM_AUTH);
197: session.setAttribute(AUTHENTICATED_USER, principal);
198: javax.servlet.RequestDispatcher rdPrevious = request
199: .getRequestDispatcher(previousLocation);
200: rdPrevious.forward(request, response);
201: } else {
202: javax.servlet.RequestDispatcher rdError = request
203: .getRequestDispatcher(this .errorPage);
204: rdError.forward(request, response);
205: }
206: }
207: return false;
208: }
209: // If it's not a login, get the session, and look up the auth user variable
210: else {
211: WinstoneRequest actualRequest = null;
212: if (request instanceof WinstoneRequest) {
213: actualRequest = (WinstoneRequest) request;
214: } else if (request instanceof HttpServletRequestWrapper) {
215: HttpServletRequestWrapper wrapper = (HttpServletRequestWrapper) request;
216: if (wrapper.getRequest() instanceof WinstoneRequest) {
217: actualRequest = (WinstoneRequest) wrapper
218: .getRequest();
219: } else {
220: Logger.log(Logger.WARNING, AUTH_RESOURCES,
221: "FormAuthenticationHandler.CantSetUser",
222: wrapper.getRequest().getClass().getName());
223: }
224: } else {
225: Logger.log(Logger.WARNING, AUTH_RESOURCES,
226: "FormAuthenticationHandler.CantSetUser",
227: request.getClass().getName());
228: }
229:
230: HttpSession session = actualRequest.getSession(false);
231: if (session != null) {
232: AuthenticationPrincipal authenticatedUser = (AuthenticationPrincipal) session
233: .getAttribute(AUTHENTICATED_USER);
234: if (authenticatedUser != null) {
235: actualRequest.setRemoteUser(authenticatedUser);
236: Logger
237: .log(Logger.FULL_DEBUG, AUTH_RESOURCES,
238: "FormAuthenticationHandler.GotUserFromSession");
239: }
240: }
241: return true;
242: }
243: }
244: }
|