1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.acegisecurity.ui;
17
18 import junit.framework.TestCase;
19 import org.acegisecurity.AccountExpiredException;
20 import org.acegisecurity.Authentication;
21 import org.acegisecurity.AuthenticationException;
22 import org.acegisecurity.BadCredentialsException;
23 import org.acegisecurity.GrantedAuthority;
24 import org.acegisecurity.GrantedAuthorityImpl;
25 import org.acegisecurity.MockAuthenticationManager;
26 import org.acegisecurity.context.SecurityContextHolder;
27 import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
28 import org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices;
29 import org.acegisecurity.ui.savedrequest.SavedRequest;
30 import org.acegisecurity.util.PortResolverImpl;
31 import org.springframework.mock.web.MockFilterConfig;
32 import org.springframework.mock.web.MockHttpServletRequest;
33 import org.springframework.mock.web.MockHttpServletResponse;
34
35 import javax.servlet.Filter;
36 import javax.servlet.FilterChain;
37 import javax.servlet.FilterConfig;
38 import javax.servlet.ServletException;
39 import javax.servlet.ServletRequest;
40 import javax.servlet.ServletResponse;
41 import javax.servlet.http.HttpServletRequest;
42 import javax.servlet.http.HttpServletResponse;
43 import java.io.IOException;
44 import java.util.Properties;
45
46
47
48
49
50
51
52
53 public class AbstractProcessingFilterTests extends TestCase {
54
55
56 public AbstractProcessingFilterTests() {
57 super();
58 }
59
60 public AbstractProcessingFilterTests(String arg0) {
61 super(arg0);
62 }
63
64
65
66 private MockHttpServletRequest createMockRequest() {
67 MockHttpServletRequest request = new MockHttpServletRequest();
68
69 request.setServletPath("/j_mock_post");
70 request.setScheme("http");
71 request.setServerName("www.example.com");
72 request.setRequestURI("/mycontext/j_mock_post");
73 request.setContextPath("/mycontext");
74
75 return request;
76 }
77
78 private void executeFilterInContainerSimulator(FilterConfig filterConfig, Filter filter, ServletRequest request,
79 ServletResponse response, FilterChain filterChain)
80 throws ServletException, IOException {
81 filter.init(filterConfig);
82 filter.doFilter(request, response, filterChain);
83 filter.destroy();
84 }
85
86 public static void main(String[] args) {
87 junit.textui.TestRunner.run(AbstractProcessingFilterTests.class);
88 }
89
90 private SavedRequest makeSavedRequestForUrl() {
91 MockHttpServletRequest request = createMockRequest();
92 request.setServletPath("/some_protected_file.html");
93 request.setScheme("http");
94 request.setServerName("www.example.com");
95 request.setRequestURI("/mycontext/some_protected_file.html");
96
97 return new SavedRequest(request, new PortResolverImpl());
98 }
99
100 protected void setUp() throws Exception {
101 super.setUp();
102 SecurityContextHolder.clearContext();
103 }
104
105 protected void tearDown() throws Exception {
106 super.tearDown();
107 SecurityContextHolder.clearContext();
108 }
109
110 public void testDefaultProcessesFilterUrlWithPathParameter() {
111 MockHttpServletRequest request = createMockRequest();
112 MockHttpServletResponse response = new MockHttpServletResponse();
113 MockAbstractProcessingFilter filter = new MockAbstractProcessingFilter();
114 filter.setFilterProcessesUrl("/j_acegi_security_check");
115
116 request.setRequestURI("/mycontext/j_acegi_security_check;jsessionid=I8MIONOSTHOR");
117 assertTrue(filter.requiresAuthentication(request, response));
118 }
119
120 public void testDoFilterWithNonHttpServletRequestDetected()
121 throws Exception {
122 AbstractProcessingFilter filter = new MockAbstractProcessingFilter();
123
124 try {
125 filter.doFilter(null, new MockHttpServletResponse(), new MockFilterChain());
126 fail("Should have thrown ServletException");
127 } catch (ServletException expected) {
128 assertEquals("Can only process HttpServletRequest", expected.getMessage());
129 }
130 }
131
132 public void testDoFilterWithNonHttpServletResponseDetected()
133 throws Exception {
134 AbstractProcessingFilter filter = new MockAbstractProcessingFilter();
135
136 try {
137 filter.doFilter(new MockHttpServletRequest(null, null), null, new MockFilterChain());
138 fail("Should have thrown ServletException");
139 } catch (ServletException expected) {
140 assertEquals("Can only process HttpServletResponse", expected.getMessage());
141 }
142 }
143
144 public void testFailedAuthenticationRedirectsAppropriately()
145 throws Exception {
146
147 MockHttpServletRequest request = createMockRequest();
148
149
150 MockFilterConfig config = new MockFilterConfig(null, null);
151
152
153 MockFilterChain chain = new MockFilterChain(false);
154 MockHttpServletResponse response = new MockHttpServletResponse();
155
156
157 MockAbstractProcessingFilter filter = new MockAbstractProcessingFilter(false);
158 filter.setAuthenticationFailureUrl("/failed.jsp");
159
160
161 executeFilterInContainerSimulator(config, filter, request, response, chain);
162
163 assertEquals("/mycontext/failed.jsp", response.getRedirectedUrl());
164 assertNull(SecurityContextHolder.getContext().getAuthentication());
165
166
167 filter = new MockAbstractProcessingFilter(new AccountExpiredException("You're account is expired"));
168 filter.setAuthenticationFailureUrl("/failed.jsp");
169
170 Properties exceptionMappings = filter.getExceptionMappings();
171 exceptionMappings.setProperty(AccountExpiredException.class.getName(), "/accountExpired.jsp");
172 filter.setExceptionMappings(exceptionMappings);
173 response = new MockHttpServletResponse();
174
175
176 executeFilterInContainerSimulator(config, filter, request, response, chain);
177
178 assertEquals("/mycontext/accountExpired.jsp", response.getRedirectedUrl());
179 assertNull(SecurityContextHolder.getContext().getAuthentication());
180 assertEquals(8*1024, response.getBufferSize());
181 }
182
183 public void testFilterProcessesUrlVariationsRespected()
184 throws Exception {
185
186 MockHttpServletRequest request = createMockRequest();
187 request.setServletPath("/j_OTHER_LOCATION");
188 request.setRequestURI("/mycontext/j_OTHER_LOCATION");
189
190
191 MockFilterConfig config = new MockFilterConfig(null, null);
192
193
194 MockFilterChain chain = new MockFilterChain(false);
195 MockHttpServletResponse response = new MockHttpServletResponse();
196
197
198 MockAbstractProcessingFilter filter = new MockAbstractProcessingFilter(true);
199 filter.setFilterProcessesUrl("/j_OTHER_LOCATION");
200 filter.setDefaultTargetUrl("/logged_in.jsp");
201
202
203 executeFilterInContainerSimulator(config, filter, request, response, chain);
204 assertEquals("/mycontext/logged_in.jsp", response.getRedirectedUrl());
205 assertNotNull(SecurityContextHolder.getContext().getAuthentication());
206 assertEquals("test", SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());
207 assertEquals(8*1024, response.getBufferSize());
208 }
209
210 public void testGettersSetters() {
211 AbstractProcessingFilter filter = new MockAbstractProcessingFilter();
212 assertNotNull(filter.getRememberMeServices());
213 filter.setRememberMeServices(new TokenBasedRememberMeServices());
214 assertEquals(TokenBasedRememberMeServices.class, filter.getRememberMeServices().getClass());
215
216 filter.setAuthenticationFailureUrl("/x");
217 assertEquals("/x", filter.getAuthenticationFailureUrl());
218
219 filter.setAuthenticationManager(new MockAuthenticationManager());
220 assertTrue(filter.getAuthenticationManager() != null);
221
222 filter.setDefaultTargetUrl("/default");
223 assertEquals("/default", filter.getDefaultTargetUrl());
224
225 filter.setFilterProcessesUrl("/p");
226 assertEquals("/p", filter.getFilterProcessesUrl());
227
228 filter.setAuthenticationFailureUrl("/fail");
229 assertEquals("/fail", filter.getAuthenticationFailureUrl());
230 }
231
232 public void testDefaultUrlMuststartWithSlashOrHttpScheme() {
233 AbstractProcessingFilter filter = new MockAbstractProcessingFilter();
234
235 filter.setDefaultTargetUrl("/acceptableRelativeUrl");
236 filter.setDefaultTargetUrl("http://some.site.org/index.html");
237 filter.setDefaultTargetUrl("https://some.site.org/index.html");
238
239 try {
240 filter.setDefaultTargetUrl("missingSlash");
241 fail("Shouldn't accept default target without leading slash");
242 } catch (IllegalArgumentException expected) {}
243 }
244
245 public void testIgnoresAnyServletPathOtherThanFilterProcessesUrl()
246 throws Exception {
247
248 MockHttpServletRequest request = createMockRequest();
249 request.setServletPath("/some.file.html");
250 request.setRequestURI("/mycontext/some.file.html");
251
252
253 MockFilterConfig config = new MockFilterConfig(null, null);
254
255
256 MockFilterChain chain = new MockFilterChain(true);
257 MockHttpServletResponse response = new MockHttpServletResponse();
258
259
260 MockAbstractProcessingFilter filter = new MockAbstractProcessingFilter(false);
261
262
263 executeFilterInContainerSimulator(config, filter, request, response, chain);
264 }
265
266 public void testNormalOperationWithDefaultFilterProcessesUrl()
267 throws Exception {
268
269 MockHttpServletRequest request = createMockRequest();
270
271
272 MockFilterConfig config = new MockFilterConfig(null, null);
273
274
275 MockFilterChain chain = new MockFilterChain(false);
276 MockHttpServletResponse response = new MockHttpServletResponse();
277
278
279 MockAbstractProcessingFilter filter = new MockAbstractProcessingFilter(true);
280 filter.setFilterProcessesUrl("/j_mock_post");
281 filter.setDefaultTargetUrl("/logged_in.jsp");
282 filter.setAuthenticationFailureUrl("/failure.jsp");
283 filter.setAuthenticationManager(new MockAuthenticationManager(true));
284 filter.afterPropertiesSet();
285
286
287 executeFilterInContainerSimulator(config, filter, request, response, chain);
288 assertEquals("/mycontext/logged_in.jsp", response.getRedirectedUrl());
289 assertNotNull(SecurityContextHolder.getContext().getAuthentication());
290 assertEquals("test", SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());
291 assertEquals(8*1024, response.getBufferSize());
292 }
293
294 public void testStartupDetectsInvalidAuthenticationFailureUrl()
295 throws Exception {
296 AbstractProcessingFilter filter = new MockAbstractProcessingFilter();
297 filter.setAuthenticationManager(new MockAuthenticationManager());
298 filter.setDefaultTargetUrl("/");
299 filter.setFilterProcessesUrl("/j_acegi_security_check");
300
301 try {
302 filter.afterPropertiesSet();
303 fail("Should have thrown IllegalArgumentException");
304 } catch (IllegalArgumentException expected) {
305 assertEquals("authenticationFailureUrl must be specified", expected.getMessage());
306 }
307 }
308
309 public void testStartupDetectsInvalidAuthenticationManager()
310 throws Exception {
311 AbstractProcessingFilter filter = new MockAbstractProcessingFilter();
312 filter.setAuthenticationFailureUrl("/failed.jsp");
313 filter.setDefaultTargetUrl("/");
314 filter.setFilterProcessesUrl("/j_acegi_security_check");
315
316 try {
317 filter.afterPropertiesSet();
318 fail("Should have thrown IllegalArgumentException");
319 } catch (IllegalArgumentException expected) {
320 assertEquals("authenticationManager must be specified", expected.getMessage());
321 }
322 }
323
324 public void testStartupDetectsInvalidDefaultTargetUrl()
325 throws Exception {
326 AbstractProcessingFilter filter = new MockAbstractProcessingFilter();
327 filter.setAuthenticationFailureUrl("/failed.jsp");
328 filter.setAuthenticationManager(new MockAuthenticationManager());
329 filter.setFilterProcessesUrl("/j_acegi_security_check");
330
331 try {
332 filter.afterPropertiesSet();
333 fail("Should have thrown IllegalArgumentException");
334 } catch (IllegalArgumentException expected) {
335 assertEquals("defaultTargetUrl must be specified", expected.getMessage());
336 }
337 }
338
339 public void testStartupDetectsInvalidFilterProcessesUrl()
340 throws Exception {
341 AbstractProcessingFilter filter = new MockAbstractProcessingFilter();
342 filter.setAuthenticationFailureUrl("/failed.jsp");
343 filter.setAuthenticationManager(new MockAuthenticationManager());
344 filter.setDefaultTargetUrl("/");
345 filter.setFilterProcessesUrl(null);
346
347 try {
348 filter.afterPropertiesSet();
349 fail("Should have thrown IllegalArgumentException");
350 } catch (IllegalArgumentException expected) {
351 assertEquals("filterProcessesUrl must be specified", expected.getMessage());
352 }
353 }
354
355 public void testSuccessLoginThenFailureLoginResultsInSessionLosingToken()
356 throws Exception {
357
358 MockHttpServletRequest request = createMockRequest();
359
360
361 MockFilterConfig config = new MockFilterConfig(null, null);
362
363
364 MockFilterChain chain = new MockFilterChain(false);
365 MockHttpServletResponse response = new MockHttpServletResponse();
366
367
368 MockAbstractProcessingFilter filter = new MockAbstractProcessingFilter(true);
369 filter.setFilterProcessesUrl("/j_mock_post");
370 filter.setDefaultTargetUrl("/logged_in.jsp");
371
372
373 executeFilterInContainerSimulator(config, filter, request, response, chain);
374 assertEquals("/mycontext/logged_in.jsp", response.getRedirectedUrl());
375 assertNotNull(SecurityContextHolder.getContext().getAuthentication());
376 assertEquals("test", SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());
377 assertEquals(8*1024, response.getBufferSize());
378
379
380
381
382 chain = new MockFilterChain(false);
383 response = new MockHttpServletResponse();
384
385
386 filter = new MockAbstractProcessingFilter(false);
387 filter.setFilterProcessesUrl("/j_mock_post");
388 filter.setAuthenticationFailureUrl("/failed.jsp");
389
390
391 executeFilterInContainerSimulator(config, filter, request, response, chain);
392 assertNull(SecurityContextHolder.getContext().getAuthentication());
393 }
394
395 public void testSuccessfulAuthenticationButWithAlwaysUseDefaultTargetUrlCausesRedirectToDefaultTargetUrl()
396 throws Exception {
397
398 MockHttpServletRequest request = createMockRequest();
399 request.getSession().setAttribute(AbstractProcessingFilter.ACEGI_SAVED_REQUEST_KEY, makeSavedRequestForUrl());
400
401
402 MockFilterConfig config = new MockFilterConfig(null, null);
403
404
405 MockFilterChain chain = new MockFilterChain(true);
406 MockHttpServletResponse response = new MockHttpServletResponse();
407
408
409 MockAbstractProcessingFilter filter = new MockAbstractProcessingFilter(true);
410 filter.setFilterProcessesUrl("/j_mock_post");
411 filter.setDefaultTargetUrl("/foobar");
412 assertFalse(filter.isAlwaysUseDefaultTargetUrl());
413 filter.setAlwaysUseDefaultTargetUrl(true);
414 assertTrue(filter.isAlwaysUseDefaultTargetUrl());
415
416
417 executeFilterInContainerSimulator(config, filter, request, response, chain);
418 assertEquals("/mycontext/foobar", response.getRedirectedUrl());
419 assertNotNull(SecurityContextHolder.getContext().getAuthentication());
420 }
421
422 public void testSuccessfulAuthenticationCausesRedirectToSessionSpecifiedUrl()
423 throws Exception {
424
425 MockHttpServletRequest request = createMockRequest();
426 request.getSession().setAttribute(AbstractProcessingFilter.ACEGI_SAVED_REQUEST_KEY, makeSavedRequestForUrl());
427
428
429 MockFilterConfig config = new MockFilterConfig(null, null);
430
431
432 MockFilterChain chain = new MockFilterChain(true);
433 MockHttpServletResponse response = new MockHttpServletResponse();
434
435
436 MockAbstractProcessingFilter filter = new MockAbstractProcessingFilter(true);
437 filter.setFilterProcessesUrl("/j_mock_post");
438
439
440 executeFilterInContainerSimulator(config, filter, request, response, chain);
441 assertEquals(makeSavedRequestForUrl().getFullRequestUrl(), response.getRedirectedUrl());
442 assertNotNull(SecurityContextHolder.getContext().getAuthentication());
443 assertEquals(8*1024, response.getBufferSize());
444 }
445
446
447
448
449 public void testFullDefaultTargetUrlDoesNotHaveContextPathPrepended() throws Exception {
450 MockHttpServletRequest request = createMockRequest();
451 MockFilterConfig config = new MockFilterConfig(null, null);
452
453 MockFilterChain chain = new MockFilterChain(true);
454 MockHttpServletResponse response = new MockHttpServletResponse();
455
456
457 MockAbstractProcessingFilter filter = new MockAbstractProcessingFilter(true);
458 filter.setFilterProcessesUrl("/j_mock_post");
459 filter.setDefaultTargetUrl("http://monkeymachine.co.uk/");
460 filter.setAlwaysUseDefaultTargetUrl(true);
461
462 executeFilterInContainerSimulator(config, filter, request, response, chain);
463 assertEquals("http://monkeymachine.co.uk/", response.getRedirectedUrl());
464 assertNotNull(SecurityContextHolder.getContext().getAuthentication());
465 }
466
467
468
469 private class MockAbstractProcessingFilter extends AbstractProcessingFilter {
470 private AuthenticationException exceptionToThrow;
471 private boolean grantAccess;
472
473 public MockAbstractProcessingFilter(boolean grantAccess) {
474 this.grantAccess = grantAccess;
475 this.exceptionToThrow = new BadCredentialsException("Mock requested to do so");
476 }
477
478 public MockAbstractProcessingFilter(AuthenticationException exceptionToThrow) {
479 this.grantAccess = false;
480 this.exceptionToThrow = exceptionToThrow;
481 }
482
483 private MockAbstractProcessingFilter() {
484 super();
485 }
486
487 public Authentication attemptAuthentication(HttpServletRequest request)
488 throws AuthenticationException {
489 if (grantAccess) {
490 return new UsernamePasswordAuthenticationToken("test", "test",
491 new GrantedAuthority[] {new GrantedAuthorityImpl("TEST")});
492 } else {
493 throw exceptionToThrow;
494 }
495 }
496
497 public String getDefaultFilterProcessesUrl() {
498 return "/j_mock_post";
499 }
500
501 public void init(FilterConfig arg0) throws ServletException {}
502
503 public boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
504 return super.requiresAuthentication(request, response);
505 }
506 }
507
508 private class MockFilterChain implements FilterChain {
509 private boolean expectToProceed;
510
511 public MockFilterChain(boolean expectToProceed) {
512 this.expectToProceed = expectToProceed;
513 }
514
515 private MockFilterChain() {
516 super();
517 }
518
519 public void doFilter(ServletRequest request, ServletResponse response)
520 throws IOException, ServletException {
521 if (expectToProceed) {
522 assertTrue(true);
523 } else {
524 fail("Did not expect filter chain to proceed");
525 }
526 }
527 }
528 }