1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.security.authentication;
15
16 import java.io.IOException;
17 import java.util.ArrayList;
18 import java.util.Collection;
19 import java.util.Collections;
20 import java.util.Enumeration;
21 import java.util.List;
22
23 import javax.servlet.RequestDispatcher;
24 import javax.servlet.ServletException;
25 import javax.servlet.ServletRequest;
26 import javax.servlet.ServletResponse;
27 import javax.servlet.http.HttpServletRequest;
28 import javax.servlet.http.HttpServletRequestWrapper;
29 import javax.servlet.http.HttpServletResponse;
30 import javax.servlet.http.HttpServletResponseWrapper;
31 import javax.servlet.http.HttpSession;
32
33 import org.eclipse.jetty.http.HttpHeaders;
34 import org.eclipse.jetty.http.security.Constraint;
35 import org.eclipse.jetty.security.Authenticator;
36 import org.eclipse.jetty.security.UserAuthentication;
37 import org.eclipse.jetty.security.ServerAuthException;
38 import org.eclipse.jetty.server.Authentication;
39 import org.eclipse.jetty.server.UserIdentity;
40 import org.eclipse.jetty.server.Authentication.User;
41 import org.eclipse.jetty.util.StringUtil;
42 import org.eclipse.jetty.util.URIUtil;
43 import org.eclipse.jetty.util.log.Log;
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 public class FormAuthenticator extends LoginAuthenticator
59 {
60 public final static String __FORM_LOGIN_PAGE="org.eclipse.jetty.security.form_login_page";
61 public final static String __FORM_ERROR_PAGE="org.eclipse.jetty.security.form_error_page";
62 public final static String __FORM_DISPATCH="org.eclipse.jetty.security.dispatch";
63 public final static String __J_URI = "org.eclipse.jetty.util.URI";
64 public final static String __J_AUTHENTICATED = "org.eclipse.jetty.server.Auth";
65 public final static String __J_SECURITY_CHECK = "/j_security_check";
66 public final static String __J_USERNAME = "j_username";
67 public final static String __J_PASSWORD = "j_password";
68 private String _formErrorPage;
69 private String _formErrorPath;
70 private String _formLoginPage;
71 private String _formLoginPath;
72 private boolean _dispatch;
73
74 public FormAuthenticator()
75 {
76 }
77
78
79 public FormAuthenticator(String login,String error)
80 {
81 if (login!=null)
82 setLoginPage(login);
83 if (error!=null)
84 setErrorPage(error);
85 }
86
87
88
89
90
91 @Override
92 public void setConfiguration(Configuration configuration)
93 {
94 super.setConfiguration(configuration);
95 String login=configuration.getInitParameter(FormAuthenticator.__FORM_LOGIN_PAGE);
96 if (login!=null)
97 setLoginPage(login);
98 String error=configuration.getInitParameter(FormAuthenticator.__FORM_ERROR_PAGE);
99 if (error!=null)
100 setErrorPage(error);
101 String dispatch=configuration.getInitParameter(FormAuthenticator.__FORM_DISPATCH);
102 _dispatch=dispatch==null || Boolean.getBoolean(dispatch);
103 }
104
105
106 public String getAuthMethod()
107 {
108 return Constraint.__FORM_AUTH;
109 }
110
111
112 private void setLoginPage(String path)
113 {
114 if (!path.startsWith("/"))
115 {
116 Log.warn("form-login-page must start with /");
117 path = "/" + path;
118 }
119 _formLoginPage = path;
120 _formLoginPath = path;
121 if (_formLoginPath.indexOf('?') > 0)
122 _formLoginPath = _formLoginPath.substring(0, _formLoginPath.indexOf('?'));
123 }
124
125
126 private void setErrorPage(String path)
127 {
128 if (path == null || path.trim().length() == 0)
129 {
130 _formErrorPath = null;
131 _formErrorPage = null;
132 }
133 else
134 {
135 if (!path.startsWith("/"))
136 {
137 Log.warn("form-error-page must start with /");
138 path = "/" + path;
139 }
140 _formErrorPage = path;
141 _formErrorPath = path;
142
143 if (_formErrorPath.indexOf('?') > 0)
144 _formErrorPath = _formErrorPath.substring(0, _formErrorPath.indexOf('?'));
145 }
146 }
147
148
149 public Authentication validateRequest(ServletRequest req, ServletResponse res, boolean mandatory) throws ServerAuthException
150 {
151 HttpServletRequest request = (HttpServletRequest)req;
152 HttpServletResponse response = (HttpServletResponse)res;
153 HttpSession session = request.getSession(mandatory);
154 String uri = request.getPathInfo();
155
156
157 if (session == null || isLoginOrErrorPage(uri))
158 {
159 return Authentication.NOT_CHECKED;
160 }
161
162
163 try
164 {
165
166 if (uri==null)
167 uri=URIUtil.SLASH;
168 else if (uri.endsWith(__J_SECURITY_CHECK))
169 {
170 final String username = request.getParameter(__J_USERNAME);
171 final String password = request.getParameter(__J_PASSWORD);
172
173 UserIdentity user = _loginService.login(username,password);
174 if (user!=null)
175 {
176
177 String nuri;
178 synchronized(session)
179 {
180 nuri = (String) session.getAttribute(__J_URI);
181 session.removeAttribute(__J_URI);
182 }
183
184 if (nuri == null || nuri.length() == 0)
185 {
186 nuri = request.getContextPath();
187 if (nuri.length() == 0)
188 nuri = URIUtil.SLASH;
189 }
190 response.setContentLength(0);
191 response.sendRedirect(response.encodeRedirectURL(nuri));
192 return new FormAuthentication(this,user);
193 }
194
195
196 if (Log.isDebugEnabled())
197 Log.debug("Form authentication FAILED for " + StringUtil.printable(username));
198 if (_formErrorPage == null)
199 {
200 if (response != null)
201 response.sendError(HttpServletResponse.SC_FORBIDDEN);
202 }
203 else if (_dispatch)
204 {
205 RequestDispatcher dispatcher = request.getRequestDispatcher(_formErrorPage);
206 response.setHeader(HttpHeaders.CACHE_CONTROL,"No-cache");
207 response.setDateHeader(HttpHeaders.EXPIRES,1);
208 dispatcher.forward(new FormRequest(request), new FormResponse(response));
209 }
210 else
211 {
212 response.sendRedirect(URIUtil.addPaths(request.getContextPath(),_formErrorPage));
213 }
214
215 return Authentication.FAILURE;
216 }
217
218 if (mandatory)
219 {
220
221 if (request.getQueryString() != null)
222 uri += "?" + request.getQueryString();
223
224 synchronized (session)
225 {
226 if (session.getAttribute(__J_URI)==null)
227 session.setAttribute(__J_URI, request.getScheme() + "://"
228 + request.getServerName()
229 + ":"
230 + request.getServerPort()
231 + URIUtil.addPaths(request.getContextPath(), uri));
232 }
233
234 if (_dispatch)
235 {
236 RequestDispatcher dispatcher = request.getRequestDispatcher(_formLoginPage);
237 response.setHeader(HttpHeaders.CACHE_CONTROL,"No-cache");
238 response.setDateHeader(HttpHeaders.EXPIRES,1);
239 dispatcher.forward(new FormRequest(request), new FormResponse(response));
240 }
241 else
242 {
243 response.sendRedirect(URIUtil.addPaths(request.getContextPath(),_formLoginPage));
244 }
245 return Authentication.CHALLENGE;
246 }
247
248 return Authentication.UNAUTHENTICATED;
249 }
250 catch (IOException e)
251 {
252 throw new ServerAuthException(e);
253 }
254 catch (ServletException e)
255 {
256 throw new ServerAuthException(e);
257 }
258 }
259
260
261 public boolean isLoginOrErrorPage(String pathInContext)
262 {
263 return pathInContext != null && (pathInContext.equals(_formErrorPath) || pathInContext.equals(_formLoginPath));
264 }
265
266
267 public boolean secureResponse(ServletRequest req, ServletResponse res, boolean mandatory, User validatedUser) throws ServerAuthException
268 {
269 return true;
270 }
271
272
273
274 protected static class FormRequest extends HttpServletRequestWrapper
275 {
276 public FormRequest(HttpServletRequest request)
277 {
278 super(request);
279 }
280
281 @Override
282 public long getDateHeader(String name)
283 {
284 if (name.toLowerCase().startsWith("if-"))
285 return -1;
286 return super.getDateHeader(name);
287 }
288
289 @Override
290 public String getHeader(String name)
291 {
292 if (name.toLowerCase().startsWith("if-"))
293 return null;
294 return super.getHeader(name);
295 }
296
297 @Override
298 public Enumeration getHeaderNames()
299 {
300 return Collections.enumeration(Collections.list(super.getHeaderNames()));
301 }
302
303 @Override
304 public Enumeration getHeaders(String name)
305 {
306 if (name.toLowerCase().startsWith("if-"))
307 return Collections.enumeration(Collections.EMPTY_LIST);
308 return super.getHeaders(name);
309 }
310 }
311
312
313
314 protected static class FormResponse extends HttpServletResponseWrapper
315 {
316 public FormResponse(HttpServletResponse response)
317 {
318 super(response);
319 }
320
321 @Override
322 public void addDateHeader(String name, long date)
323 {
324 if (notIgnored(name))
325 super.addDateHeader(name,date);
326 }
327
328 @Override
329 public void addHeader(String name, String value)
330 {
331 if (notIgnored(name))
332 super.addHeader(name,value);
333 }
334
335 @Override
336 public void setDateHeader(String name, long date)
337 {
338 if (notIgnored(name))
339 super.setDateHeader(name,date);
340 }
341
342 @Override
343 public void setHeader(String name, String value)
344 {
345 if (notIgnored(name))
346 super.setHeader(name,value);
347 }
348
349 private boolean notIgnored(String name)
350 {
351 if (HttpHeaders.CACHE_CONTROL.equalsIgnoreCase(name) ||
352 HttpHeaders.PRAGMA.equalsIgnoreCase(name) ||
353 HttpHeaders.ETAG.equalsIgnoreCase(name) ||
354 HttpHeaders.EXPIRES.equalsIgnoreCase(name) ||
355 HttpHeaders.LAST_MODIFIED.equalsIgnoreCase(name) ||
356 HttpHeaders.AGE.equalsIgnoreCase(name))
357 return false;
358 return true;
359 }
360 }
361
362 public static class FormAuthentication extends UserAuthentication implements Authentication.ResponseSent
363 {
364 public FormAuthentication(Authenticator authenticator, UserIdentity userIdentity)
365 {
366 super(authenticator,userIdentity);
367 }
368
369 public String toString()
370 {
371 return "Form"+super.toString();
372 }
373 }
374 }