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