1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.acegisecurity.ui.rememberme;
17
18 import junit.framework.TestCase;
19
20 import org.acegisecurity.Authentication;
21 import org.acegisecurity.GrantedAuthority;
22 import org.acegisecurity.GrantedAuthorityImpl;
23
24
25 import org.acegisecurity.providers.TestingAuthenticationToken;
26 import org.acegisecurity.userdetails.UserDetailsService;
27 import org.acegisecurity.userdetails.User;
28 import org.acegisecurity.userdetails.UserDetails;
29 import org.acegisecurity.userdetails.UsernameNotFoundException;
30
31 import org.apache.commons.codec.binary.Base64;
32 import org.apache.commons.codec.digest.DigestUtils;
33
34 import org.springframework.dao.DataAccessException;
35
36 import org.springframework.util.StringUtils;
37 import org.springframework.mock.web.MockHttpServletRequest;
38 import org.springframework.mock.web.MockHttpServletResponse;
39
40 import java.util.Date;
41
42 import javax.servlet.http.Cookie;
43
44
45 /***
46 * Tests {@link
47 * org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices}.
48 *
49 * @author Ben Alex
50 * @version $Id: TokenBasedRememberMeServicesTests.java,v 1.6 2005/11/30 00:20:13 benalex Exp $
51 */
52 public class TokenBasedRememberMeServicesTests extends TestCase {
53
54
55 public TokenBasedRememberMeServicesTests() {
56 super();
57 }
58
59 public TokenBasedRememberMeServicesTests(String arg0) {
60 super(arg0);
61 }
62
63
64
65 public static void main(String[] args) {
66 junit.textui.TestRunner.run(TokenBasedRememberMeServicesTests.class);
67 }
68
69 public void testAutoLoginIfDoesNotPresentAnyCookies()
70 throws Exception {
71 TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
72 services.setKey("key");
73 services.setUserDetailsService(new MockAuthenticationDao(null, true));
74 services.afterPropertiesSet();
75
76 MockHttpServletRequest request = new MockHttpServletRequest();
77 request.setRequestURI("dc");
78 MockHttpServletResponse response = new MockHttpServletResponse();
79
80 Authentication result = services.autoLogin(request, response);
81
82 assertNull(result);
83
84 Cookie returnedCookie = response.getCookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY);
85 assertNull(returnedCookie);
86 }
87
88 public void testAutoLoginIfDoesNotPresentRequiredCookie()
89 throws Exception {
90 TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
91 services.setKey("key");
92 services.setUserDetailsService(new MockAuthenticationDao(null, true));
93 services.afterPropertiesSet();
94
95 Cookie cookie = new Cookie("unrelated_cookie", "foobar");
96 MockHttpServletRequest request = new MockHttpServletRequest();
97 request.setCookies(new Cookie[] {cookie});
98 MockHttpServletResponse response = new MockHttpServletResponse();
99
100 Authentication result = services.autoLogin(request, response);
101
102 assertNull(result);
103
104 Cookie returnedCookie = response.getCookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY);
105 assertNull(returnedCookie);
106 }
107
108 public void testAutoLoginIfExpired() throws Exception {
109 UserDetails user = new User("someone", "password", true, true, true,
110 true,
111 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ABC")});
112
113 TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
114 services.setKey("key");
115 services.setUserDetailsService(new MockAuthenticationDao(user, false));
116 services.afterPropertiesSet();
117
118 Cookie cookie = new Cookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY,
119 generateCorrectCookieContentForToken(System.currentTimeMillis()
120 - 1000000, "someone", "password", "key"));
121 MockHttpServletRequest request = new MockHttpServletRequest();
122 request.setCookies(new Cookie[] {cookie});
123 MockHttpServletResponse response = new MockHttpServletResponse();
124
125 Authentication result = services.autoLogin(request, response);
126
127 assertNull(result);
128
129 Cookie returnedCookie = response.getCookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY);
130 assertNotNull(returnedCookie);
131 assertEquals(0, returnedCookie.getMaxAge());
132 }
133
134 public void testAutoLoginIfMissingThreeTokensInCookieValue()
135 throws Exception {
136 UserDetails user = new User("someone", "password", true, true, true,
137 true,
138 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ABC")});
139
140 TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
141 services.setKey("key");
142 services.setUserDetailsService(new MockAuthenticationDao(user, false));
143 services.afterPropertiesSet();
144
145 Cookie cookie = new Cookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY,
146 new String(Base64.encodeBase64("x".getBytes())));
147 MockHttpServletRequest request = new MockHttpServletRequest();
148 request.setCookies(new Cookie[] {cookie});
149 MockHttpServletResponse response = new MockHttpServletResponse();
150
151 Authentication result = services.autoLogin(request, response);
152
153 assertNull(result);
154
155 Cookie returnedCookie = response.getCookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY);
156 assertNotNull(returnedCookie);
157 assertEquals(0, returnedCookie.getMaxAge());
158 }
159
160 public void testAutoLoginIfNotBase64Encoded() throws Exception {
161 UserDetails user = new User("someone", "password", true, true, true,
162 true,
163 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ABC")});
164
165 TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
166 services.setKey("key");
167 services.setUserDetailsService(new MockAuthenticationDao(user, false));
168 services.afterPropertiesSet();
169
170 Cookie cookie = new Cookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY,
171 "NOT_BASE_64_ENCODED");
172 MockHttpServletRequest request = new MockHttpServletRequest();
173 request.setCookies(new Cookie[] {cookie});
174 MockHttpServletResponse response = new MockHttpServletResponse();
175
176 Authentication result = services.autoLogin(request, response);
177
178 assertNull(result);
179
180 Cookie returnedCookie = response.getCookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY);
181 assertNotNull(returnedCookie);
182 assertEquals(0, returnedCookie.getMaxAge());
183 }
184
185 public void testAutoLoginIfSignatureBlocksDoesNotMatchExpectedValue()
186 throws Exception {
187 UserDetails user = new User("someone", "password", true, true, true,
188 true,
189 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ABC")});
190
191 TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
192 services.setKey("key");
193 services.setUserDetailsService(new MockAuthenticationDao(user, false));
194 services.afterPropertiesSet();
195
196 Cookie cookie = new Cookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY,
197 generateCorrectCookieContentForToken(System.currentTimeMillis()
198 + 1000000, "someone", "password", "WRONG_KEY"));
199 MockHttpServletRequest request = new MockHttpServletRequest();
200 request.setCookies(new Cookie[] {cookie});
201 MockHttpServletResponse response = new MockHttpServletResponse();
202
203 Authentication result = services.autoLogin(request, response);
204
205 assertNull(result);
206
207 Cookie returnedCookie = response.getCookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY);
208 assertNotNull(returnedCookie);
209 assertEquals(0, returnedCookie.getMaxAge());
210 }
211
212 public void testAutoLoginIfTokenDoesNotContainANumberInCookieValue()
213 throws Exception {
214 UserDetails user = new User("someone", "password", true, true, true,
215 true,
216 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ABC")});
217
218 TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
219 services.setKey("key");
220 services.setUserDetailsService(new MockAuthenticationDao(user, false));
221 services.afterPropertiesSet();
222
223 Cookie cookie = new Cookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY,
224 new String(Base64.encodeBase64(
225 "username:NOT_A_NUMBER:signature".getBytes())));
226 MockHttpServletRequest request = new MockHttpServletRequest();
227 request.setCookies(new Cookie[] {cookie});
228 MockHttpServletResponse response = new MockHttpServletResponse();
229
230 Authentication result = services.autoLogin(request, response);
231
232 assertNull(result);
233
234 Cookie returnedCookie = response.getCookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY);
235 assertNotNull(returnedCookie);
236 assertEquals(0, returnedCookie.getMaxAge());
237 }
238
239 public void testAutoLoginIfUserNotFound() throws Exception {
240 TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
241 services.setKey("key");
242 services.setUserDetailsService(new MockAuthenticationDao(null, true));
243 services.afterPropertiesSet();
244
245 Cookie cookie = new Cookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY,
246 generateCorrectCookieContentForToken(System.currentTimeMillis()
247 + 1000000, "someone", "password", "key"));
248 MockHttpServletRequest request = new MockHttpServletRequest();
249 request.setCookies(new Cookie[] {cookie});
250 MockHttpServletResponse response = new MockHttpServletResponse();
251
252 Authentication result = services.autoLogin(request, response);
253
254 assertNull(result);
255
256 Cookie returnedCookie = response.getCookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY);
257 assertNotNull(returnedCookie);
258 assertEquals(0, returnedCookie.getMaxAge());
259 }
260
261 public void testAutoLoginWithValidToken() throws Exception {
262 UserDetails user = new User("someone", "password", true, true, true,
263 true,
264 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ABC")});
265
266 TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
267 services.setKey("key");
268 services.setUserDetailsService(new MockAuthenticationDao(user, false));
269 services.afterPropertiesSet();
270
271 Cookie cookie = new Cookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY,
272 generateCorrectCookieContentForToken(System.currentTimeMillis()
273 + 1000000, "someone", "password", "key"));
274 MockHttpServletRequest request = new MockHttpServletRequest();
275 request.setCookies(new Cookie[] {cookie});
276 MockHttpServletResponse response = new MockHttpServletResponse();
277
278 Authentication result = services.autoLogin(request, response);
279
280 assertNotNull(result);
281
282 UserDetails resultingUserDetails = (UserDetails) result.getPrincipal();
283
284 assertEquals(user, resultingUserDetails);
285 }
286
287 public void testGettersSetters() {
288 TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
289 services.setUserDetailsService(new MockAuthenticationDao(null, false));
290 assertTrue(services.getUserDetailsService() != null);
291
292 services.setKey("d");
293 assertEquals("d", services.getKey());
294
295 assertEquals(TokenBasedRememberMeServices.DEFAULT_PARAMETER,
296 services.getParameter());
297 services.setParameter("some_param");
298 assertEquals("some_param", services.getParameter());
299
300 services.setTokenValiditySeconds(12);
301 assertEquals(12, services.getTokenValiditySeconds());
302 }
303
304 public void testLoginFail() {
305 TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
306 MockHttpServletRequest request = new MockHttpServletRequest();
307 request.setRequestURI("fv");
308 MockHttpServletResponse response = new MockHttpServletResponse();
309 services.loginFail(request, response);
310
311 Cookie cookie = response.getCookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY);
312 assertNotNull(cookie);
313 assertEquals(0, cookie.getMaxAge());
314 }
315
316 public void testLoginSuccessIgnoredIfParameterNotSetOrFalse() {
317 TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
318 MockHttpServletRequest request = new MockHttpServletRequest();
319 request.setRequestURI("d");
320 request.addParameter(TokenBasedRememberMeServices.DEFAULT_PARAMETER,
321 "false");
322
323 MockHttpServletResponse response = new MockHttpServletResponse();
324 services.loginSuccess(request, response,
325 new TestingAuthenticationToken("someone", "password",
326 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ABC")}));
327
328 Cookie cookie = response.getCookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY);
329 assertNull(cookie);
330 }
331
332 public void testLoginSuccessNormalWithNonUserDetailsBasedPrincipal() {
333 TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
334 MockHttpServletRequest request = new MockHttpServletRequest();
335 request.setRequestURI("d");
336 request.addParameter(TokenBasedRememberMeServices.DEFAULT_PARAMETER, "true");
337
338 MockHttpServletResponse response = new MockHttpServletResponse();
339 services.loginSuccess(request, response,
340 new TestingAuthenticationToken("someone", "password",
341 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ABC")}));
342
343 Cookie cookie = response.getCookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY);
344 assertNotNull(cookie);
345 assertEquals(60 * 60 * 24 * 365 * 5, cookie.getMaxAge());
346 assertTrue(Base64.isArrayByteBase64(cookie.getValue().getBytes()));
347 assertTrue(new Date().before(
348 new Date(determineExpiryTimeFromBased64EncodedToken(
349 cookie.getValue()))));
350 }
351
352 public void testLoginSuccessNormalWithUserDetailsBasedPrincipal() {
353 TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
354 MockHttpServletRequest request = new MockHttpServletRequest();
355 request.setRequestURI("d");
356 request.addParameter(TokenBasedRememberMeServices.DEFAULT_PARAMETER, "true");
357
358 MockHttpServletResponse response = new MockHttpServletResponse();
359 UserDetails user = new User("someone", "password", true, true, true,
360 true,
361 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ABC")});
362 services.loginSuccess(request, response,
363 new TestingAuthenticationToken(user, "ignored",
364 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ABC")}));
365
366 Cookie cookie = response.getCookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY);
367 assertNotNull(cookie);
368 assertEquals(60 * 60 * 24 * 365 * 5, cookie.getMaxAge());
369 assertTrue(Base64.isArrayByteBase64(cookie.getValue().getBytes()));
370 assertTrue(new Date().before(
371 new Date(determineExpiryTimeFromBased64EncodedToken(
372 cookie.getValue()))));
373 }
374
375 private long determineExpiryTimeFromBased64EncodedToken(String validToken) {
376 String cookieAsPlainText = new String(Base64.decodeBase64(
377 validToken.getBytes()));
378 String[] cookieTokens = StringUtils.delimitedListToStringArray(cookieAsPlainText,
379 ":");
380
381 if (cookieTokens.length == 3) {
382 try {
383 return new Long(cookieTokens[1]).longValue();
384 } catch (NumberFormatException nfe) {}
385 }
386
387 return -1;
388 }
389
390 private String generateCorrectCookieContentForToken(long expiryTime,
391 String username, String password, String key) {
392
393
394 String signatureValue = new String(DigestUtils.md5Hex(username + ":"
395 + expiryTime + ":" + password + ":" + key));
396 String tokenValue = username + ":" + expiryTime + ":" + signatureValue;
397 String tokenValueBase64 = new String(Base64.encodeBase64(
398 tokenValue.getBytes()));
399
400 return tokenValueBase64;
401 }
402
403
404
405 private class MockAuthenticationDao implements UserDetailsService {
406 private UserDetails toReturn;
407 private boolean throwException;
408
409 public MockAuthenticationDao(UserDetails toReturn,
410 boolean throwException) {
411 this.toReturn = toReturn;
412 this.throwException = throwException;
413 }
414
415 public UserDetails loadUserByUsername(String username)
416 throws UsernameNotFoundException, DataAccessException {
417 if (throwException) {
418 throw new UsernameNotFoundException("as requested by mock");
419 }
420
421 return toReturn;
422 }
423 }
424 }