1 package com.atlassian.seraph.auth;
2
3 import static com.atlassian.seraph.auth.LoginReason.AUTHENTICATED_FAILED;
4 import static com.atlassian.seraph.auth.LoginReason.AUTHENTICATION_DENIED;
5 import static com.atlassian.seraph.auth.LoginReason.AUTHORISATION_FAILED;
6 import static com.atlassian.seraph.auth.LoginReason.OK;
7 import static com.atlassian.seraph.auth.LoginReason.OUT;
8 import com.atlassian.seraph.config.SecurityConfig;
9 import com.atlassian.seraph.config.SecurityConfigFactory;
10 import com.atlassian.seraph.elevatedsecurity.ElevatedSecurityGuard;
11 import com.atlassian.seraph.interceptor.LogoutInterceptor;
12 import com.atlassian.seraph.service.rememberme.RememberMeService;
13 import com.atlassian.seraph.util.RedirectUtils;
14 import com.opensymphony.user.EntityNotFoundException;
15 import com.opensymphony.user.User;
16 import com.opensymphony.user.UserManager;
17 import com.opensymphony.user.provider.ejb.util.Base64;
18 import org.apache.commons.lang.StringUtils;
19 import org.apache.log4j.Logger;
20
21 import java.io.IOException;
22 import java.security.Principal;
23 import java.util.List;
24 import java.util.Map;
25 import javax.servlet.http.HttpServletRequest;
26 import javax.servlet.http.HttpServletResponse;
27 import javax.servlet.http.HttpSession;
28
29
30
31
32
33
34 public class DefaultAuthenticator extends AbstractAuthenticator
35 {
36
37
38
39 public static final String LOGGED_IN_KEY = "seraph_defaultauthenticator_user";
40
41
42
43
44
45 public static final String LOGGED_OUT_KEY = "seraph_defaultauthenticator_logged_out_user";
46
47 private static final Logger log = Logger.getLogger(DefaultAuthenticator.class);
48
49
50
51 private String basicAuthParameterName;
52
53 @Override
54 public void init(final Map<String, String> params, final SecurityConfig config)
55 {
56 if (log.isDebugEnabled())
57 {
58 log.debug(this.getClass().getName() + " $Revision: 39412 $ initializing");
59 }
60 super.init(params, config);
61 basicAuthParameterName = config.getAuthType();
62 }
63
64
65
66
67 @Deprecated
68 @Override
69 public boolean isUserInRole(final HttpServletRequest request, final String role)
70 {
71 return getRoleMapper().hasRole(getUser(request), request, role);
72 }
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89 @Override
90 public boolean login(final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse, final String userName, final String password, final boolean setRememberMeCookie)
91 throws AuthenticatorException
92 {
93 final String METHOD = "login : ";
94 final boolean dbg = log.isDebugEnabled();
95
96 final Principal user = getUser(userName);
97
98 if (user == null)
99 {
100 log.info(METHOD + "'" + userName + "' does not exist and cannot be authenticated.");
101 }
102 else
103 {
104 final boolean authenticated = authenticate(user, password);
105 if (dbg)
106 {
107 log.debug(METHOD + "'" + userName + "' has " + (authenticated ? "been" : "not been") + " authenticated");
108 }
109 if (authenticated)
110 {
111 if (authoriseUserAndEstablishSession(httpServletRequest, httpServletResponse, user))
112 {
113 if (setRememberMeCookie && httpServletResponse != null)
114 {
115 getRememberMeService().addRememberMeCookie(httpServletRequest, httpServletResponse, userName);
116 }
117 return true;
118 }
119 AUTHORISATION_FAILED.stampRequestResponse(httpServletRequest, httpServletResponse);
120 }
121 else
122 {
123 log.info(METHOD + "'" + userName + "' could not be authenticated with the given password");
124 }
125 }
126
127 if ((httpServletResponse != null))
128 {
129 log.warn(METHOD + "'" + userName + "' tried to login but they do not have USE permission or weren't found. Deleting remember me cookie.");
130
131 getRememberMeService().removeRememberMeCookie(httpServletRequest, httpServletResponse);
132 }
133
134 return false;
135 }
136
137
138
139
140
141
142
143
144
145
146
147
148 @Override
149 public boolean logout(final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse)
150 throws AuthenticatorException
151 {
152 final String METHOD = "logout : ";
153 final boolean dbg = log.isDebugEnabled();
154 if (dbg)
155 {
156 log.debug(METHOD + "Calling interceptors and clearing remember me cookie");
157 }
158 final List<LogoutInterceptor> interceptors = getLogoutInterceptors();
159
160 for (final LogoutInterceptor interceptor : interceptors)
161 {
162 interceptor.beforeLogout(httpServletRequest, httpServletResponse);
163 }
164
165 removePrincipalFromSessionContext(httpServletRequest);
166
167 OUT.stampRequestResponse(httpServletRequest, httpServletResponse);
168
169
170
171 if (httpServletResponse != null)
172 {
173 getRememberMeService().removeRememberMeCookie(httpServletRequest, httpServletResponse);
174 }
175
176 for (final Object element : interceptors)
177 {
178 final LogoutInterceptor interceptor = (LogoutInterceptor) element;
179 interceptor.afterLogout(httpServletRequest, httpServletResponse);
180 }
181
182 return true;
183 }
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198 protected boolean authoriseUserAndEstablishSession(final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse, final Principal principal)
199 {
200 final String METHOD = "authoriseUser : ";
201 final boolean dbg = log.isDebugEnabled();
202
203 final String userName = principal.getName();
204
205
206 putPrincipalInSessionContext(httpServletRequest, null);
207
208 final boolean canLogin = isAuthorised(httpServletRequest, principal);
209 if (dbg)
210 {
211 log.debug(METHOD + "'" + userName + "' " + (canLogin ? "can" : "CANT") + " login according to the RoleMapper");
212 }
213 if (canLogin)
214 {
215 putPrincipalInSessionContext(httpServletRequest, principal);
216 return true;
217 }
218 return false;
219 }
220
221
222
223
224
225
226
227
228
229 protected boolean isAuthorised(final HttpServletRequest httpServletRequest, final Principal principal)
230 {
231 return getRoleMapper().canLogin(principal, httpServletRequest);
232 }
233
234
235
236
237
238
239
240 protected void putPrincipalInSessionContext(final HttpServletRequest httpServletRequest, final Principal principal)
241 {
242 final HttpSession httpSession = httpServletRequest.getSession();
243 httpSession.setAttribute(LOGGED_IN_KEY, principal);
244 httpSession.setAttribute(LOGGED_OUT_KEY, null);
245 }
246
247 protected void removePrincipalFromSessionContext(final HttpServletRequest httpServletRequest)
248 {
249 final HttpSession httpSession = httpServletRequest.getSession();
250 if (httpSession != null)
251 {
252 httpServletRequest.getSession().setAttribute(LOGGED_IN_KEY, null);
253 httpServletRequest.getSession().setAttribute(LOGGED_OUT_KEY, Boolean.TRUE);
254 }
255 }
256
257
258
259
260
261
262
263 protected RoleMapper getRoleMapper()
264 {
265 return SecurityConfigFactory.getInstance().getRoleMapper();
266 }
267
268
269
270
271
272
273
274
275
276
277 protected Principal getUser(final String username)
278 {
279 final String METHOD = "getUser : ";
280 if (log.isDebugEnabled())
281 {
282 log.debug(METHOD + "Looking in UserManager for '" + username + "'");
283 }
284 try
285 {
286 return UserManager.getInstance().getUser(username);
287 }
288 catch (final EntityNotFoundException e)
289 {
290 log.warn(METHOD + "Could not find user '" + username + "' in UserManager : " + e);
291 }
292 return null;
293 }
294
295
296
297
298
299
300
301
302
303 protected boolean authenticate(final Principal user, final String password)
304 {
305 return ((User) user).authenticate(password);
306 }
307
308
309
310
311
312
313
314
315
316
317
318 @Override
319 public Principal getUser(final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse)
320 {
321 final String METHOD = "getUser : ";
322 final boolean dbg = log.isDebugEnabled();
323
324 if (httpServletRequest.getSession(false) != null)
325 {
326 final Principal sessionUser = getUserFromSession(httpServletRequest);
327 if (sessionUser != null)
328 {
329 OK.stampRequestResponse(httpServletRequest, httpServletResponse);
330 return sessionUser;
331 }
332 }
333 else
334 {
335 final Principal cookieUser = getUserFromCookie(httpServletRequest, httpServletResponse);
336 if (cookieUser != null)
337 {
338 return cookieUser;
339 }
340 }
341
342 if (RedirectUtils.isBasicAuthentication(httpServletRequest, basicAuthParameterName))
343 {
344 final Principal basicAuthUser = getUserFromBasicAuthentication(httpServletRequest, httpServletResponse);
345 if (basicAuthUser != null)
346 {
347 return basicAuthUser;
348 }
349 }
350
351 if (dbg)
352 {
353 log.debug(METHOD + "User not found in either Session, Cookie or Basic Auth.");
354 }
355
356 return null;
357 }
358
359
360
361
362
363
364
365
366
367 protected Principal getUserFromSession(final HttpServletRequest httpServletRequest)
368 {
369 final String METHOD = "getUserFromSession : ";
370 final boolean dbg = log.isDebugEnabled();
371 try
372 {
373 if (httpServletRequest.getSession().getAttribute(LOGGED_OUT_KEY) != null)
374 {
375 if (dbg)
376 {
377 log.debug(METHOD + "Session found; user has already logged out. eg has LOGGED_OUT_KEY in session");
378 }
379 return null;
380 }
381 final Principal principal = (Principal) httpServletRequest.getSession().getAttribute(LOGGED_IN_KEY);
382 if (dbg)
383 {
384 if (principal == null)
385 {
386 log.debug(METHOD + "Session found; BUT it has no Principal in it");
387 }
388 else
389 {
390 log.debug(METHOD + "Session found; '" + principal.getName() + "' is present");
391 }
392 }
393 return principal;
394 }
395 catch (final Exception e)
396 {
397 log.warn(METHOD + "Exception when retrieving user from session: " + e, e);
398 return null;
399 }
400 }
401
402
403
404
405
406
407
408
409
410
411 protected Principal getUserFromCookie(final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse)
412 {
413 final String METHOD = "getUserFromCookie : ";
414 final boolean dbg = log.isDebugEnabled();
415
416
417 final String userName = getRememberMeService().getRememberMeCookieAuthenticatedUsername(httpServletRequest, httpServletResponse);
418 if (dbg)
419 {
420 log.debug(METHOD + "Got username : '" + userName + "' from cookie, attempting to authenticate user is known");
421 }
422 if (StringUtils.isNotBlank(userName))
423 {
424
425
426
427 final Principal principal = getUser(userName);
428 if (principal != null)
429 {
430
431 final ElevatedSecurityGuard securityGuard = getElevatedSecurityGuard();
432 if (!securityGuard.performElevatedSecurityCheck(httpServletRequest, userName))
433 {
434 if (dbg)
435 {
436 log.debug(METHOD + "'" + userName + "' failed elevated security check");
437 }
438 AUTHENTICATION_DENIED.stampRequestResponse(httpServletRequest, httpServletResponse);
439 securityGuard.onFailedLoginAttempt(httpServletRequest, userName);
440 return null;
441 }
442
443
444
445
446
447
448
449
450 if (authoriseUserAndEstablishSession(httpServletRequest, httpServletResponse, principal))
451 {
452 if (dbg)
453 {
454 log.debug(METHOD + "Authenticated '" + userName + "' via Remember Me Cookie");
455 }
456 OK.stampRequestResponse(httpServletRequest, httpServletResponse);
457 securityGuard.onSuccessfulLoginAttempt(httpServletRequest, userName);
458 return principal;
459 }
460 if (dbg)
461 {
462 log.debug(METHOD + "'" + userName + "' failed authorisation security check");
463 }
464 AUTHORISATION_FAILED.stampRequestResponse(httpServletRequest, httpServletResponse);
465 securityGuard.onFailedLoginAttempt(httpServletRequest, userName);
466 }
467 }
468 return null;
469 }
470
471
472
473
474
475
476
477
478
479
480
481 protected Principal getUserFromBasicAuthentication(final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse)
482 {
483 final String METHOD = "getUserFromSession : ";
484 final boolean dbg = log.isDebugEnabled();
485
486 final String header = httpServletRequest.getHeader("Authorization");
487 LoginReason reason = OK;
488
489 if ((header != null) && header.startsWith("Basic "))
490 {
491 if (dbg)
492 {
493 log.debug(METHOD + "Looking in Basic Auth headers");
494 }
495 final String base64Token = header.substring(6);
496 final String token = new String(Base64.decode(base64Token.getBytes()));
497
498 String userName = "";
499 String password = "";
500
501 final int delim = token.indexOf(":");
502
503 if (delim != -1)
504 {
505 userName = token.substring(0, delim);
506 password = token.substring(delim + 1);
507 }
508
509 final ElevatedSecurityGuard securityGuard = getElevatedSecurityGuard();
510 if (!securityGuard.performElevatedSecurityCheck(httpServletRequest, userName))
511 {
512 if (dbg)
513 {
514 log.debug(METHOD + "'" + userName + "' failed elevated security check");
515 }
516 reason = AUTHENTICATION_DENIED.stampRequestResponse(httpServletRequest, httpServletResponse);
517 securityGuard.onFailedLoginAttempt(httpServletRequest, userName);
518 }
519 else
520 {
521 if (dbg)
522 {
523 log.debug(METHOD + "'" + userName + "' does not require elevated security check. Attempting authentication...");
524 }
525
526 try
527 {
528 final boolean loggedin = login(httpServletRequest, httpServletResponse, userName, password, false);
529 if (loggedin)
530 {
531 reason = OK.stampRequestResponse(httpServletRequest, httpServletResponse);
532 securityGuard.onSuccessfulLoginAttempt(httpServletRequest, userName);
533 if (dbg)
534 {
535 log.debug(METHOD + "Authenticated '" + userName + "' via Basic Auth");
536 }
537 return getUser(userName);
538 }
539 else
540 {
541 reason = AUTHENTICATED_FAILED.stampRequestResponse(httpServletRequest, httpServletResponse);
542 securityGuard.onFailedLoginAttempt(httpServletRequest, userName);
543 }
544 }
545 catch (final AuthenticatorException e)
546 {
547 log.warn(METHOD + "Exception trying to login '" + userName + "' via Basic Auth:" + e, e);
548 }
549 }
550 try
551 {
552 httpServletResponse.sendError(401, "Basic Authentication Failure - Reason : " + reason.toString());
553 }
554 catch (final IOException e)
555 {
556 log.warn(METHOD + "Exception trying to send Basic Auth failed error: " + e, e);
557 }
558 return null;
559 }
560
561 httpServletResponse.setStatus(401);
562 httpServletResponse.setHeader("WWW-Authenticate", "BASIC realm=\"protected-area\"");
563 return null;
564 }
565
566 public String getAuthType()
567 {
568 return basicAuthParameterName;
569 }
570
571 protected List<LogoutInterceptor> getLogoutInterceptors()
572 {
573 return getConfig().getInterceptors(LogoutInterceptor.class);
574 }
575
576 protected ElevatedSecurityGuard getElevatedSecurityGuard()
577 {
578 return getConfig().getElevatedSecurityGuard();
579 }
580
581 protected RememberMeService getRememberMeService()
582 {
583 return getConfig().getRememberMeService();
584 }
585
586 }