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.elevatedsecurity.CountingElevatedSecurityGuard;
7 import com.atlassian.seraph.interceptor.Interceptor;
8 import com.atlassian.seraph.interceptor.LogoutInterceptor;
9 import com.atlassian.seraph.service.rememberme.RememberMeService;
10 import com.atlassian.seraph.util.CharsetUtils;
11 import com.atlassian.seraph.util.SecurityUtils;
12 import com.mockobjects.dynamic.C;
13 import com.mockobjects.dynamic.Mock;
14 import junit.framework.TestCase;
15
16 import javax.servlet.http.HttpServletRequest;
17 import javax.servlet.http.HttpServletResponse;
18 import javax.servlet.http.HttpSession;
19 import java.security.Principal;
20
21 import static org.mockito.Mockito.mock;
22 import static org.mockito.Mockito.when;
23
24
25
26
27
28
29
30
31 public class TestDefaultAuthenticator extends TestCase
32 {
33 private Mock request;
34 private Mock response;
35 private SecurityConfigImpl config;
36 private StubAuthenticator authenticator;
37 private Mock session;
38 private Principal user;
39 private RememberMeService rememberMeService;
40 private static final String TEST_USERNAME = CharsetUtils.stringFromBytes(new byte[]{(byte) 0xfc, 0x03, 0x05, 0x02, 0x0e, (byte) 0xf5, 0x0d, 0x05}, CharsetUtils.ISO_LATIN_1_CHARSET);
41 private static final String TEST_PASSWORD = CharsetUtils.stringFromBytes(new byte[]{0x00, (byte) 0xf4, 0x03, 0x03, 0x07, 0x0f, 0x02, 0x04}, CharsetUtils.ISO_LATIN_1_CHARSET);
42
43 protected void setUp() throws Exception
44 {
45 super.setUp();
46 request = new Mock(HttpServletRequest.class);
47 response = new Mock(HttpServletResponse.class);
48 session = new Mock(HttpSession.class);
49 SecurityConfigFactory.setSecurityConfig(null);
50 config = (SecurityConfigImpl) SecurityConfigFactory.getInstance("test-seraph-config.xml");
51 authenticator = (StubAuthenticator) config.getAuthenticator();
52 user = new Principal()
53 {
54 public String getName()
55 {
56 return "Test User";
57 }
58 };
59
60 rememberMeService = mock(RememberMeService.class);
61 authenticator.setRememberMeService(rememberMeService);
62
63 authenticator.addUser(user.getName(), user);
64 }
65
66 public void testLogout() throws ConfigurationException, AuthenticatorException
67 {
68
69 final Mock logoutInterceptor = new Mock(LogoutInterceptor.class);
70
71
72 request.expectAndReturn("getSession", session.proxy());
73
74 mockOutLoginReason(LoginReason.OUT);
75
76 session.expect("setAttribute", C.args(C.eq(DefaultAuthenticator.LOGGED_IN_KEY), C.IS_NULL));
77 session.expect("setAttribute", C.args(C.eq(DefaultAuthenticator.LOGGED_OUT_KEY), C.eq(Boolean.TRUE)));
78
79 logoutInterceptor.expect("beforeLogout", C.ANY_ARGS);
80 logoutInterceptor.expect("afterLogout", C.ANY_ARGS);
81 config.addInterceptor((Interceptor) logoutInterceptor.proxy());
82
83
84 authenticator.logout((HttpServletRequest) request.proxy(), (HttpServletResponse) response.proxy());
85
86
87 request.verify();
88 response.verify();
89 session.verify();
90 logoutInterceptor.verify();
91 }
92
93 public void testGetUserChecksSessionFirst()
94 {
95
96 request.matchAndReturn("getSession", C.ANY_ARGS, session.proxy());
97 session.matchAndReturn("getAttribute", C.args(C.eq(DefaultAuthenticator.LOGGED_OUT_KEY)), null);
98 session.matchAndReturn("getAttribute", C.args(C.eq(DefaultAuthenticator.LOGGED_IN_KEY)), user);
99
100 mockOutLoginReason(LoginReason.OK);
101
102 final Principal result = authenticator.getUser((HttpServletRequest) request.proxy(), (HttpServletResponse) response.proxy());
103 assertEquals(user, result);
104
105 request.verify();
106 response.verify();
107 session.verify();
108 }
109
110 private StubAuthenticator setupRememberMeCookieState(LoginReason loginReason)
111 {
112 request.matchAndReturn("getSession", C.IS_FALSE, null);
113 request.matchAndReturn("getSession", C.NO_ARGS, session.proxy());
114
115 mockOutLoginReason(loginReason);
116
117 session.matchAndReturn("getAttribute", C.args(C.eq(DefaultAuthenticator.LOGGED_OUT_KEY)), null);
118 session.matchAndReturn("getAttribute", C.args(C.eq(DefaultAuthenticator.LOGGED_IN_KEY)), user);
119 return authenticator;
120 }
121
122 public void testGetUserChecksCookieIfNoSession()
123 {
124 setupRememberMeCookieState(LoginReason.OK);
125
126 final HttpServletRequest httpServletRequest = (HttpServletRequest) request.proxy();
127 final HttpServletResponse httpServletResponse = (HttpServletResponse) response.proxy();
128
129 when(rememberMeService.getRememberMeCookieAuthenticatedUsername(httpServletRequest, httpServletResponse)).thenReturn(user.getName());
130
131 final Principal result = authenticator.getUser(httpServletRequest, httpServletResponse);
132 assertEquals(user, result);
133
134 request.verify();
135 response.verify();
136 session.verify();
137 }
138
139 public void testGetUserChecksCookieIfNoSession_ButFailedAuthorisation()
140 {
141 authenticator.setDesiredLoginAnswer(false);
142 setupRememberMeCookieState(LoginReason.AUTHORISATION_FAILED);
143
144
145 request.expectAndReturn("getQueryString", "p=v");
146 request.expectAndReturn("getHeader", "Authorization", null);
147
148 final HttpServletRequest httpServletRequest = (HttpServletRequest) request.proxy();
149 final HttpServletResponse httpServletResponse = (HttpServletResponse) response.proxy();
150
151 when(rememberMeService.getRememberMeCookieAuthenticatedUsername(httpServletRequest, httpServletResponse)).thenReturn(user.getName());
152
153 final Principal result = authenticator.getUser(httpServletRequest, httpServletResponse);
154 assertNull(result);
155
156 request.verify();
157 response.verify();
158 session.verify();
159 }
160
161
162 public void testGetUserReturnsNullWithNoValidAuthentication()
163 {
164 request.matchAndReturn("getSession", C.IS_FALSE, null);
165 request.expectAndReturn("getQueryString", null);
166 request.expectAndReturn("getHeader", C.args(C.eq("Authorization")), null);
167
168 final Principal result = authenticator.getUser((HttpServletRequest) request.proxy(), (HttpServletResponse) response.proxy());
169 assertEquals(null, result);
170
171 request.verify();
172 response.verify();
173 session.verify();
174 }
175
176 public void testGetUserBasicAuthRequiredButMissing()
177 {
178 request.matchAndReturn("getSession", C.IS_FALSE, null);
179 request.matchAndReturn("getCookies", null);
180 request.matchAndReturn("getQueryString", "os_authType=basic");
181
182
183 request.expectAndReturn("getHeader", C.eq("Authorization"), null);
184
185 response.expect("setStatus", C.eq(401));
186 response.expect("setHeader", C.eq("WWW-Authenticate", "Basic realm=\"protected-area\""));
187
188 final Principal result = authenticator.getUser((HttpServletRequest) request.proxy(), (HttpServletResponse) response.proxy());
189 assertEquals(null, result);
190
191 request.verify();
192 response.verify();
193 session.verify();
194 }
195
196 private StubAuthenticator setupBasicAuthHttpState(LoginReason loginReason)
197 {
198 request.matchAndReturn("getSession", C.IS_FALSE, null);
199 request.matchAndReturn("getCookies", null);
200 request.matchAndReturn("getQueryString", "os_authType=basic");
201
202 mockOutLoginReason(loginReason);
203
204
205 request.expectAndReturn("getHeader", C.eq("Authorization"),
206 SecurityUtils.encodeBasicAuthorizationCredentials(TEST_USERNAME, TEST_PASSWORD));
207
208 final StubAuthenticator stubAuthenticator = authenticator;
209 stubAuthenticator.addUser(TEST_USERNAME, user);
210 return stubAuthenticator;
211 }
212
213 public void testGetUserBasicAuthProvidedUsingRequestParameter()
214 {
215 setupBasicAuthHttpState(LoginReason.OK);
216
217 final Principal result = authenticator.getUser((HttpServletRequest) request.proxy(), (HttpServletResponse) response.proxy());
218 assertEquals(user, result);
219
220 request.verify();
221 response.verify();
222 session.verify();
223 }
224
225 public void testGetUserBasicAuthProvidedUsingRequestParameter_ButFailsElevatedSecurity() throws ConfigurationException
226 {
227 final StubAuthenticator stubAuthenticator = setupBasicAuthHttpState(LoginReason.AUTHENTICATION_DENIED);
228
229 final CountingElevatedSecurityGuard securityGuard = new CountingElevatedSecurityGuard(false, TEST_USERNAME);
230 stubAuthenticator.setElevatedSecurityGuard(securityGuard);
231
232
233 response.expect("sendError", C.args(C.eq(401), C.eq("Basic Authentication Failure - Reason : " + LoginReason.AUTHENTICATION_DENIED)));
234
235 final Principal result = authenticator.getUser((HttpServletRequest) request.proxy(), (HttpServletResponse) response.proxy());
236 assertNull(result);
237
238 assertEquals(0, securityGuard.getSuccessCount());
239 assertEquals(1, securityGuard.getFailedCount());
240
241 request.verify();
242 response.verify();
243 session.verify();
244 }
245
246 public void testGetUserBasicAuthProvidedUsingRequestParameter_PassesElevatedSecurity_ButFailsLogin() throws ConfigurationException
247 {
248 final StubAuthenticator stubAuthenticator = setupBasicAuthHttpState(LoginReason.AUTHENTICATED_FAILED);
249 stubAuthenticator.setDesiredLoginAnswer(false);
250
251 final CountingElevatedSecurityGuard securityGuard = new CountingElevatedSecurityGuard(true, TEST_USERNAME);
252 stubAuthenticator.setElevatedSecurityGuard(securityGuard);
253
254
255 response.expect("sendError", C.args(C.eq(401), C.eq("Basic Authentication Failure - Reason : " + LoginReason.AUTHENTICATED_FAILED)));
256
257 final Principal result = authenticator.getUser((HttpServletRequest) request.proxy(), (HttpServletResponse) response.proxy());
258 assertNull(result);
259
260 assertEquals(0, securityGuard.getSuccessCount());
261 assertEquals(1, securityGuard.getFailedCount());
262
263 request.verify();
264 response.verify();
265 session.verify();
266 }
267
268 public void testGetUserBasicAuthProvidedUsingRequestParameter_PassesElevatedSecurity_AndPassesLogin() throws ConfigurationException
269 {
270 final StubAuthenticator stubAuthenticator = setupBasicAuthHttpState(LoginReason.OK);
271 stubAuthenticator.setDesiredLoginAnswer(true);
272
273 final CountingElevatedSecurityGuard securityGuard = new CountingElevatedSecurityGuard(true, TEST_USERNAME);
274 stubAuthenticator.setElevatedSecurityGuard(securityGuard);
275
276 final Principal result = authenticator.getUser((HttpServletRequest) request.proxy(), (HttpServletResponse) response.proxy());
277 assertEquals(user, result);
278
279 assertEquals(1, securityGuard.getSuccessCount());
280 assertEquals(0, securityGuard.getFailedCount());
281
282 request.verify();
283 response.verify();
284 session.verify();
285 }
286
287 public void testGetUserBasicAuthProvidedUsingHeader()
288 {
289 final String authorizationHeader = SecurityUtils.encodeBasicAuthorizationCredentials(TEST_USERNAME, TEST_PASSWORD);
290
291 request.matchAndReturn("getSession", C.IS_FALSE, null);
292 request.matchAndReturn("getCookies", null);
293 request.matchAndReturn("getQueryString", null);
294
295 request.expectAndReturn("getHeader", C.eq("Authorization"), authorizationHeader);
296 request.expectAndReturn("getHeader", C.eq("Authorization"), authorizationHeader);
297
298 mockOutLoginReason(LoginReason.OK);
299
300
301 final StubAuthenticator stubAuthenticator = authenticator;
302 stubAuthenticator.addUser(TEST_USERNAME, user);
303
304 final CountingElevatedSecurityGuard securityGuard = new CountingElevatedSecurityGuard(true, TEST_USERNAME);
305 stubAuthenticator.setElevatedSecurityGuard(securityGuard);
306
307 final Principal result = authenticator.getUser((HttpServletRequest) request.proxy(), (HttpServletResponse) response.proxy());
308 assertEquals(user, result);
309
310 assertEquals(1, securityGuard.getSuccessCount());
311 assertEquals(0, securityGuard.getFailedCount());
312
313 request.verify();
314 response.verify();
315 session.verify();
316 }
317
318 private void mockOutLoginReason(LoginReason loginReason)
319 {
320 request.expectAndReturn("getAttribute", C.args(C.eq("com.atlassian.seraph.auth.LoginReason")), null);
321 request.expect("setAttribute", C.args(C.eq("com.atlassian.seraph.auth.LoginReason"), C.eq(loginReason)));
322
323 response.expect("addHeader", C.ANY_ARGS);
324 }
325 }