1 package com.atlassian.seraph.auth;
2
3 import com.atlassian.seraph.config.ConfigurationException;
4 import com.atlassian.seraph.config.SecurityConfigFactory;
5 import com.atlassian.seraph.config.SecurityConfigImpl;
6 import com.atlassian.seraph.cookie.InsecureCookieEncoder;
7 import com.atlassian.seraph.elevatedsecurity.CountingElevatedSecurityGuard;
8 import com.atlassian.seraph.interceptor.Interceptor;
9 import com.atlassian.seraph.interceptor.LogoutInterceptor;
10 import com.mockobjects.dynamic.C;
11 import com.mockobjects.dynamic.Mock;
12 import com.opensymphony.user.provider.ejb.util.Base64;
13 import junit.framework.TestCase;
14
15 import java.security.Principal;
16 import javax.servlet.http.Cookie;
17 import javax.servlet.http.HttpServletRequest;
18 import javax.servlet.http.HttpServletResponse;
19 import javax.servlet.http.HttpSession;
20
21 public class TestDefaultAuthenticator extends TestCase
22 {
23 private Mock request;
24 private Mock response;
25 private SecurityConfigImpl config;
26 private Authenticator auth;
27 private Mock session;
28 private Principal user;
29
30 protected void setUp() throws Exception
31 {
32 super.setUp();
33 request = new Mock(HttpServletRequest.class);
34 response = new Mock(HttpServletResponse.class);
35 session = new Mock(HttpSession.class);
36 SecurityConfigFactory.setSecurityConfig(null);
37 config = (SecurityConfigImpl) SecurityConfigFactory.getInstance("test-seraph-config.xml");
38 auth = config.getAuthenticator();
39 user = new Principal()
40 {
41 public String getName()
42 {
43 return "Test User";
44 }
45 };
46 }
47
48 public void testLogout() throws ConfigurationException, AuthenticatorException
49 {
50
51 final Mock logoutInterceptor = new Mock(LogoutInterceptor.class);
52
53
54 request.expectAndReturn("getSession", session.proxy());
55 request.expectAndReturn("getSession", session.proxy());
56 request.expectAndReturn("getContextPath", "");
57 request.expectAndReturn("isSecure", false);
58 request.expectAndReturn("getCookies", new Cookie[] { new Cookie(config.getLoginCookieKey(), null) });
59 response.expect("addCookie", C.ANY_ARGS);
60
61 mockOutLoginReason(LoginReason.OUT);
62
63 session.expect("setAttribute", C.args(C.eq(DefaultAuthenticator.LOGGED_IN_KEY), C.IS_NULL));
64 session.expect("setAttribute", C.args(C.eq(DefaultAuthenticator.LOGGED_OUT_KEY), C.eq(Boolean.TRUE)));
65
66 logoutInterceptor.expect("beforeLogout", C.ANY_ARGS);
67 logoutInterceptor.expect("afterLogout", C.ANY_ARGS);
68 config.addInterceptor((Interceptor) logoutInterceptor.proxy());
69
70
71 auth.logout((HttpServletRequest) request.proxy(), (HttpServletResponse) response.proxy());
72
73
74 request.verify();
75 response.verify();
76 session.verify();
77 logoutInterceptor.verify();
78 }
79
80 public void testLoginWithNoCustomCookiePath()
81 {
82 request.expectAndReturn("getContextPath", "/bar");
83 final DefaultAuthenticator dauth = (DefaultAuthenticator) auth;
84 assertEquals("/bar", dauth.getCookiePath((HttpServletRequest) request.proxy()));
85 }
86
87 public void testLoginWithCustomCookiePath()
88 {
89 SecurityConfigFactory.setSecurityConfig(null);
90 config = (SecurityConfigImpl) SecurityConfigFactory.getInstance("test-seraph-config-with-custom-cookie-path.xml");
91 final DefaultAuthenticator dauth = (DefaultAuthenticator) config.getAuthenticator();
92 assertEquals("/foo", dauth.getCookiePath((HttpServletRequest) request.proxy()));
93 }
94
95 public void testGetUserChecksSessionFirst()
96 {
97
98 request.matchAndReturn("getSession", C.ANY_ARGS, session.proxy());
99 session.matchAndReturn("getAttribute", C.args(C.eq(DefaultAuthenticator.LOGGED_OUT_KEY)), null);
100 session.matchAndReturn("getAttribute", C.args(C.eq(DefaultAuthenticator.LOGGED_IN_KEY)), user);
101
102 mockOutLoginReason(LoginReason.OK);
103
104 final Principal result = auth.getUser((HttpServletRequest) request.proxy(), (HttpServletResponse) response.proxy());
105 assertEquals(user, result);
106
107 request.verify();
108 response.verify();
109 session.verify();
110 }
111
112 private StubAuthenticator setupRememberMeCookieState(LoginReason loginReason)
113 {
114 request.matchAndReturn("getSession", C.IS_FALSE, null);
115 request.matchAndReturn("getSession", C.NO_ARGS, session.proxy());
116
117 mockOutLoginReason(loginReason);
118
119 final String cookieValue = new InsecureCookieEncoder().encodePasswordCookie("test", "test", config.getCookieEncoding());
120 request.expectAndReturn("getCookies", new Cookie[] { new Cookie(config.getLoginCookieKey(), cookieValue) });
121
122 session.matchAndReturn("getAttribute", C.args(C.eq(DefaultAuthenticator.LOGGED_OUT_KEY)), null);
123 session.matchAndReturn("getAttribute", C.args(C.eq(DefaultAuthenticator.LOGGED_IN_KEY)), user);
124 return (StubAuthenticator) auth;
125 }
126
127 public void testGetUserChecksCookieIfNoSession()
128 {
129 setupRememberMeCookieState(LoginReason.OK);
130
131 final Principal result = auth.getUser((HttpServletRequest) request.proxy(), (HttpServletResponse) response.proxy());
132 assertEquals(user, result);
133
134 request.verify();
135 response.verify();
136 session.verify();
137 }
138
139 public void testGetUserChecksCookieIfNoSession_ButFailsElevatedSecurity()
140 {
141 final StubAuthenticator stubAuthenticator = setupRememberMeCookieState(LoginReason.AUTHENTICATION_DENIED);
142
143
144 request.expectAndReturn("getQueryString", "p=v");
145 request.expectAndReturn("getHeader", "Authorization", null);
146
147 final CountingElevatedSecurityGuard securityGuard = new CountingElevatedSecurityGuard(false,"test");
148 stubAuthenticator.setElevatedSecurityGuard(securityGuard);
149
150 final Principal result = auth.getUser((HttpServletRequest) request.proxy(), (HttpServletResponse) response.proxy());
151 assertNull(result);
152
153 assertEquals(0, securityGuard.getSuccessCount());
154 assertEquals(1, securityGuard.getFailedCount());
155
156 request.verify();
157 response.verify();
158 session.verify();
159 }
160
161 public void testGetUserChecksCookieIfNoSession_PassesElevatedSecurity_ButFailsLogin()
162 {
163 final StubAuthenticator stubAuthenticator = setupRememberMeCookieState(LoginReason.AUTHENTICATED_FAILED);
164
165
166 request.expectAndReturn("getQueryString", "p=v");
167 request.expectAndReturn("getHeader", "Authorization", null);
168
169 final CountingElevatedSecurityGuard securityGuard = new CountingElevatedSecurityGuard(true,"test");
170 stubAuthenticator.setElevatedSecurityGuard(securityGuard);
171 stubAuthenticator.setDesiredLoginAnswer(false);
172
173 final Principal result = auth.getUser((HttpServletRequest) request.proxy(), (HttpServletResponse) response.proxy());
174 assertNull(result);
175
176 assertEquals(0, securityGuard.getSuccessCount());
177 assertEquals(1, securityGuard.getFailedCount());
178
179 request.verify();
180 response.verify();
181 session.verify();
182 }
183
184 public void testGetUserChecksCookieIfNoSession_PassesElevatedSecurity_AndPassesLogin()
185 {
186 final StubAuthenticator stubAuthenticator = setupRememberMeCookieState(LoginReason.OK);
187
188 final CountingElevatedSecurityGuard securityGuard = new CountingElevatedSecurityGuard(true,"test");
189 stubAuthenticator.setElevatedSecurityGuard(securityGuard);
190 stubAuthenticator.setDesiredLoginAnswer(true);
191
192 final Principal result = auth.getUser((HttpServletRequest) request.proxy(), (HttpServletResponse) response.proxy());
193 assertEquals(user, result);
194
195 assertEquals(1, securityGuard.getSuccessCount());
196 assertEquals(0, securityGuard.getFailedCount());
197
198 request.verify();
199 response.verify();
200 session.verify();
201 }
202
203 public void testGetUserReturnsNullWithNoValidAuthentication()
204 {
205 request.matchAndReturn("getSession", C.IS_FALSE, null);
206 request.expectAndReturn("getCookies", null);
207 request.expectAndReturn("getQueryString", null);
208 request.expectAndReturn("getHeader", C.args(C.eq("Authorization")), null);
209
210 final Principal result = auth.getUser((HttpServletRequest) request.proxy(), (HttpServletResponse) response.proxy());
211 assertEquals(null, result);
212
213 request.verify();
214 response.verify();
215 session.verify();
216 }
217
218 public void testGetUserBasicAuthRequiredButMissing()
219 {
220 request.matchAndReturn("getSession", C.IS_FALSE, null);
221 request.matchAndReturn("getCookies", null);
222 request.matchAndReturn("getQueryString", "os_authType=basic");
223
224
225 request.expectAndReturn("getHeader", C.eq("Authorization"), null);
226
227 response.expect("setStatus", C.eq(401));
228 response.expect("setHeader", C.eq("WWW-Authenticate", "BASIC realm=\"protected-area\""));
229
230 final Principal result = auth.getUser((HttpServletRequest) request.proxy(), (HttpServletResponse) response.proxy());
231 assertEquals(null, result);
232
233 request.verify();
234 response.verify();
235 session.verify();
236 }
237
238 private StubAuthenticator setupBasicAuthHttpState(LoginReason loginReason)
239 {
240 request.matchAndReturn("getSession", C.IS_FALSE, null);
241 request.matchAndReturn("getCookies", null);
242 request.matchAndReturn("getQueryString", "os_authType=basic");
243
244 mockOutLoginReason(loginReason);
245
246
247 final String token = new String(Base64.encode("username:password".getBytes()));
248 request.expectAndReturn("getHeader", C.eq("Authorization"), "Basic " + token);
249
250 final StubAuthenticator stubAuthenticator = (StubAuthenticator) auth;
251 stubAuthenticator.addUser("username", user);
252 return stubAuthenticator;
253 }
254
255 public void testGetUserBasicAuthProvidedUsingRequestParameter()
256 {
257 setupBasicAuthHttpState(LoginReason.OK);
258
259 final Principal result = auth.getUser((HttpServletRequest) request.proxy(), (HttpServletResponse) response.proxy());
260 assertEquals(user, result);
261
262 request.verify();
263 response.verify();
264 session.verify();
265 }
266
267 public void testGetUserBasicAuthProvidedUsingRequestParameter_ButFailsElevatedSecurity() throws ConfigurationException
268 {
269 final StubAuthenticator stubAuthenticator = setupBasicAuthHttpState(LoginReason.AUTHENTICATION_DENIED);
270
271 final CountingElevatedSecurityGuard securityGuard = new CountingElevatedSecurityGuard(false,"username");
272 stubAuthenticator.setElevatedSecurityGuard(securityGuard);
273
274
275 response.expect("sendError", C.args(C.eq(401), C.eq("Basic Authentication Failure - Reason : " + LoginReason.AUTHENTICATION_DENIED)));
276
277 final Principal result = auth.getUser((HttpServletRequest) request.proxy(), (HttpServletResponse) response.proxy());
278 assertNull(result);
279
280 assertEquals(0, securityGuard.getSuccessCount());
281 assertEquals(1, securityGuard.getFailedCount());
282
283 request.verify();
284 response.verify();
285 session.verify();
286 }
287
288 public void testGetUserBasicAuthProvidedUsingRequestParameter_PassesElevatedSecurity_ButFailsLogin() throws ConfigurationException
289 {
290 final StubAuthenticator stubAuthenticator = setupBasicAuthHttpState(LoginReason.AUTHENTICATED_FAILED);
291 stubAuthenticator.setDesiredLoginAnswer(false);
292
293 final CountingElevatedSecurityGuard securityGuard = new CountingElevatedSecurityGuard(true,"username");
294 stubAuthenticator.setElevatedSecurityGuard(securityGuard);
295
296
297 response.expect("sendError", C.args(C.eq(401), C.eq("Basic Authentication Failure - Reason : " + LoginReason.AUTHENTICATED_FAILED)));
298
299 final Principal result = auth.getUser((HttpServletRequest) request.proxy(), (HttpServletResponse) response.proxy());
300 assertNull(result);
301
302 assertEquals(0, securityGuard.getSuccessCount());
303 assertEquals(1, securityGuard.getFailedCount());
304
305 request.verify();
306 response.verify();
307 session.verify();
308 }
309
310 public void testGetUserBasicAuthProvidedUsingRequestParameter_PassesElevatedSecurity_AndPassesLogin() throws ConfigurationException
311 {
312 final StubAuthenticator stubAuthenticator = setupBasicAuthHttpState(LoginReason.OK);
313 stubAuthenticator.setDesiredLoginAnswer(true);
314
315 final CountingElevatedSecurityGuard securityGuard = new CountingElevatedSecurityGuard(true,"username");
316 stubAuthenticator.setElevatedSecurityGuard(securityGuard);
317
318 final Principal result = auth.getUser((HttpServletRequest) request.proxy(), (HttpServletResponse) response.proxy());
319 assertEquals(user, result);
320
321 assertEquals(1, securityGuard.getSuccessCount());
322 assertEquals(0, securityGuard.getFailedCount());
323
324 request.verify();
325 response.verify();
326 session.verify();
327 }
328
329 public void testGetUserBasicAuthProvidedUsingHeader()
330 {
331 final String authorizationHeader = "Basic " + new String(Base64.encode("username:password".getBytes()));
332
333 request.matchAndReturn("getSession", C.IS_FALSE, null);
334 request.matchAndReturn("getCookies", null);
335 request.matchAndReturn("getQueryString", null);
336
337 request.expectAndReturn("getHeader", C.eq("Authorization"), authorizationHeader);
338 request.expectAndReturn("getHeader", C.eq("Authorization"), authorizationHeader);
339
340 mockOutLoginReason(LoginReason.OK);
341
342
343 final StubAuthenticator stubAuthenticator = (StubAuthenticator) auth;
344 stubAuthenticator.addUser("username", user);
345
346 final CountingElevatedSecurityGuard securityGuard = new CountingElevatedSecurityGuard(true,"username");
347 stubAuthenticator.setElevatedSecurityGuard(securityGuard);
348
349 final Principal result = auth.getUser((HttpServletRequest) request.proxy(), (HttpServletResponse) response.proxy());
350 assertEquals(user, result);
351
352 assertEquals(1, securityGuard.getSuccessCount());
353 assertEquals(0, securityGuard.getFailedCount());
354
355 request.verify();
356 response.verify();
357 session.verify();
358 }
359
360 private void mockOutLoginReason(LoginReason loginReason)
361 {
362 request.expectAndReturn("getAttribute", C.args(C.eq("com.atlassian.seraph.auth.LoginReason")), null);
363 request.expect("setAttribute", C.args(C.eq("com.atlassian.seraph.auth.LoginReason"), C.eq(loginReason)));
364
365 response.expect("addHeader", C.ANY_ARGS);
366 }
367 }