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.getRequestURI();
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 synchronized (session)
219 {
220 if (session.getAttribute(__J_URI)==null)
221 {
222 StringBuffer buf = request.getRequestURL();
223 if (request.getQueryString() != null)
224 buf.append("?").append(request.getQueryString());
225 session.setAttribute(__J_URI, buf.toString());
226 }
227 }
228
229 if (_dispatch)
230 {
231 RequestDispatcher dispatcher = request.getRequestDispatcher(_formLoginPage);
232 response.setHeader(HttpHeaders.CACHE_CONTROL,"No-cache");
233 response.setDateHeader(HttpHeaders.EXPIRES,1);
234 dispatcher.forward(new FormRequest(request), new FormResponse(response));
235 }
236 else
237 {
238 response.sendRedirect(URIUtil.addPaths(request.getContextPath(),_formLoginPage));
239 }
240 return Authentication.SEND_CONTINUE;
241 }
242
243 return Authentication.UNAUTHENTICATED;
244 }
245 catch (IOException e)
246 {
247 throw new ServerAuthException(e);
248 }
249 catch (ServletException e)
250 {
251 throw new ServerAuthException(e);
252 }
253 }
254
255
256 public boolean isLoginOrErrorPage(String pathInContext)
257 {
258 return pathInContext != null && (pathInContext.equals(_formErrorPath) || pathInContext.equals(_formLoginPath));
259 }
260
261
262 public boolean secureResponse(ServletRequest req, ServletResponse res, boolean mandatory, User validatedUser) throws ServerAuthException
263 {
264 return true;
265 }
266
267
268
269 protected static class FormRequest extends HttpServletRequestWrapper
270 {
271 public FormRequest(HttpServletRequest request)
272 {
273 super(request);
274 }
275
276 @Override
277 public long getDateHeader(String name)
278 {
279 if (name.toLowerCase().startsWith("if-"))
280 return -1;
281 return super.getDateHeader(name);
282 }
283
284 @Override
285 public String getHeader(String name)
286 {
287 if (name.toLowerCase().startsWith("if-"))
288 return null;
289 return super.getHeader(name);
290 }
291
292 @Override
293 public Enumeration getHeaderNames()
294 {
295 return Collections.enumeration(Collections.list(super.getHeaderNames()));
296 }
297
298 @Override
299 public Enumeration getHeaders(String name)
300 {
301 if (name.toLowerCase().startsWith("if-"))
302 return Collections.enumeration(Collections.EMPTY_LIST);
303 return super.getHeaders(name);
304 }
305 }
306
307
308
309 protected static class FormResponse extends HttpServletResponseWrapper
310 {
311 public FormResponse(HttpServletResponse response)
312 {
313 super(response);
314 }
315
316 @Override
317 public void addDateHeader(String name, long date)
318 {
319 if (notIgnored(name))
320 super.addDateHeader(name,date);
321 }
322
323 @Override
324 public void addHeader(String name, String value)
325 {
326 if (notIgnored(name))
327 super.addHeader(name,value);
328 }
329
330 @Override
331 public void setDateHeader(String name, long date)
332 {
333 if (notIgnored(name))
334 super.setDateHeader(name,date);
335 }
336
337 @Override
338 public void setHeader(String name, String value)
339 {
340 if (notIgnored(name))
341 super.setHeader(name,value);
342 }
343
344 private boolean notIgnored(String name)
345 {
346 if (HttpHeaders.CACHE_CONTROL.equalsIgnoreCase(name) ||
347 HttpHeaders.PRAGMA.equalsIgnoreCase(name) ||
348 HttpHeaders.ETAG.equalsIgnoreCase(name) ||
349 HttpHeaders.EXPIRES.equalsIgnoreCase(name) ||
350 HttpHeaders.LAST_MODIFIED.equalsIgnoreCase(name) ||
351 HttpHeaders.AGE.equalsIgnoreCase(name))
352 return false;
353 return true;
354 }
355 }
356
357 public static class FormAuthentication extends UserAuthentication implements Authentication.ResponseSent
358 {
359 public FormAuthentication(Authenticator authenticator, UserIdentity userIdentity)
360 {
361 super(authenticator,userIdentity);
362 }
363
364 public String toString()
365 {
366 return "Form"+super.toString();
367 }
368 }
369 }