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