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 user = getUser(userName);
87
88 if (user == null)
89 {
90 log.info(METHOD + "'" + userName + "' does not exist and cannot be authenticated.");
91 }
92 else
93 {
94 final boolean authenticated = authenticate(user, password);
95 if (dbg)
96 {
97 log.debug(METHOD + "'" + userName + "' has " + (authenticated ? "been" : "not been") + " authenticated");
98 }
99 if (authenticated)
100 {
101 if (authoriseUserAndEstablishSession(httpServletRequest, httpServletResponse, user))
102 {
103 if (setRememberMeCookie && httpServletResponse != null)
104 {
105 getRememberMeService().addRememberMeCookie(httpServletRequest, httpServletResponse, userName);
106 }
107 return true;
108 }
109 AUTHORISATION_FAILED.stampRequestResponse(httpServletRequest, httpServletResponse);
110 }
111 else
112 {
113 log.info(METHOD + "'" + userName + "' could not be authenticated with the given password");
114 }
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 protected abstract boolean authenticate(final Principal user, final String password) throws AuthenticatorException;
298
299
300
301
302
303
304
305
306
307
308 @Override
309 public Principal getUser(final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse)
310 {
311 final String METHOD = "getUser : ";
312 final boolean dbg = log.isDebugEnabled();
313
314 if (httpServletRequest.getSession(false) != null)
315 {
316 final Principal sessionUser = getUserFromSession(httpServletRequest);
317 if (sessionUser != null)
318 {
319 OK.stampRequestResponse(httpServletRequest, httpServletResponse);
320 return sessionUser;
321 }
322 }
323 else
324 {
325 final Principal cookieUser = getUserFromCookie(httpServletRequest, httpServletResponse);
326 if (cookieUser != null)
327 {
328 return cookieUser;
329 }
330 }
331
332 if (RedirectUtils.isBasicAuthentication(httpServletRequest, basicAuthParameterName))
333 {
334 final Principal basicAuthUser = getUserFromBasicAuthentication(httpServletRequest, httpServletResponse);
335 if (basicAuthUser != null)
336 {
337 return basicAuthUser;
338 }
339 }
340
341 if (dbg)
342 {
343 log.debug(METHOD + "User not found in either Session, Cookie or Basic Auth.");
344 }
345
346 return null;
347 }
348
349
350
351
352
353
354
355
356 protected Principal getUserFromSession(final HttpServletRequest httpServletRequest)
357 {
358 final String METHOD = "getUserFromSession : ";
359 final boolean dbg = log.isDebugEnabled();
360 try
361 {
362 if (httpServletRequest.getSession().getAttribute(LOGGED_OUT_KEY) != null)
363 {
364 if (dbg)
365 {
366 log.debug(METHOD + "Session found; user has already logged out. eg has LOGGED_OUT_KEY in session");
367 }
368 return null;
369 }
370 final Principal principal = (Principal) httpServletRequest.getSession().getAttribute(LOGGED_IN_KEY);
371 if (dbg)
372 {
373 if (principal == null)
374 {
375 log.debug(METHOD + "Session found; BUT it has no Principal in it");
376 }
377 else
378 {
379 log.debug(METHOD + "Session found; '" + principal.getName() + "' is present");
380 }
381 }
382 return principal;
383 }
384 catch (final Exception e)
385 {
386 log.warn(METHOD + "Exception when retrieving user from session: " + e, e);
387 return null;
388 }
389 }
390
391
392
393
394
395
396
397
398
399 protected Principal getUserFromCookie(final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse)
400 {
401 final String METHOD = "getUserFromCookie : ";
402 final boolean dbg = log.isDebugEnabled();
403
404
405 final String userName = getRememberMeService().getRememberMeCookieAuthenticatedUsername(httpServletRequest, httpServletResponse);
406 if (dbg)
407 {
408 log.debug(METHOD + "Got username : '" + userName + "' from cookie, attempting to authenticate user is known");
409 }
410 if (StringUtils.isNotBlank(userName))
411 {
412
413
414
415 final Principal principal = getUser(userName);
416 if (principal != null)
417 {
418
419 final ElevatedSecurityGuard securityGuard = getElevatedSecurityGuard();
420 if (!securityGuard.performElevatedSecurityCheck(httpServletRequest, userName))
421 {
422 if (dbg)
423 {
424 log.debug(METHOD + "'" + userName + "' failed elevated security check");
425 }
426 AUTHENTICATION_DENIED.stampRequestResponse(httpServletRequest, httpServletResponse);
427 securityGuard.onFailedLoginAttempt(httpServletRequest, userName);
428 return null;
429 }
430
431
432
433
434
435
436
437
438 if (authoriseUserAndEstablishSession(httpServletRequest, httpServletResponse, principal))
439 {
440 if (dbg)
441 {
442 log.debug(METHOD + "Authenticated '" + userName + "' via Remember Me Cookie");
443 }
444 OK.stampRequestResponse(httpServletRequest, httpServletResponse);
445 securityGuard.onSuccessfulLoginAttempt(httpServletRequest, userName);
446 return principal;
447 }
448 if (dbg)
449 {
450 log.debug(METHOD + "'" + userName + "' failed authorisation security check");
451 }
452 AUTHORISATION_FAILED.stampRequestResponse(httpServletRequest, httpServletResponse);
453 securityGuard.onFailedLoginAttempt(httpServletRequest, userName);
454 }
455 }
456 return null;
457 }
458
459
460
461
462
463
464
465
466
467
468 protected Principal getUserFromBasicAuthentication(final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse)
469 {
470 final String METHOD = "getUserFromSession : ";
471 final boolean dbg = log.isDebugEnabled();
472
473 final String header = httpServletRequest.getHeader("Authorization");
474 LoginReason reason = OK;
475
476 if (SecurityUtils.isBasicAuthorizationHeader(header))
477 {
478 if (dbg)
479 {
480 log.debug(METHOD + "Looking in Basic Auth headers");
481 }
482
483 final SecurityUtils.UserPassCredentials creds = SecurityUtils.decodeBasicAuthorizationCredentials(header);
484 final ElevatedSecurityGuard securityGuard = getElevatedSecurityGuard();
485 if (!securityGuard.performElevatedSecurityCheck(httpServletRequest, creds.getUsername()))
486 {
487 if (dbg)
488 {
489 log.debug(METHOD + "'" + creds.getUsername() + "' failed elevated security check");
490 }
491 reason = AUTHENTICATION_DENIED.stampRequestResponse(httpServletRequest, httpServletResponse);
492 securityGuard.onFailedLoginAttempt(httpServletRequest, creds.getUsername());
493 }
494 else
495 {
496 if (dbg)
497 {
498 log.debug(METHOD + "'" + creds.getUsername() + "' does not require elevated security check. Attempting authentication...");
499 }
500
501 try
502 {
503 final boolean loggedin = login(httpServletRequest, httpServletResponse, creds.getUsername(),
504 creds.getPassword(), false);
505 if (loggedin)
506 {
507 reason = OK.stampRequestResponse(httpServletRequest, httpServletResponse);
508 securityGuard.onSuccessfulLoginAttempt(httpServletRequest, creds.getUsername());
509 if (dbg)
510 {
511 log.debug(METHOD + "Authenticated '" + creds.getUsername() + "' via Basic Auth");
512 }
513 return getUser(creds.getUsername());
514 }
515 else
516 {
517 reason = AUTHENTICATED_FAILED.stampRequestResponse(httpServletRequest, httpServletResponse);
518 securityGuard.onFailedLoginAttempt(httpServletRequest, creds.getUsername());
519 }
520 }
521 catch (final AuthenticatorException e)
522 {
523 log.warn(METHOD + "Exception trying to login '" + creds.getUsername() + "' via Basic Auth:" + e, e);
524 }
525 }
526 try
527 {
528 httpServletResponse.sendError(401, "Basic Authentication Failure - Reason : " + reason.toString());
529 }
530 catch (final IOException e)
531 {
532 log.warn(METHOD + "Exception trying to send Basic Auth failed error: " + e, e);
533 }
534 return null;
535 }
536
537 httpServletResponse.setStatus(401);
538 httpServletResponse.setHeader("WWW-Authenticate", "Basic realm=\"protected-area\"");
539 return null;
540 }
541
542 public String getAuthType()
543 {
544 return basicAuthParameterName;
545 }
546
547 protected List<LogoutInterceptor> getLogoutInterceptors()
548 {
549 return getConfig().getInterceptors(LogoutInterceptor.class);
550 }
551
552 protected ElevatedSecurityGuard getElevatedSecurityGuard()
553 {
554 return getConfig().getElevatedSecurityGuard();
555 }
556
557 protected RememberMeService getRememberMeService()
558 {
559 return getConfig().getRememberMeService();
560 }
561
562 private void invalidateSession(HttpServletRequest httpServletRequest)
563 {
564 SessionInvalidator si = new SessionInvalidator(getConfig().getInvalidateSessionExcludeList());
565 si.invalidateSession(httpServletRequest);
566 }
567
568 }