2
* Copyright 2003-2006 Rick Knowles <winstone-devel at lists sourceforge net>
3
* Distributed under the terms of either:
4
* - the common development and distribution license (CDDL), v1.0; or
5
* - the GNU Lesser General Public License, v2.1 or later
9
import java.io.IOException;
10
import java.util.List;
13
import javax.servlet.ServletException;
14
import javax.servlet.ServletRequest;
15
import javax.servlet.ServletResponse;
16
import javax.servlet.http.HttpServletRequest;
17
import javax.servlet.http.HttpServletRequestWrapper;
18
import javax.servlet.http.HttpServletResponse;
19
import javax.servlet.http.HttpSession;
21
import org.w3c.dom.Node;
23
import winstone.AuthenticationPrincipal;
24
import winstone.AuthenticationRealm;
25
import winstone.Logger;
26
import winstone.WebAppConfiguration;
27
import winstone.WinstoneRequest;
30
* Handles FORM based authentication configurations. Fairly simple ... it just
31
* redirects any unauthorized requests to the login page, and any bad logins to
32
* the error page. The auth values are stored in the session in a special slot.
34
* @author <a href="mailto:rick_knowles@hotmail.com">Rick Knowles</a>
35
* @version $Id: FormAuthenticationHandler.java,v 1.7 2006/12/13 14:07:43 rickknowles Exp $
37
public class FormAuthenticationHandler extends BaseAuthenticationHandler {
38
private static final String ELEM_FORM_LOGIN_CONFIG = "form-login-config";
39
private static final String ELEM_FORM_LOGIN_PAGE = "form-login-page";
40
private static final String ELEM_FORM_ERROR_PAGE = "form-error-page";
41
private static final String FORM_ACTION = "j_security_check";
42
private static final String FORM_USER = "j_username";
43
private static final String FORM_PASS = "j_password";
44
private static final String AUTHENTICATED_USER = "winstone.auth.FormAuthenticationHandler.AUTHENTICATED_USER";
45
private static final String CACHED_REQUEST = "winstone.auth.FormAuthenticationHandler.CACHED_REQUEST";
47
private String loginPage;
48
private String errorPage;
51
* Constructor for the FORM authenticator
54
* The realm against which we are authenticating
56
* The array of security constraints that might apply
58
* The list of resource strings for messages
60
* The name of the realm this handler claims
62
public FormAuthenticationHandler(Node loginConfigNode,
63
List constraintNodes, Set rolesAllowed,
64
AuthenticationRealm realm) {
65
super(loginConfigNode, constraintNodes, rolesAllowed, realm);
67
for (int n = 0; n < loginConfigNode.getChildNodes().getLength(); n++) {
68
Node loginElm = loginConfigNode.getChildNodes().item(n);
69
if (loginElm.getNodeName().equals(ELEM_FORM_LOGIN_CONFIG)) {
70
for (int k = 0; k < loginElm.getChildNodes().getLength(); k++) {
71
Node formElm = loginElm.getChildNodes().item(k);
72
if (formElm.getNodeType() != Node.ELEMENT_NODE)
74
else if (formElm.getNodeName().equals(ELEM_FORM_LOGIN_PAGE))
75
loginPage = WebAppConfiguration.getTextFromNode(formElm);
76
else if (formElm.getNodeName().equals(ELEM_FORM_ERROR_PAGE))
77
errorPage = WebAppConfiguration.getTextFromNode(formElm);
81
Logger.log(Logger.DEBUG, AUTH_RESOURCES,
82
"FormAuthenticationHandler.Initialised", realmName);
86
* Evaluates any authentication constraints, intercepting if auth is
87
* required. The relevant authentication handler subclass's logic is used to
88
* actually authenticate.
90
* @return A boolean indicating whether to continue after this request
92
public boolean processAuthentication(ServletRequest request,
93
ServletResponse response, String pathRequested) throws IOException,
95
if (pathRequested.equals(this.loginPage)
96
|| pathRequested.equals(this.errorPage)) {
99
return super.processAuthentication(request, response, pathRequested);
104
* Call this once we know that we need to authenticate
106
protected void requestAuthentication(HttpServletRequest request,
107
HttpServletResponse response, String pathRequested)
108
throws ServletException, IOException {
109
// Save the critical details of the request into the session map
110
ServletRequest unwrapped = request;
111
while (unwrapped instanceof HttpServletRequestWrapper) {
112
unwrapped = ((HttpServletRequestWrapper) unwrapped).getRequest();
114
HttpSession session = request.getSession(true);
115
session.setAttribute(CACHED_REQUEST, new RetryRequestParams(unwrapped));
117
// Forward on to the login page
118
Logger.log(Logger.FULL_DEBUG, AUTH_RESOURCES,
119
"FormAuthenticationHandler.GoToLoginPage");
120
javax.servlet.RequestDispatcher rdLogin = request
121
.getRequestDispatcher(this.loginPage);
122
setNoCache(response);
123
rdLogin.forward(request, response);
127
* Check the response - is it a response to the login page ?
129
* @return A boolean indicating whether to continue with the request or not
131
protected boolean validatePossibleAuthenticationResponse(
132
HttpServletRequest request, HttpServletResponse response,
133
String pathRequested) throws ServletException, IOException {
134
// Check if this is a j_security_check uri
135
if (pathRequested.endsWith(FORM_ACTION)) {
136
String username = request.getParameter(FORM_USER);
137
String password = request.getParameter(FORM_PASS);
139
// Send to error page if invalid
140
AuthenticationPrincipal principal = this.realm
141
.authenticateByUsernamePassword(username, password);
142
if (principal == null) {
143
javax.servlet.RequestDispatcher rdError = request
144
.getRequestDispatcher(this.errorPage);
145
rdError.forward(request, response);
148
// Send to stashed request
150
// Iterate back as far as we can
151
ServletRequest wrapperCheck = request;
152
while (wrapperCheck instanceof HttpServletRequestWrapper) {
153
wrapperCheck = ((HttpServletRequestWrapper) wrapperCheck).getRequest();
156
// Get the stashed request
157
WinstoneRequest actualRequest = null;
158
if (wrapperCheck instanceof WinstoneRequest) {
159
actualRequest = (WinstoneRequest) wrapperCheck;
160
actualRequest.setRemoteUser(principal);
162
Logger.log(Logger.WARNING, AUTH_RESOURCES,
163
"FormAuthenticationHandler.CantSetUser",
164
wrapperCheck.getClass().getName());
166
HttpSession session = request.getSession(true);
167
String previousLocation = this.loginPage;
168
RetryRequestParams cachedRequest = (RetryRequestParams)
169
session.getAttribute(CACHED_REQUEST);
170
if ((cachedRequest != null) && (actualRequest != null)) {
171
// Repopulate this request from the params we saved
172
request = new RetryRequestWrapper(request, cachedRequest);
174
(request.getServletPath() == null ? "" : request.getServletPath()) +
175
(request.getPathInfo() == null ? "" : request.getPathInfo());
177
Logger.log(Logger.DEBUG, AUTH_RESOURCES,
178
"FormAuthenticationHandler.NoCachedRequest");
181
// do role check, since we don't know that this user has permission
182
if (doRoleCheck(request, response, previousLocation)) {
183
principal.setAuthType(HttpServletRequest.FORM_AUTH);
184
session.setAttribute(AUTHENTICATED_USER, principal);
185
javax.servlet.RequestDispatcher rdPrevious = request
186
.getRequestDispatcher(previousLocation);
187
rdPrevious.forward(request, response);
189
javax.servlet.RequestDispatcher rdError = request
190
.getRequestDispatcher(this.errorPage);
191
rdError.forward(request, response);
196
// If it's not a login, get the session, and look up the auth user variable
198
WinstoneRequest actualRequest = null;
199
if (request instanceof WinstoneRequest) {
200
actualRequest = (WinstoneRequest) request;
201
} else if (request instanceof HttpServletRequestWrapper) {
202
HttpServletRequestWrapper wrapper = (HttpServletRequestWrapper) request;
203
if (wrapper.getRequest() instanceof WinstoneRequest) {
204
actualRequest = (WinstoneRequest) wrapper.getRequest();
206
Logger.log(Logger.WARNING, AUTH_RESOURCES,
207
"FormAuthenticationHandler.CantSetUser", wrapper
208
.getRequest().getClass().getName());
211
Logger.log(Logger.WARNING, AUTH_RESOURCES,
212
"FormAuthenticationHandler.CantSetUser", request
213
.getClass().getName());
216
HttpSession session = actualRequest.getSession(false);
217
if (session != null) {
218
AuthenticationPrincipal authenticatedUser = (AuthenticationPrincipal)
219
session.getAttribute(AUTHENTICATED_USER);
220
if (authenticatedUser != null) {
221
actualRequest.setRemoteUser(authenticatedUser);
222
Logger.log(Logger.FULL_DEBUG, AUTH_RESOURCES,
223
"FormAuthenticationHandler.GotUserFromSession");