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