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