1 package com.atlassian.seraph.auth;
2
3 import java.io.IOException;
4 import java.security.Principal;
5 import java.util.Iterator;
6 import java.util.List;
7 import java.util.Map;
8
9 import javax.servlet.http.Cookie;
10 import javax.servlet.http.HttpServletRequest;
11 import javax.servlet.http.HttpServletResponse;
12
13 import org.apache.log4j.Logger;
14
15 import com.atlassian.seraph.config.SecurityConfig;
16 import com.atlassian.seraph.config.SecurityConfigFactory;
17 import com.atlassian.seraph.cookie.CookieFactory;
18 import com.atlassian.seraph.cookie.CookieHandler;
19 import com.atlassian.seraph.interceptor.LogoutInterceptor;
20 import com.atlassian.seraph.util.RedirectUtils;
21 import com.opensymphony.user.EntityNotFoundException;
22 import com.opensymphony.user.User;
23 import com.opensymphony.user.UserManager;
24 import com.opensymphony.user.provider.ejb.util.Base64;
25
26
27
28
29
30
31 public class DefaultAuthenticator extends AbstractAuthenticator
32 {
33
34
35
36 public static final String LOGGED_IN_KEY = "seraph_defaultauthenticator_user";
37
38
39
40
41
42 public static final String LOGGED_OUT_KEY = "seraph_defaultauthenticator_logged_out_user";
43
44 private static final Logger log = Logger.getLogger(DefaultAuthenticator.class);
45
46
47
48 private String loginCookieKey;
49 private String authType;
50 private int autoLoginCookieAge;
51 private String loginCookiePath;
52
53 public void init(Map params, SecurityConfig config)
54 {
55 if (log.isDebugEnabled())
56 {
57 log.debug(this.getClass().getName() + " $Revision: 16581 $ initializing");
58 }
59 super.init(params, config);
60 this.loginCookieKey = config.getLoginCookieKey();
61 this.authType = config.getAuthType();
62 this.autoLoginCookieAge = config.getAutoLoginCookieAge();
63 this.loginCookiePath = config.getLoginCookiePath();
64 }
65
66
67
68
69 public boolean isUserInRole(HttpServletRequest request, String role)
70 {
71 return getRoleMapper().hasRole(getUser(request), request, role);
72 }
73
74
75
76
77
78
79
80
81 public boolean login(HttpServletRequest request, HttpServletResponse response, String username, String password, boolean cookie)
82 throws AuthenticatorException
83 {
84 final boolean dbg = log.isDebugEnabled();
85 final Principal user = getUser(username);
86 CookieHandler cookieHandler = CookieFactory.getCookieHandler();
87
88
89 if (user == null)
90 {
91 log.info("Cannot login user '" + username + "' as they do not exist.");
92 }
93 else
94 {
95 boolean authenticated = authenticate(user, password);
96 if (dbg)
97 {
98 log.debug("User : " + username + " has " + (authenticated ? "been" : "no been") + " authenticated");
99 }
100 if (authenticated)
101 {
102 request.getSession().setAttribute(LOGGED_IN_KEY, user);
103 request.getSession().setAttribute(LOGGED_OUT_KEY, null);
104
105 final boolean canLogin = getRoleMapper().canLogin(user, request);
106 if (dbg)
107 {
108 log.debug("User : " + username + " " + (canLogin ? "can" : "CANT") + " login according to the RoleMapper");
109 }
110 if (canLogin)
111 {
112 if (cookie && response != null)
113 {
114 cookieHandler.setCookie(request, response, getLoginCookieKey(), encodeCookie(username, password), autoLoginCookieAge, getCookiePath(request));
115 }
116 return true;
117 }
118 else
119 {
120 request.getSession().removeAttribute(LOGGED_IN_KEY);
121 }
122 }
123 else
124 {
125 log.info("Cannot login user '" + username + "' as they used an incorrect password");
126 }
127 }
128
129 if (response != null && cookieHandler.getCookie(request, getLoginCookieKey()) != null)
130 {
131 log.warn("User: " + username + " tried to login but they do not have USE permission or weren't found. Deleting cookie.");
132
133 try
134 {
135 cookieHandler.invalidateCookie(request, response, getLoginCookieKey(), getCookiePath(request));
136 }
137 catch (Exception e)
138 {
139 log.error("Could not invalidate cookie: " + e, e);
140 }
141 }
142
143 return false;
144 }
145
146
147
148 protected RoleMapper getRoleMapper()
149 {
150 return SecurityConfigFactory.getInstance().getRoleMapper();
151 }
152
153
154
155
156
157
158 protected Principal getUser(String username)
159 {
160 if (log.isDebugEnabled())
161 {
162 log.debug("Looking in UserManager for user : " + username);
163 }
164 try
165 {
166 return UserManager.getInstance().getUser(username);
167 }
168 catch (EntityNotFoundException e)
169 {
170 log.warn("Could not find user : " + username + " in UserManager : " + e);
171 }
172 return null;
173 }
174
175
176
177
178 protected boolean authenticate(Principal user, String password)
179 {
180 return ((User) user).authenticate(password);
181 }
182
183 public boolean logout(HttpServletRequest request, HttpServletResponse response) throws AuthenticatorException
184 {
185 boolean dbg = log.isDebugEnabled();
186 if (dbg)
187 {
188 log.debug("logout requested. Calling interceptors and clearing cookies");
189 }
190 List interceptors = getLogoutInterceptors();
191 CookieHandler cookieHandler = CookieFactory.getCookieHandler();
192
193 for (Iterator iterator = interceptors.iterator(); iterator.hasNext();)
194 {
195 LogoutInterceptor interceptor = (LogoutInterceptor) iterator.next();
196 interceptor.beforeLogout(request, response);
197 }
198
199 request.getSession().setAttribute(LOGGED_IN_KEY, null);
200 request.getSession().setAttribute(LOGGED_OUT_KEY, Boolean.TRUE);
201
202
203
204 if (response != null && cookieHandler.getCookie(request, getLoginCookieKey()) != null)
205 {
206 try
207 {
208 cookieHandler.invalidateCookie(request, response, getLoginCookieKey(), getCookiePath(request));
209 }
210 catch (Exception e)
211 {
212 log.error("Could not invalidate cookie: " + e, e);
213 }
214 }
215
216 for (Iterator iterator = interceptors.iterator(); iterator.hasNext();)
217 {
218 LogoutInterceptor interceptor = (LogoutInterceptor) iterator.next();
219 interceptor.afterLogout(request, response);
220 }
221
222 return true;
223 }
224
225
226
227
228
229
230
231
232
233
234
235
236
237 public Principal getUser(HttpServletRequest request, HttpServletResponse response)
238 {
239 final boolean dbg = log.isDebugEnabled();
240 if (request.getSession(false) != null)
241 {
242 Principal sessionUser = getUserFromSession(request);
243 if (sessionUser != null)
244 {
245 if (dbg)
246 {
247 log.debug("Session found; BUT user doesn't exist");
248 }
249 return sessionUser;
250 }
251 }
252 else
253 {
254 Principal cookieUser = getUserFromCookie(request, response);
255 if (cookieUser != null) return cookieUser;
256 log.debug("Cannot log user in via a cookie");
257 }
258
259 if (RedirectUtils.isBasicAuthentication(request, authType))
260 {
261 Principal basicAuthUser = getUserFromBasicAuthentication(request, response);
262 if (basicAuthUser != null) return basicAuthUser;
263 }
264
265 if (dbg)
266 {
267 log.debug("User not logged in.");
268 }
269
270 return null;
271 }
272
273
274
275
276
277
278
279 protected Principal getUserFromCookie(HttpServletRequest request, HttpServletResponse response)
280 {
281 final boolean dbg = log.isDebugEnabled();
282 final String cookieName = getLoginCookieKey();
283 final Cookie cookie = CookieFactory.getCookieHandler().getCookie(request, cookieName);
284 if (cookie == null)
285 {
286 return null;
287 }
288
289 final String cookieValue = cookie.getValue();
290 if (dbg)
291 {
292 log.debug("Found cookie : '" + cookieName + "' with value : '" + cookieValue + "'");
293 }
294 final String[] values = decodeCookie(cookieValue);
295 if (values == null)
296 {
297 if (dbg)
298 {
299 log.debug("Unable to decode " + cookieName + " cookie with value : '" + cookieValue + "'");
300 }
301 return null;
302 }
303
304 final String username = values[0];
305 final String password = values[1];
306 if (dbg)
307 {
308 log.debug("Got username : '" + username + "' and password from cookie, attempting to authenticate user");
309 }
310
311 try
312 {
313 if (!login(request, response, username, password, false))
314 {
315 return null;
316 }
317 }
318 catch (Exception e)
319 {
320 log.warn("Cookie login for user : '" + username + "' failed with exception: " + e, e);
321 return null;
322 }
323
324 if (dbg)
325 {
326 log.debug("Logged user : '" + username + "' in via a cookie");
327 }
328 return getUserFromSession(request);
329 }
330
331
332
333
334
335
336
337
338
339
340 protected Principal getUserFromSession(HttpServletRequest request)
341 {
342 final boolean dbg = log.isDebugEnabled();
343 try
344 {
345 if (request.getSession().getAttribute(LOGGED_OUT_KEY) != null)
346 {
347 if (dbg)
348 {
349 log.debug("Session found; user has already logged out");
350 }
351 return null;
352 }
353 if (request.getSession().getAttribute(LOGGED_IN_KEY) == null)
354 {
355 return null;
356 }
357 final Principal principal = (Principal) request.getSession().getAttribute(LOGGED_IN_KEY);
358 if (dbg)
359 {
360 if (principal == null)
361 {
362 log.debug("Session found; BUT it has no Principal in it");
363 }
364 else
365 {
366 log.debug("Session found; user : '" + principal.getName() + "' already logged in");
367 }
368 }
369 return principal;
370 }
371 catch (Exception e)
372 {
373 log.warn("Exception when retrieving user from session: " + e, e);
374 return null;
375 }
376 }
377
378
379
380
381
382
383
384
385 protected Principal getUserFromBasicAuthentication(HttpServletRequest request, HttpServletResponse response)
386 {
387 final boolean dbg = log.isDebugEnabled();
388 String header = request.getHeader("Authorization");
389
390 if (header != null && header.startsWith("Basic "))
391 {
392 if (dbg)
393 {
394 log.debug("Looking in Basic Auth headers");
395 }
396 String base64Token = header.substring(6);
397 String token = new String(Base64.decode(base64Token.getBytes()));
398
399 String username = "";
400 String password = "";
401
402 int delim = token.indexOf(":");
403
404 if (delim != -1)
405 {
406 username = token.substring(0, delim);
407 password = token.substring(delim + 1);
408 }
409
410 try
411 {
412 if (login(request, response, username, password, false))
413 {
414 if (dbg)
415 {
416 log.debug("Logged in user : '" + username + "' via basic auth");
417 }
418 return getUser(username);
419 }
420 }
421 catch (AuthenticatorException e)
422 {
423 log.warn("Exception trying to login user : '" + username + "' via basic auth:" + e, e);
424 }
425 try
426 {
427 response.sendError(401);
428 }
429 catch (IOException e)
430 {
431 log.warn("Exception trying to send basic auth failed error: " + e, e);
432 }
433 return null;
434 }
435
436 if (response == null)
437 {
438 return null;
439 }
440
441 response.setStatus(401);
442 response.setHeader("WWW-Authenticate", "BASIC realm=\"protected-area\"");
443 return null;
444 }
445
446
447
448
449
450 protected String getCookiePath(HttpServletRequest request)
451 {
452 if (getLoginCookiePath() != null)
453 return getLoginCookiePath();
454
455 String path = request.getContextPath();
456 if (path == null || path.equals(""))
457 {
458 return "/";
459 }
460
461
462 if (!path.startsWith("/"))
463 {
464 return "/" + path;
465 }
466
467 return path;
468 }
469
470 protected String getLoginCookieKey()
471 {
472 return loginCookieKey;
473 }
474
475 public String getAuthType()
476 {
477 return authType;
478 }
479
480 protected List getLogoutInterceptors()
481 {
482 return getConfig().getInterceptors(LogoutInterceptor.class);
483 }
484
485 protected String encodeCookie(final String username, final String password)
486 {
487 return CookieFactory.getCookieEncoder().encodePasswordCookie(username, password, getConfig().getCookieEncoding());
488 }
489
490 protected String[] decodeCookie(final String value)
491 {
492 return CookieFactory.getCookieEncoder().decodePasswordCookie(value, getConfig().getCookieEncoding());
493 }
494
495 protected String getLoginCookiePath()
496 {
497 return loginCookiePath;
498 }
499 }