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