1 package com.atlassian.seraph.filter;
2
3 import com.atlassian.seraph.auth.AuthenticationErrorType;
4 import com.atlassian.seraph.auth.Authenticator;
5 import com.atlassian.seraph.auth.AuthenticatorException;
6 import com.atlassian.seraph.config.SecurityConfig;
7 import com.atlassian.seraph.elevatedsecurity.CountingElevatedSecurityGuard;
8 import com.atlassian.seraph.interceptor.LoginInterceptor;
9 import com.atlassian.seraph.util.LocalMockHttpServletRequest;
10 import com.mockobjects.dynamic.C;
11 import com.mockobjects.dynamic.Mock;
12 import junit.framework.TestCase;
13
14 import javax.servlet.http.HttpServletRequest;
15 import javax.servlet.http.HttpServletResponse;
16 import javax.servlet.http.HttpSession;
17 import java.security.Principal;
18 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.List;
21 import java.util.Map;
22
23
24
25
26 public class TestPasswordBasedLoginFilter extends TestCase
27 {
28 public void testNullUserNameFails()
29 {
30 final MockSecurityConfig securityConfig = new MockSecurityConfig(Collections.EMPTY_LIST);
31 final PasswordBasedLoginFilter passwordBasedLoginFilter = new TestedPasswordBasedLoginFilter(null, "password", securityConfig);
32
33 final String actualStatus = passwordBasedLoginFilter.login(makeHttpRequest(), makeHttpResponse());
34 assertEquals(PasswordBasedLoginFilter.LOGIN_NOATTEMPT, actualStatus);
35 }
36
37
38 public void testNullPasswordFails()
39 {
40 final MockSecurityConfig securityConfig = new MockSecurityConfig(Collections.EMPTY_LIST);
41 final PasswordBasedLoginFilter passwordBasedLoginFilter = new TestedPasswordBasedLoginFilter("userName", null, securityConfig);
42
43 final String actualStatus = passwordBasedLoginFilter.login(makeHttpRequest(), makeHttpResponse());
44 assertEquals(PasswordBasedLoginFilter.LOGIN_NOATTEMPT, actualStatus);
45 }
46
47 public void testNullUserPairFails()
48 {
49 final PasswordBasedLoginFilter passwordBasedLoginFilter = new PasswordBasedLoginFilter()
50 {
51 protected PasswordBasedLoginFilter.UserPasswordPair extractUserPasswordPair(final HttpServletRequest request)
52 {
53 return null;
54 }
55 };
56
57 final String actualStatus = passwordBasedLoginFilter.login(makeHttpRequest(), makeHttpResponse());
58 assertEquals(PasswordBasedLoginFilter.LOGIN_NOATTEMPT, actualStatus);
59 }
60
61 public void testElevatedSecurityGuard_FailedCheck()
62 {
63 final CountingElevatedSecurityGuard securityGuard = new CountingElevatedSecurityGuard(false, "userName");
64
65 final MockSecurityConfig securityConfig = new MockSecurityConfig(securityGuard, null, null, Collections.EMPTY_LIST);
66 final PasswordBasedLoginFilter passwordBasedLoginFilter = new TestedPasswordBasedLoginFilter("userName", "password", securityConfig);
67
68
69 final String actualStatus = passwordBasedLoginFilter.login(makeHttpRequest(), makeHttpResponse());
70 assertEquals(PasswordBasedLoginFilter.LOGIN_FAILED, actualStatus);
71 assertEquals(1, securityGuard.getFailedCount());
72 assertEquals(0, securityGuard.getSuccessCount());
73 }
74
75 public void testElevatedSecurityGuard_PassedCheck_ButFailedAuthenticator()
76 {
77 final CountingElevatedSecurityGuard securityGuard = new CountingElevatedSecurityGuard(true, "userName");
78
79 final AssertingAuthenticator authenticator = new AssertingAuthenticator(false, "userName", "password");
80
81 final MockSecurityConfig securityConfig = new MockSecurityConfig(securityGuard, authenticator, null, Collections.EMPTY_LIST);
82 final PasswordBasedLoginFilter passwordBasedLoginFilter = new TestedPasswordBasedLoginFilter("userName", "password", securityConfig);
83
84
85 final String actualStatus = passwordBasedLoginFilter.login(makeHttpRequest(), makeHttpResponse());
86 assertEquals(PasswordBasedLoginFilter.LOGIN_FAILED, actualStatus);
87 assertEquals(1, securityGuard.getFailedCount());
88 assertEquals(0, securityGuard.getSuccessCount());
89 }
90
91 public void testElevatedSecurityGuard_PassedCheck_ButAuthenticatorThrewException()
92 {
93 final CountingElevatedSecurityGuard securityGuard = new CountingElevatedSecurityGuard(true, "userName");
94
95 @SuppressWarnings({"ThrowableInstanceNeverThrown"})
96 final AssertingAuthenticator authenticator = new AssertingAuthenticator(false, "userName", "password", new AuthenticatorException());
97
98 final MockSecurityConfig securityConfig = new MockSecurityConfig(securityGuard, authenticator, null, Collections.EMPTY_LIST);
99 final PasswordBasedLoginFilter passwordBasedLoginFilter = new TestedPasswordBasedLoginFilter("userName", "password", securityConfig);
100
101
102 final String actualStatus = passwordBasedLoginFilter.login(makeHttpRequest(), makeHttpResponse());
103 assertEquals(PasswordBasedLoginFilter.LOGIN_ERROR, actualStatus);
104
105
106 assertEquals(0, securityGuard.getFailedCount());
107 assertEquals(0, securityGuard.getSuccessCount());
108 }
109
110 public void testElevatedSecurityGuard_PassedCheck_AndPassedAuthenticator()
111 {
112 final CountingElevatedSecurityGuard securityGuard = new CountingElevatedSecurityGuard(true, "userName");
113
114 final AssertingAuthenticator authenticator = new AssertingAuthenticator(true, "userName", "password");
115 final MockSecurityConfig securityConfig = new MockSecurityConfig(securityGuard, authenticator, null, Collections.EMPTY_LIST);
116 final PasswordBasedLoginFilter passwordBasedLoginFilter = new TestedPasswordBasedLoginFilter("userName", "password", securityConfig);
117
118
119 final String actualStatus = passwordBasedLoginFilter.login(makeHttpRequest(), makeHttpResponse());
120 assertEquals(PasswordBasedLoginFilter.LOGIN_SUCCESS, actualStatus);
121 assertEquals(0, securityGuard.getFailedCount());
122 assertEquals(1, securityGuard.getSuccessCount());
123 }
124
125
126 public void testInterceptorsAreCalled()
127 {
128 CountingLoginInterceptor loginInterceptor = new CountingLoginInterceptor();
129 List<CountingLoginInterceptor> interceptors = new ArrayList<CountingLoginInterceptor>();
130 interceptors.add(loginInterceptor);
131
132 final CountingElevatedSecurityGuard securityGuard = new CountingElevatedSecurityGuard(true, "userName");
133
134 final AssertingAuthenticator authenticator = new AssertingAuthenticator(true, "userName", "password", null);
135
136 final MockSecurityConfig securityConfig = new MockSecurityConfig(securityGuard, authenticator, null, interceptors);
137 final PasswordBasedLoginFilter passwordBasedLoginFilter = new TestedPasswordBasedLoginFilter("userName", "password", securityConfig);
138
139
140 passwordBasedLoginFilter.login(makeHttpRequest(), makeHttpResponse());
141 assertEquals(1, loginInterceptor.getBeforeLogin());
142 assertEquals(1, loginInterceptor.getAfterLogin());
143
144 }
145
146 public void testLoginNullErrorType()
147 {
148 final CountingElevatedSecurityGuard securityGuard = new CountingElevatedSecurityGuard(true, "userName");
149
150 @SuppressWarnings({"ThrowableInstanceNeverThrown"})
151 final AssertingAuthenticator authenticator = new AssertingAuthenticator(false, "userName", "password", new AuthenticatorException());
152
153 final MockSecurityConfig securityConfig = new MockSecurityConfig(securityGuard, authenticator, null, Collections.EMPTY_LIST);
154 final PasswordBasedLoginFilter passwordBasedLoginFilter = new TestedPasswordBasedLoginFilter("userName", "password", securityConfig);
155
156 final LocalMockHttpServletRequest mockHttpServletRequest = makeHttpRequest();
157 final String actualStatus = passwordBasedLoginFilter.login(mockHttpServletRequest, makeHttpResponse());
158 assertEquals(PasswordBasedLoginFilter.LOGIN_ERROR, actualStatus);
159 assertEquals(null, mockHttpServletRequest.getAttribute(BaseLoginFilter.AUTHENTICATION_ERROR_TYPE));
160
161
162 assertEquals(0, securityGuard.getFailedCount());
163 assertEquals(0, securityGuard.getSuccessCount());
164 }
165
166 public void testLoginCommunicationError()
167 {
168 final CountingElevatedSecurityGuard securityGuard = new CountingElevatedSecurityGuard(true, "userName");
169
170 @SuppressWarnings({"ThrowableInstanceNeverThrown"})
171 final AssertingAuthenticator authenticator = new AssertingAuthenticator(false, "userName", "password", new AuthenticatorException(AuthenticationErrorType.CommunicationError));
172
173 final MockSecurityConfig securityConfig = new MockSecurityConfig(securityGuard, authenticator, null, Collections.EMPTY_LIST);
174 final PasswordBasedLoginFilter passwordBasedLoginFilter = new TestedPasswordBasedLoginFilter("userName", "password", securityConfig);
175
176 final LocalMockHttpServletRequest mockHttpServletRequest = makeHttpRequest();
177 final String actualStatus = passwordBasedLoginFilter.login(mockHttpServletRequest, makeHttpResponse());
178 assertEquals(PasswordBasedLoginFilter.LOGIN_ERROR, actualStatus);
179 assertEquals(AuthenticationErrorType.CommunicationError, mockHttpServletRequest.getAttribute(BaseLoginFilter.AUTHENTICATION_ERROR_TYPE));
180
181
182 assertEquals(0, securityGuard.getFailedCount());
183 assertEquals(0, securityGuard.getSuccessCount());
184 }
185
186 public void testLoginUnknownError()
187 {
188 final CountingElevatedSecurityGuard securityGuard = new CountingElevatedSecurityGuard(true, "userName");
189
190 @SuppressWarnings({"ThrowableInstanceNeverThrown"})
191 final AssertingAuthenticator authenticator = new AssertingAuthenticator(false, "userName", "password", new AuthenticatorException(AuthenticationErrorType.UnknownError));
192
193 final MockSecurityConfig securityConfig = new MockSecurityConfig(securityGuard, authenticator, null, Collections.EMPTY_LIST);
194 final PasswordBasedLoginFilter passwordBasedLoginFilter = new TestedPasswordBasedLoginFilter("userName", "password", securityConfig);
195
196 final LocalMockHttpServletRequest mockHttpServletRequest = makeHttpRequest();
197 final String actualStatus = passwordBasedLoginFilter.login(mockHttpServletRequest, makeHttpResponse());
198 assertEquals(PasswordBasedLoginFilter.LOGIN_ERROR, actualStatus);
199 assertEquals(AuthenticationErrorType.UnknownError, mockHttpServletRequest.getAttribute(BaseLoginFilter.AUTHENTICATION_ERROR_TYPE));
200
201
202 assertEquals(0, securityGuard.getFailedCount());
203 assertEquals(0, securityGuard.getSuccessCount());
204 }
205
206 class TestedPasswordBasedLoginFilter extends PasswordBasedLoginFilter
207 {
208 private final String userName;
209 private final String password;
210 private final MockSecurityConfig mockSecurityConfig;
211
212
213 TestedPasswordBasedLoginFilter(final String userName, final String password, final MockSecurityConfig mockSecurityConfig)
214 {
215 this.userName = userName;
216 this.password = password;
217 this.mockSecurityConfig = mockSecurityConfig;
218 }
219
220 @Override
221 protected PasswordBasedLoginFilter.UserPasswordPair extractUserPasswordPair(final HttpServletRequest request)
222 {
223 return new PasswordBasedLoginFilter.UserPasswordPair(userName, password, true);
224 }
225
226 @Override
227 protected SecurityConfig getSecurityConfig()
228 {
229 return mockSecurityConfig;
230 }
231 }
232
233 class AssertingAuthenticator implements Authenticator
234 {
235 private final boolean loginOK;
236 private final String expectedUserName;
237 private final String expectedPassword;
238 private final AuthenticatorException authenticatorException;
239
240 public AssertingAuthenticator(final boolean loginOK, final String expectedUserName, final String expectedPassword)
241 {
242 this(loginOK, expectedUserName, expectedPassword, null);
243 }
244
245 public AssertingAuthenticator(final boolean loginOK, final String expectedUserName, final String expectedPassword, final AuthenticatorException authenticatorException)
246 {
247 this.loginOK = loginOK;
248 this.expectedUserName = expectedUserName;
249 this.expectedPassword = expectedPassword;
250 this.authenticatorException = authenticatorException;
251 }
252
253 public boolean login(final HttpServletRequest request, final HttpServletResponse response, final String username, final String password)
254 throws AuthenticatorException
255 {
256 return loginImpl(username, password);
257 }
258
259 public boolean login(final HttpServletRequest request, final HttpServletResponse response, final String username, final String password, final boolean storeCookie)
260 throws AuthenticatorException
261 {
262 return loginImpl(username, password);
263 }
264
265 private boolean loginImpl(final String username, final String password) throws AuthenticatorException
266 {
267 assertEquals(expectedUserName, username);
268 assertEquals(expectedPassword, password);
269 if (authenticatorException != null)
270 {
271 throw authenticatorException;
272 }
273 return loginOK;
274 }
275
276 public String getRemoteUser(final HttpServletRequest request)
277 {
278 return null;
279 }
280
281 public void destroy()
282 {
283 }
284
285 public Principal getUser(final HttpServletRequest request)
286 {
287 return null;
288 }
289
290 public Principal getUser(final HttpServletRequest request, final HttpServletResponse response)
291 {
292 return null;
293 }
294
295 public boolean isUserInRole(final HttpServletRequest request, final String role)
296 {
297 return false;
298 }
299
300 public boolean logout(final HttpServletRequest request, final HttpServletResponse response)
301 throws AuthenticatorException
302 {
303 return false;
304 }
305
306 public void init(final Map<String, String> params, final SecurityConfig config)
307 {
308 }
309 }
310
311 class CountingLoginInterceptor implements LoginInterceptor
312 {
313 private int beforeLogin;
314 private int afterLogin;
315
316 public void beforeLogin(final HttpServletRequest request, final HttpServletResponse response, final String username, final String password, final boolean cookieLogin)
317 {
318 beforeLogin++;
319 }
320
321 public void afterLogin(final HttpServletRequest request, final HttpServletResponse response, final String username, final String password, final boolean cookieLogin, final String loginStatus)
322 {
323 afterLogin++;
324 }
325
326 public void destroy()
327 {
328 }
329
330 public void init(final Map<String, String> params, final SecurityConfig config)
331 {
332 }
333
334 public int getBeforeLogin()
335 {
336 return beforeLogin;
337 }
338
339 public int getAfterLogin()
340 {
341 return afterLogin;
342 }
343 }
344
345 private HttpServletResponse makeHttpResponse()
346 {
347 final Mock mockHttpServletResponse = new Mock(HttpServletResponse.class);
348 mockHttpServletResponse.expect("addHeader", C.ANY_ARGS);
349 return (HttpServletResponse) mockHttpServletResponse.proxy();
350 }
351
352 private LocalMockHttpServletRequest makeHttpRequest()
353 {
354 final LocalMockHttpServletRequest httpServletRequest = new LocalMockHttpServletRequest();
355 httpServletRequest.setupGetAttribute(null);
356
357 final HttpSession session = new MockSession();
358 httpServletRequest.setSession(session);
359 return httpServletRequest;
360 }
361
362
363 }