1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.acegisecurity.intercept.method.aopalliance;
17
18 import java.lang.reflect.Method;
19 import java.util.Iterator;
20
21 import junit.framework.TestCase;
22
23 import org.acegisecurity.AccessDecisionManager;
24 import org.acegisecurity.AccessDeniedException;
25 import org.acegisecurity.AfterInvocationManager;
26 import org.acegisecurity.Authentication;
27 import org.acegisecurity.AuthenticationCredentialsNotFoundException;
28 import org.acegisecurity.AuthenticationException;
29 import org.acegisecurity.ConfigAttribute;
30 import org.acegisecurity.ConfigAttributeDefinition;
31 import org.acegisecurity.GrantedAuthority;
32 import org.acegisecurity.GrantedAuthorityImpl;
33 import org.acegisecurity.ITargetObject;
34 import org.acegisecurity.MockAccessDecisionManager;
35 import org.acegisecurity.MockAfterInvocationManager;
36 import org.acegisecurity.MockAuthenticationManager;
37 import org.acegisecurity.MockRunAsManager;
38 import org.acegisecurity.RunAsManager;
39 import org.acegisecurity.context.SecurityContextHolder;
40 import org.acegisecurity.intercept.method.AbstractMethodDefinitionSource;
41 import org.acegisecurity.intercept.method.MockMethodDefinitionSource;
42 import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
43 import org.acegisecurity.runas.RunAsManagerImpl;
44 import org.springframework.context.ApplicationContext;
45 import org.springframework.context.support.ClassPathXmlApplicationContext;
46
47
48 /***
49 * Tests {@link MethodSecurityInterceptor}.
50 *
51 * @author Ben Alex
52 * @version $Id: MethodSecurityInterceptorTests.java,v 1.12 2005/11/30 01:23:36 benalex Exp $
53 */
54 public class MethodSecurityInterceptorTests extends TestCase {
55
56
57 public MethodSecurityInterceptorTests() {
58 super();
59 }
60
61 public MethodSecurityInterceptorTests(String arg0) {
62 super(arg0);
63 }
64
65
66
67 public final void setUp() throws Exception {
68 super.setUp();
69 SecurityContextHolder.getContext().setAuthentication(null);
70 }
71
72 public static void main(String[] args) {
73 junit.textui.TestRunner.run(MethodSecurityInterceptorTests.class);
74 }
75
76 public void testCallingAPublicMethodFacadeWillNotRepeatSecurityChecksWhenPassedToTheSecuredMethodItFronts()
77 throws Exception {
78 ITargetObject target = makeInterceptedTarget();
79 String result = target.publicMakeLowerCase("HELLO");
80 assertEquals("hello Authentication empty", result);
81 }
82
83 public void testCallingAPublicMethodWhenPresentingAnAuthenticationObjectWillNotChangeItsIsAuthenticatedProperty()
84 throws Exception {
85 UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test",
86 "Password");
87 assertTrue(!token.isAuthenticated());
88 SecurityContextHolder.getContext().setAuthentication(token);
89
90
91 ITargetObject target = makeInterceptedTarget();
92 String result = target.publicMakeLowerCase("HELLO");
93 assertEquals("hello org.acegisecurity.providers.UsernamePasswordAuthenticationToken false",
94 result);
95 }
96
97 public void testDeniesWhenAppropriate() throws Exception {
98 UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test",
99 "Password",
100 new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_NO_BENEFIT_TO_THIS_GRANTED_AUTHORITY")});
101 SecurityContextHolder.getContext().setAuthentication(token);
102
103 ITargetObject target = makeInterceptedTarget();
104
105 try {
106 target.makeUpperCase("HELLO");
107 fail("Should have thrown AccessDeniedException");
108 } catch (AccessDeniedException expected) {
109 assertTrue(true);
110 }
111 }
112
113 public void testGetters() {
114 MockAccessDecisionManager accessDecision = new MockAccessDecisionManager();
115 MockRunAsManager runAs = new MockRunAsManager();
116 MockAuthenticationManager authManager = new MockAuthenticationManager();
117 MockMethodDefinitionSource methodSource = new MockMethodDefinitionSource(false,
118 true);
119 MockAfterInvocationManager afterInvocation = new MockAfterInvocationManager();
120
121 MethodSecurityInterceptor si = new MethodSecurityInterceptor();
122 si.setAccessDecisionManager(accessDecision);
123 si.setRunAsManager(runAs);
124 si.setAuthenticationManager(authManager);
125 si.setObjectDefinitionSource(methodSource);
126 si.setAfterInvocationManager(afterInvocation);
127
128 assertEquals(accessDecision, si.getAccessDecisionManager());
129 assertEquals(runAs, si.getRunAsManager());
130 assertEquals(authManager, si.getAuthenticationManager());
131 assertEquals(methodSource, si.getObjectDefinitionSource());
132 assertEquals(afterInvocation, si.getAfterInvocationManager());
133 }
134
135 public void testMethodCallWithRunAsReplacement() throws Exception {
136 UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test",
137 "Password",
138 new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_UPPER")});
139 SecurityContextHolder.getContext().setAuthentication(token);
140
141 ITargetObject target = makeInterceptedTarget();
142 String result = target.makeUpperCase("hello");
143 assertEquals("HELLO org.acegisecurity.MockRunAsAuthenticationToken true",
144 result);
145 }
146
147 public void testMethodCallWithoutRunAsReplacement()
148 throws Exception {
149 UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test",
150 "Password",
151 new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_LOWER")});
152 assertTrue(token.isAuthenticated());
153 SecurityContextHolder.getContext().setAuthentication(token);
154
155 ITargetObject target = makeInterceptedTargetWithoutAnAfterInvocationManager();
156 String result = target.makeLowerCase("HELLO");
157
158
159 assertEquals("hello org.acegisecurity.providers.UsernamePasswordAuthenticationToken true",
160 result);
161 }
162
163 public void testRejectionOfEmptySecurityContext() throws Exception {
164 ITargetObject target = makeInterceptedTarget();
165
166 try {
167 target.makeUpperCase("hello");
168 fail(
169 "Should have thrown AuthenticationCredentialsNotFoundException");
170 } catch (AuthenticationCredentialsNotFoundException expected) {
171 assertTrue(true);
172 }
173 }
174
175 public void testRejectsAccessDecisionManagersThatDoNotSupportMethodInvocation()
176 throws Exception {
177 MethodSecurityInterceptor si = new MethodSecurityInterceptor();
178 si.setAccessDecisionManager(new MockAccessDecisionManagerWhichOnlySupportsStrings());
179 si.setAuthenticationManager(new MockAuthenticationManager());
180 si.setObjectDefinitionSource(new MockMethodDefinitionSource(false, true));
181 si.setRunAsManager(new MockRunAsManager());
182
183 try {
184 si.afterPropertiesSet();
185 fail("Should have thrown IllegalArgumentException");
186 } catch (IllegalArgumentException expected) {
187 assertEquals("AccessDecisionManager does not support secure object class: interface org.aopalliance.intercept.MethodInvocation",
188 expected.getMessage());
189 }
190 }
191
192 public void testRejectsCallsWhenAuthenticationIsIncorrect()
193 throws Exception {
194 UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test",
195 "Password");
196 assertTrue(!token.isAuthenticated());
197 SecurityContextHolder.getContext().setAuthentication(token);
198
199
200 ITargetObject target = makeInterceptedTargetRejectsAuthentication();
201
202 try {
203 target.makeLowerCase("HELLO");
204 fail("Should have thrown AuthenticationException");
205 } catch (AuthenticationException expected) {
206 assertTrue(true);
207 }
208 }
209
210 public void testRejectsCallsWhenObjectDefinitionSourceDoesNotSupportObject()
211 throws Throwable {
212 MethodSecurityInterceptor interceptor = new MethodSecurityInterceptor();
213 interceptor.setObjectDefinitionSource(new MockObjectDefinitionSourceWhichOnlySupportsStrings());
214 interceptor.setAccessDecisionManager(new MockAccessDecisionManager());
215 interceptor.setAuthenticationManager(new MockAuthenticationManager());
216 interceptor.setRunAsManager(new MockRunAsManager());
217
218 try {
219 interceptor.afterPropertiesSet();
220 fail("Should have thrown IllegalArgumentException");
221 } catch (IllegalArgumentException expected) {
222 assertEquals("ObjectDefinitionSource does not support secure object class: interface org.aopalliance.intercept.MethodInvocation",
223 expected.getMessage());
224 }
225 }
226
227 public void testRejectsCallsWhenObjectIsNull() throws Throwable {
228 MethodSecurityInterceptor interceptor = new MethodSecurityInterceptor();
229
230 try {
231 interceptor.invoke(null);
232 fail("Should have thrown IllegalArgumentException");
233 } catch (IllegalArgumentException expected) {
234 assertEquals("Object was null", expected.getMessage());
235 }
236 }
237
238 public void testRejectsRunAsManagersThatDoNotSupportMethodInvocation()
239 throws Exception {
240 MethodSecurityInterceptor si = new MethodSecurityInterceptor();
241 si.setAccessDecisionManager(new MockAccessDecisionManager());
242 si.setAuthenticationManager(new MockAuthenticationManager());
243 si.setObjectDefinitionSource(new MockMethodDefinitionSource(false, true));
244 si.setRunAsManager(new MockRunAsManagerWhichOnlySupportsStrings());
245 si.setAfterInvocationManager(new MockAfterInvocationManager());
246
247 try {
248 si.afterPropertiesSet();
249 fail("Should have thrown IllegalArgumentException");
250 } catch (IllegalArgumentException expected) {
251 assertEquals("RunAsManager does not support secure object class: interface org.aopalliance.intercept.MethodInvocation",
252 expected.getMessage());
253 }
254 }
255
256 public void testStartupCheckForAccessDecisionManager()
257 throws Exception {
258 MethodSecurityInterceptor si = new MethodSecurityInterceptor();
259 si.setRunAsManager(new MockRunAsManager());
260 si.setAuthenticationManager(new MockAuthenticationManager());
261 si.setAfterInvocationManager(new MockAfterInvocationManager());
262
263 si.setObjectDefinitionSource(new MockMethodDefinitionSource(false, true));
264
265 try {
266 si.afterPropertiesSet();
267 fail("Should have thrown IllegalArgumentException");
268 } catch (IllegalArgumentException expected) {
269 assertEquals("An AccessDecisionManager is required",
270 expected.getMessage());
271 }
272 }
273
274 public void testStartupCheckForAuthenticationManager()
275 throws Exception {
276 MethodSecurityInterceptor si = new MethodSecurityInterceptor();
277 si.setAccessDecisionManager(new MockAccessDecisionManager());
278 si.setRunAsManager(new MockRunAsManager());
279 si.setAfterInvocationManager(new MockAfterInvocationManager());
280
281 si.setObjectDefinitionSource(new MockMethodDefinitionSource(false, true));
282
283 try {
284 si.afterPropertiesSet();
285 fail("Should have thrown IllegalArgumentException");
286 } catch (IllegalArgumentException expected) {
287 assertEquals("An AuthenticationManager is required",
288 expected.getMessage());
289 }
290 }
291
292 public void testStartupCheckForMethodDefinitionSource()
293 throws Exception {
294 MethodSecurityInterceptor si = new MethodSecurityInterceptor();
295 si.setAccessDecisionManager(new MockAccessDecisionManager());
296 si.setAuthenticationManager(new MockAuthenticationManager());
297
298 try {
299 si.afterPropertiesSet();
300 fail("Should have thrown IllegalArgumentException");
301 } catch (IllegalArgumentException expected) {
302 assertEquals("An ObjectDefinitionSource is required",
303 expected.getMessage());
304 }
305 }
306
307 public void testStartupCheckForRunAsManager() throws Exception {
308 MethodSecurityInterceptor si = new MethodSecurityInterceptor();
309 si.setAccessDecisionManager(new MockAccessDecisionManager());
310 si.setAuthenticationManager(new MockAuthenticationManager());
311 si.setRunAsManager(null);
312
313 si.setObjectDefinitionSource(new MockMethodDefinitionSource(false, true));
314
315 try {
316 si.afterPropertiesSet();
317 fail("Should have thrown IllegalArgumentException");
318 } catch (IllegalArgumentException expected) {
319 assertEquals("A RunAsManager is required", expected.getMessage());
320 }
321 }
322
323 public void testStartupCheckForValidAfterInvocationManager()
324 throws Exception {
325 MethodSecurityInterceptor si = new MethodSecurityInterceptor();
326 si.setRunAsManager(new MockRunAsManager());
327 si.setAuthenticationManager(new MockAuthenticationManager());
328 si.setAfterInvocationManager(new MockAfterInvocationManagerWhichOnlySupportsStrings());
329 si.setAccessDecisionManager(new MockAccessDecisionManager());
330 si.setObjectDefinitionSource(new MockMethodDefinitionSource(false, true));
331
332 try {
333 si.afterPropertiesSet();
334 fail("Should have thrown IllegalArgumentException");
335 } catch (IllegalArgumentException expected) {
336 assertTrue(expected.getMessage().startsWith("AfterInvocationManager does not support secure object class:"));
337 }
338 }
339
340 public void testValidationFailsIfInvalidAttributePresented()
341 throws Exception {
342 MethodSecurityInterceptor si = new MethodSecurityInterceptor();
343 si.setAccessDecisionManager(new MockAccessDecisionManager());
344 si.setAuthenticationManager(new MockAuthenticationManager());
345 si.setRunAsManager(new RunAsManagerImpl());
346
347 assertTrue(si.isValidateConfigAttributes());
348 si.setObjectDefinitionSource(new MockMethodDefinitionSource(true, true));
349
350 try {
351 si.afterPropertiesSet();
352 fail("Should have thrown IllegalArgumentException");
353 } catch (IllegalArgumentException expected) {
354 assertEquals("Unsupported configuration attributes: [ANOTHER_INVALID, INVALID_ATTRIBUTE]",
355 expected.getMessage());
356 }
357 }
358
359 public void testValidationNotAttemptedIfIsValidateConfigAttributesSetToFalse()
360 throws Exception {
361 MethodSecurityInterceptor si = new MethodSecurityInterceptor();
362 si.setAccessDecisionManager(new MockAccessDecisionManager());
363 si.setAuthenticationManager(new MockAuthenticationManager());
364
365 assertTrue(si.isValidateConfigAttributes());
366 si.setValidateConfigAttributes(false);
367 assertTrue(!si.isValidateConfigAttributes());
368
369 si.setObjectDefinitionSource(new MockMethodDefinitionSource(true, true));
370 si.afterPropertiesSet();
371 assertTrue(true);
372 }
373
374 public void testValidationNotAttemptedIfMethodDefinitionSourceCannotReturnIterator()
375 throws Exception {
376 MethodSecurityInterceptor si = new MethodSecurityInterceptor();
377 si.setAccessDecisionManager(new MockAccessDecisionManager());
378 si.setRunAsManager(new MockRunAsManager());
379 si.setAuthenticationManager(new MockAuthenticationManager());
380
381 assertTrue(si.isValidateConfigAttributes());
382 si.setObjectDefinitionSource(new MockMethodDefinitionSource(true, false));
383 si.afterPropertiesSet();
384 assertTrue(true);
385 }
386
387 private ITargetObject makeInterceptedTarget() {
388 ApplicationContext context = new ClassPathXmlApplicationContext(
389 "org/acegisecurity/intercept/method/aopalliance/applicationContext.xml");
390
391 return (ITargetObject) context.getBean("target");
392 }
393
394 private ITargetObject makeInterceptedTargetRejectsAuthentication() {
395 ApplicationContext context = new ClassPathXmlApplicationContext(
396 "org/acegisecurity/intercept/method/aopalliance/applicationContext.xml");
397
398 MockAuthenticationManager authenticationManager = new MockAuthenticationManager(false);
399 MethodSecurityInterceptor si = (MethodSecurityInterceptor) context
400 .getBean("securityInterceptor");
401 si.setAuthenticationManager(authenticationManager);
402
403 return (ITargetObject) context.getBean("target");
404 }
405
406 private ITargetObject makeInterceptedTargetWithoutAnAfterInvocationManager() {
407 ApplicationContext context = new ClassPathXmlApplicationContext(
408 "org/acegisecurity/intercept/method/aopalliance/applicationContext.xml");
409
410 MethodSecurityInterceptor si = (MethodSecurityInterceptor) context
411 .getBean("securityInterceptor");
412 si.setAfterInvocationManager(null);
413
414 return (ITargetObject) context.getBean("target");
415 }
416
417
418
419 private class MockAccessDecisionManagerWhichOnlySupportsStrings
420 implements AccessDecisionManager {
421 public void decide(Authentication authentication, Object object,
422 ConfigAttributeDefinition config) throws AccessDeniedException {
423 throw new UnsupportedOperationException(
424 "mock method not implemented");
425 }
426
427 public boolean supports(Class clazz) {
428 if (String.class.isAssignableFrom(clazz)) {
429 return true;
430 } else {
431 return false;
432 }
433 }
434
435 public boolean supports(ConfigAttribute attribute) {
436 return true;
437 }
438 }
439
440 private class MockAfterInvocationManagerWhichOnlySupportsStrings
441 implements AfterInvocationManager {
442 public Object decide(Authentication authentication, Object object,
443 ConfigAttributeDefinition config, Object returnedObject)
444 throws AccessDeniedException {
445 throw new UnsupportedOperationException(
446 "mock method not implemented");
447 }
448
449 public boolean supports(Class clazz) {
450 if (String.class.isAssignableFrom(clazz)) {
451 return true;
452 } else {
453 return false;
454 }
455 }
456
457 public boolean supports(ConfigAttribute attribute) {
458 return true;
459 }
460 }
461
462 private class MockObjectDefinitionSourceWhichOnlySupportsStrings
463 extends AbstractMethodDefinitionSource {
464 public Iterator getConfigAttributeDefinitions() {
465 return null;
466 }
467
468 public boolean supports(Class clazz) {
469 if (String.class.isAssignableFrom(clazz)) {
470 return true;
471 } else {
472 return false;
473 }
474 }
475
476 protected ConfigAttributeDefinition lookupAttributes(Method method) {
477 throw new UnsupportedOperationException(
478 "mock method not implemented");
479 }
480 }
481
482 private class MockRunAsManagerWhichOnlySupportsStrings
483 implements RunAsManager {
484 public Authentication buildRunAs(Authentication authentication,
485 Object object, ConfigAttributeDefinition config) {
486 throw new UnsupportedOperationException(
487 "mock method not implemented");
488 }
489
490 public boolean supports(Class clazz) {
491 if (String.class.isAssignableFrom(clazz)) {
492 return true;
493 } else {
494 return false;
495 }
496 }
497
498 public boolean supports(ConfigAttribute attribute) {
499 return true;
500 }
501 }
502 }