001: /* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
002: *
003: * Licensed under the Apache License, Version 2.0 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at
006: *
007: * http://www.apache.org/licenses/LICENSE-2.0
008: *
009: * Unless required by applicable law or agreed to in writing, software
010: * distributed under the License is distributed on an "AS IS" BASIS,
011: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: * See the License for the specific language governing permissions and
013: * limitations under the License.
014: */
015:
016: package org.acegisecurity.vote;
017:
018: import junit.framework.TestCase;
019:
020: import org.acegisecurity.AuthorizationServiceException;
021: import org.acegisecurity.ConfigAttributeDefinition;
022: import org.acegisecurity.MockAclManager;
023: import org.acegisecurity.SecurityConfig;
024: import org.acegisecurity.acl.AclEntry;
025: import org.acegisecurity.acl.AclManager;
026: import org.acegisecurity.acl.basic.MockAclObjectIdentity;
027: import org.acegisecurity.acl.basic.SimpleAclEntry;
028: import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
029: import org.acegisecurity.util.SimpleMethodInvocation;
030: import org.aopalliance.intercept.MethodInvocation;
031: import org.aspectj.lang.JoinPoint;
032:
033: import java.lang.reflect.Method;
034:
035: /**
036: * Tests {@link BasicAclEntryVoter}.
037: *
038: * @author Ben Alex
039: * @version $Id: BasicAclEntryVoterTests.java 1597 2006-08-22 17:57:18Z carlossg $
040: */
041: public class BasicAclEntryVoterTests extends TestCase {
042: //~ Constructors ===================================================================================================
043:
044: public BasicAclEntryVoterTests() {
045: super ();
046: }
047:
048: public BasicAclEntryVoterTests(String arg0) {
049: super (arg0);
050: }
051:
052: //~ Methods ========================================================================================================
053:
054: private MethodInvocation getMethodInvocation(
055: SomeDomainObject domainObject) throws Exception {
056: Class clazz = SomeDomainObjectManager.class;
057: Method method = clazz.getMethod("someServiceMethod",
058: new Class[] { SomeDomainObject.class });
059:
060: return new SimpleMethodInvocation(method,
061: new Object[] { domainObject });
062: }
063:
064: public static void main(String[] args) {
065: junit.textui.TestRunner.run(BasicAclEntryVoterTests.class);
066: }
067:
068: public final void setUp() throws Exception {
069: super .setUp();
070: }
071:
072: public void testNormalOperation() throws Exception {
073: // Setup a domain object subject of this test
074: SomeDomainObject domainObject = new SomeDomainObject("foo");
075:
076: // Setup an AclManager
077: AclManager aclManager = new MockAclManager(domainObject,
078: "marissa", new AclEntry[] {
079: new MockAclEntry(),
080: new SimpleAclEntry("marissa",
081: new MockAclObjectIdentity(), null,
082: SimpleAclEntry.ADMINISTRATION),
083: new SimpleAclEntry("marissa",
084: new MockAclObjectIdentity(), null,
085: SimpleAclEntry.READ),
086: new SimpleAclEntry("marissa",
087: new MockAclObjectIdentity(), null,
088: SimpleAclEntry.DELETE) });
089:
090: // Wire up a voter
091: BasicAclEntryVoter voter = new BasicAclEntryVoter();
092: voter.setAclManager(aclManager);
093: assertEquals(aclManager, voter.getAclManager());
094: voter.setProcessConfigAttribute("FOO_ADMIN_OR_WRITE_ACCESS");
095: assertEquals("FOO_ADMIN_OR_WRITE_ACCESS", voter
096: .getProcessConfigAttribute());
097: voter.setRequirePermission(new int[] {
098: SimpleAclEntry.ADMINISTRATION, SimpleAclEntry.WRITE });
099: assertEquals(2, voter.getRequirePermission().length);
100: voter.setProcessDomainObjectClass(SomeDomainObject.class);
101: assertEquals(SomeDomainObject.class, voter
102: .getProcessDomainObjectClass());
103: voter.afterPropertiesSet();
104:
105: // Wire up an invocation to be voted on
106: ConfigAttributeDefinition attr = new ConfigAttributeDefinition();
107: attr.addConfigAttribute(new SecurityConfig(
108: "FOO_ADMIN_OR_WRITE_ACCESS"));
109:
110: // Setup a MockMethodInvocation, so voter can retrieve domainObject
111: MethodInvocation mi = getMethodInvocation(domainObject);
112:
113: assertEquals(AccessDecisionVoter.ACCESS_GRANTED, voter
114: .vote(new UsernamePasswordAuthenticationToken(
115: "marissa", null), mi, attr));
116: }
117:
118: public void testOnlySupportsMethodInvocationAndJoinPoint() {
119: BasicAclEntryVoter voter = new BasicAclEntryVoter();
120: assertTrue(voter.supports(MethodInvocation.class));
121: assertTrue(voter.supports(JoinPoint.class));
122: assertFalse(voter.supports(String.class));
123: }
124:
125: public void testStartupRejectsMissingAclManager() throws Exception {
126: AclManager aclManager = new MockAclManager("domain1",
127: "marissa", new AclEntry[] {
128: new MockAclEntry(),
129: new SimpleAclEntry("marissa",
130: new MockAclObjectIdentity(), null,
131: SimpleAclEntry.ADMINISTRATION),
132: new SimpleAclEntry("marissa",
133: new MockAclObjectIdentity(), null,
134: SimpleAclEntry.READ),
135: new SimpleAclEntry("marissa",
136: new MockAclObjectIdentity(), null,
137: SimpleAclEntry.DELETE) });
138:
139: // Wire up a voter
140: BasicAclEntryVoter voter = new BasicAclEntryVoter();
141: voter.setProcessConfigAttribute("FOO_ADMIN_OR_WRITE_ACCESS");
142: voter.setRequirePermission(new int[] {
143: SimpleAclEntry.ADMINISTRATION, SimpleAclEntry.WRITE });
144: voter.setProcessDomainObjectClass(SomeDomainObject.class);
145:
146: try {
147: voter.afterPropertiesSet();
148: fail("Should have thrown IllegalArgumentException");
149: } catch (IllegalArgumentException expected) {
150: assertTrue(true);
151: }
152: }
153:
154: public void testStartupRejectsMissingProcessConfigAttribute()
155: throws Exception {
156: AclManager aclManager = new MockAclManager("domain1",
157: "marissa", new AclEntry[] {
158: new MockAclEntry(),
159: new SimpleAclEntry("marissa",
160: new MockAclObjectIdentity(), null,
161: SimpleAclEntry.ADMINISTRATION),
162: new SimpleAclEntry("marissa",
163: new MockAclObjectIdentity(), null,
164: SimpleAclEntry.READ),
165: new SimpleAclEntry("marissa",
166: new MockAclObjectIdentity(), null,
167: SimpleAclEntry.DELETE) });
168:
169: // Wire up a voter
170: BasicAclEntryVoter voter = new BasicAclEntryVoter();
171: voter.setAclManager(aclManager);
172: voter.setRequirePermission(new int[] {
173: SimpleAclEntry.ADMINISTRATION, SimpleAclEntry.WRITE });
174: voter.setProcessDomainObjectClass(SomeDomainObject.class);
175:
176: try {
177: voter.afterPropertiesSet();
178: fail("Should have thrown IllegalArgumentException");
179: } catch (IllegalArgumentException expected) {
180: assertTrue(true);
181: }
182: }
183:
184: public void testStartupRejectsMissingProcessDomainObjectClass()
185: throws Exception {
186: BasicAclEntryVoter voter = new BasicAclEntryVoter();
187:
188: try {
189: voter.setProcessDomainObjectClass(null);
190: fail("Should have thrown IllegalArgumentException");
191: } catch (IllegalArgumentException expected) {
192: assertTrue(true);
193: }
194: }
195:
196: public void testStartupRejectsMissingRequirePermission()
197: throws Exception {
198: AclManager aclManager = new MockAclManager("domain1",
199: "marissa", new AclEntry[] {
200: new MockAclEntry(),
201: new SimpleAclEntry("marissa",
202: new MockAclObjectIdentity(), null,
203: SimpleAclEntry.ADMINISTRATION),
204: new SimpleAclEntry("marissa",
205: new MockAclObjectIdentity(), null,
206: SimpleAclEntry.READ),
207: new SimpleAclEntry("marissa",
208: new MockAclObjectIdentity(), null,
209: SimpleAclEntry.DELETE) });
210:
211: // Wire up a voter
212: BasicAclEntryVoter voter = new BasicAclEntryVoter();
213: voter.setAclManager(aclManager);
214: voter.setProcessConfigAttribute("FOO_ADMIN_OR_WRITE_ACCESS");
215: voter.setProcessDomainObjectClass(SomeDomainObject.class);
216:
217: try {
218: voter.afterPropertiesSet();
219: fail("Should have thrown IllegalArgumentException");
220: } catch (IllegalArgumentException expected) {
221: assertTrue(true);
222: }
223: }
224:
225: public void testSupportsConfigAttribute() {
226: BasicAclEntryVoter voter = new BasicAclEntryVoter();
227: voter.setProcessConfigAttribute("foobar");
228: assertTrue(voter.supports(new SecurityConfig("foobar")));
229: }
230:
231: public void testVoterAbstainsIfDomainObjectIsNull()
232: throws Exception {
233: // Setup a domain object subject of this test
234: SomeDomainObject domainObject = new SomeDomainObject("foo");
235:
236: // Setup an AclManager
237: AclManager aclManager = new MockAclManager(domainObject,
238: "marissa", new AclEntry[] {
239: new MockAclEntry(),
240: new SimpleAclEntry("marissa",
241: new MockAclObjectIdentity(), null,
242: SimpleAclEntry.ADMINISTRATION),
243: new SimpleAclEntry("marissa",
244: new MockAclObjectIdentity(), null,
245: SimpleAclEntry.READ),
246: new SimpleAclEntry("marissa",
247: new MockAclObjectIdentity(), null,
248: SimpleAclEntry.DELETE) });
249:
250: // Wire up a voter
251: BasicAclEntryVoter voter = new BasicAclEntryVoter();
252: voter.setAclManager(aclManager);
253: voter.setProcessConfigAttribute("FOO_ADMIN_OR_WRITE_ACCESS");
254: voter.setRequirePermission(new int[] {
255: SimpleAclEntry.ADMINISTRATION, SimpleAclEntry.WRITE });
256: voter.setProcessDomainObjectClass(SomeDomainObject.class);
257: voter.afterPropertiesSet();
258:
259: // Wire up an invocation to be voted on
260: ConfigAttributeDefinition attr = new ConfigAttributeDefinition();
261: attr.addConfigAttribute(new SecurityConfig(
262: "A_DIFFERENT_ATTRIBUTE"));
263:
264: // Setup a MockMethodInvocation, so voter can retrieve domainObject
265: MethodInvocation mi = getMethodInvocation(domainObject);
266:
267: assertEquals(AccessDecisionVoter.ACCESS_ABSTAIN, voter
268: .vote(new UsernamePasswordAuthenticationToken(
269: "marissa", null), mi, attr));
270: }
271:
272: public void testVoterAbstainsIfNotMatchingConfigAttribute()
273: throws Exception {
274: // Setup a domain object subject of this test
275: SomeDomainObject domainObject = null;
276:
277: // Setup an AclManager
278: AclManager aclManager = new MockAclManager(domainObject,
279: "marissa", new AclEntry[] {
280: new MockAclEntry(),
281: new SimpleAclEntry("marissa",
282: new MockAclObjectIdentity(), null,
283: SimpleAclEntry.ADMINISTRATION),
284: new SimpleAclEntry("marissa",
285: new MockAclObjectIdentity(), null,
286: SimpleAclEntry.READ),
287: new SimpleAclEntry("marissa",
288: new MockAclObjectIdentity(), null,
289: SimpleAclEntry.DELETE) });
290:
291: // Wire up a voter
292: BasicAclEntryVoter voter = new BasicAclEntryVoter();
293: voter.setAclManager(aclManager);
294: voter.setProcessConfigAttribute("FOO_ADMIN_OR_WRITE_ACCESS");
295: voter.setRequirePermission(new int[] {
296: SimpleAclEntry.ADMINISTRATION, SimpleAclEntry.WRITE });
297: voter.setProcessDomainObjectClass(SomeDomainObject.class);
298: voter.afterPropertiesSet();
299:
300: // Wire up an invocation to be voted on
301: ConfigAttributeDefinition attr = new ConfigAttributeDefinition();
302: attr.addConfigAttribute(new SecurityConfig(
303: "FOO_ADMIN_OR_WRITE_ACCESS"));
304:
305: // Setup a MockMethodInvocation, so voter can retrieve domainObject
306: MethodInvocation mi = getMethodInvocation(domainObject);
307:
308: assertEquals(AccessDecisionVoter.ACCESS_ABSTAIN, voter
309: .vote(new UsernamePasswordAuthenticationToken(
310: "marissa", null), mi, attr));
311: }
312:
313: public void testVoterCanDenyAccessBasedOnInternalMethodOfDomainObject()
314: throws Exception {
315: // Setup a domain object subject of this test
316: SomeDomainObject domainObject = new SomeDomainObject("foo");
317:
318: // Setup an AclManager
319: AclManager aclManager = new MockAclManager(domainObject
320: .getParent(), "marissa", new AclEntry[] {
321: new MockAclEntry(),
322: new SimpleAclEntry("marissa",
323: new MockAclObjectIdentity(), null,
324: SimpleAclEntry.DELETE) });
325:
326: // Wire up a voter
327: BasicAclEntryVoter voter = new BasicAclEntryVoter();
328: voter.setAclManager(aclManager);
329: voter.setProcessConfigAttribute("FOO_ADMIN_OR_WRITE_ACCESS");
330: voter.setRequirePermission(new int[] {
331: SimpleAclEntry.ADMINISTRATION, SimpleAclEntry.WRITE });
332: voter.setProcessDomainObjectClass(SomeDomainObject.class);
333: voter.setInternalMethod("getParent");
334: voter.afterPropertiesSet();
335:
336: // Wire up an invocation to be voted on
337: ConfigAttributeDefinition attr = new ConfigAttributeDefinition();
338: attr.addConfigAttribute(new SecurityConfig(
339: "FOO_ADMIN_OR_WRITE_ACCESS"));
340:
341: // Setup a MockMethodInvocation, so voter can retrieve domainObject
342: MethodInvocation mi = getMethodInvocation(domainObject);
343:
344: assertEquals(AccessDecisionVoter.ACCESS_DENIED, voter
345: .vote(new UsernamePasswordAuthenticationToken(
346: "marissa", null), mi, attr));
347: }
348:
349: public void testVoterCanDenyAccessIfPrincipalHasNoPermissionsAtAllToDomainObject()
350: throws Exception {
351: // Setup a domain object subject of this test
352: SomeDomainObject domainObject = new SomeDomainObject("foo");
353:
354: // Setup an AclManager
355: AclManager aclManager = new MockAclManager(domainObject,
356: "marissa", new AclEntry[] {
357: new MockAclEntry(),
358: new SimpleAclEntry("marissa",
359: new MockAclObjectIdentity(), null,
360: SimpleAclEntry.DELETE) });
361:
362: // Wire up a voter
363: BasicAclEntryVoter voter = new BasicAclEntryVoter();
364: voter.setAclManager(aclManager);
365: voter.setProcessConfigAttribute("FOO_ADMIN_OR_WRITE_ACCESS");
366: voter.setRequirePermission(new int[] {
367: SimpleAclEntry.ADMINISTRATION, SimpleAclEntry.WRITE });
368: voter.setProcessDomainObjectClass(SomeDomainObject.class);
369: voter.setInternalMethod("getParent");
370: voter.afterPropertiesSet();
371:
372: // Wire up an invocation to be voted on
373: ConfigAttributeDefinition attr = new ConfigAttributeDefinition();
374: attr.addConfigAttribute(new SecurityConfig(
375: "FOO_ADMIN_OR_WRITE_ACCESS"));
376:
377: // Setup a MockMethodInvocation, so voter can retrieve domainObject
378: MethodInvocation mi = getMethodInvocation(domainObject);
379:
380: // NB: scott is the principal, not marissa
381: assertEquals(AccessDecisionVoter.ACCESS_DENIED, voter.vote(
382: new UsernamePasswordAuthenticationToken("scott", null),
383: mi, attr));
384: }
385:
386: public void testVoterCanGrantAccessBasedOnInternalMethodOfDomainObject()
387: throws Exception {
388: // Setup a domain object subject of this test
389: SomeDomainObject domainObject = new SomeDomainObject("foo");
390:
391: // Setup an AclManager
392: AclManager aclManager = new MockAclManager(domainObject
393: .getParent(), "marissa", new AclEntry[] {
394: new MockAclEntry(),
395: new SimpleAclEntry("marissa",
396: new MockAclObjectIdentity(), null,
397: SimpleAclEntry.ADMINISTRATION),
398: new SimpleAclEntry("marissa",
399: new MockAclObjectIdentity(), null,
400: SimpleAclEntry.READ),
401: new SimpleAclEntry("marissa",
402: new MockAclObjectIdentity(), null,
403: SimpleAclEntry.DELETE) });
404:
405: // Wire up a voter
406: BasicAclEntryVoter voter = new BasicAclEntryVoter();
407: voter.setAclManager(aclManager);
408: voter.setProcessConfigAttribute("FOO_ADMIN_OR_WRITE_ACCESS");
409: voter.setRequirePermission(new int[] {
410: SimpleAclEntry.ADMINISTRATION, SimpleAclEntry.WRITE });
411: voter.setProcessDomainObjectClass(SomeDomainObject.class);
412: voter.setInternalMethod("getParent");
413: assertEquals("getParent", voter.getInternalMethod());
414: voter.afterPropertiesSet();
415:
416: // Wire up an invocation to be voted on
417: ConfigAttributeDefinition attr = new ConfigAttributeDefinition();
418: attr.addConfigAttribute(new SecurityConfig(
419: "FOO_ADMIN_OR_WRITE_ACCESS"));
420:
421: // Setup a MockMethodInvocation, so voter can retrieve domainObject
422: // (well actually it will access domainObject.getParent())
423: MethodInvocation mi = getMethodInvocation(domainObject);
424:
425: assertEquals(AccessDecisionVoter.ACCESS_GRANTED, voter
426: .vote(new UsernamePasswordAuthenticationToken(
427: "marissa", null), mi, attr));
428: }
429:
430: public void testVoterThrowsExceptionIfInvalidInternalMethodOfDomainObject()
431: throws Exception {
432: // Setup a domain object subject of this test
433: SomeDomainObject domainObject = new SomeDomainObject("foo");
434:
435: // Setup an AclManager
436: AclManager aclManager = new MockAclManager(domainObject
437: .getParent(), "marissa", new AclEntry[] {
438: new MockAclEntry(),
439: new SimpleAclEntry("marissa",
440: new MockAclObjectIdentity(), null,
441: SimpleAclEntry.ADMINISTRATION),
442: new SimpleAclEntry("marissa",
443: new MockAclObjectIdentity(), null,
444: SimpleAclEntry.READ),
445: new SimpleAclEntry("marissa",
446: new MockAclObjectIdentity(), null,
447: SimpleAclEntry.DELETE) });
448:
449: // Wire up a voter
450: BasicAclEntryVoter voter = new BasicAclEntryVoter();
451: voter.setAclManager(aclManager);
452: voter.setProcessConfigAttribute("FOO_ADMIN_OR_WRITE_ACCESS");
453: voter.setRequirePermission(new int[] {
454: SimpleAclEntry.ADMINISTRATION, SimpleAclEntry.WRITE });
455: voter.setProcessDomainObjectClass(SomeDomainObject.class);
456: voter.setInternalMethod("getNonExistentParentName");
457: voter.afterPropertiesSet();
458:
459: // Wire up an invocation to be voted on
460: ConfigAttributeDefinition attr = new ConfigAttributeDefinition();
461: attr.addConfigAttribute(new SecurityConfig(
462: "FOO_ADMIN_OR_WRITE_ACCESS"));
463:
464: // Setup a MockMethodInvocation, so voter can retrieve domainObject
465: // (well actually it will access domainObject.getParent())
466: MethodInvocation mi = getMethodInvocation(domainObject);
467:
468: try {
469: voter.vote(new UsernamePasswordAuthenticationToken(
470: "marissa", null), mi, attr);
471: fail("Should have thrown AuthorizationServiceException");
472: } catch (AuthorizationServiceException expected) {
473: assertTrue(true);
474: }
475: }
476:
477: public void testVoterThrowsExceptionIfProcessDomainObjectNotFound()
478: throws Exception {
479: // Setup a domain object subject of this test
480: SomeDomainObject domainObject = new SomeDomainObject("foo");
481:
482: // Setup an AclManager
483: AclManager aclManager = new MockAclManager(domainObject
484: .getParent(), "marissa", new AclEntry[] {
485: new MockAclEntry(),
486: new SimpleAclEntry("marissa",
487: new MockAclObjectIdentity(), null,
488: SimpleAclEntry.ADMINISTRATION),
489: new SimpleAclEntry("marissa",
490: new MockAclObjectIdentity(), null,
491: SimpleAclEntry.READ),
492: new SimpleAclEntry("marissa",
493: new MockAclObjectIdentity(), null,
494: SimpleAclEntry.DELETE) });
495:
496: // Wire up a voter
497: BasicAclEntryVoter voter = new BasicAclEntryVoter();
498: voter.setAclManager(aclManager);
499: voter.setProcessConfigAttribute("FOO_ADMIN_OR_WRITE_ACCESS");
500: voter.setRequirePermission(new int[] {
501: SimpleAclEntry.ADMINISTRATION, SimpleAclEntry.WRITE });
502: voter.setProcessDomainObjectClass(SomeDomainObject.class);
503: voter.afterPropertiesSet();
504:
505: // Wire up an invocation to be voted on
506: ConfigAttributeDefinition attr = new ConfigAttributeDefinition();
507: attr.addConfigAttribute(new SecurityConfig(
508: "FOO_ADMIN_OR_WRITE_ACCESS"));
509:
510: // Setup a MockMethodInvocation that doesn't provide SomeDomainObject arg
511: Class clazz = String.class;
512: Method method = clazz.getMethod("toString", new Class[] {});
513:
514: MethodInvocation mi = new SimpleMethodInvocation(method,
515: new Object[] { domainObject });
516:
517: try {
518: voter.vote(new UsernamePasswordAuthenticationToken(
519: "marissa", null), mi, attr);
520: fail("Should have thrown AuthorizationServiceException");
521: } catch (AuthorizationServiceException expected) {
522: assertTrue(true);
523: }
524: }
525:
526: public void testSetRequirePermissionFromString() {
527: assertPermission("NOTHING", SimpleAclEntry.NOTHING);
528: assertPermission("ADMINISTRATION",
529: SimpleAclEntry.ADMINISTRATION);
530: assertPermission("READ", SimpleAclEntry.READ);
531: assertPermission("WRITE", SimpleAclEntry.WRITE);
532: assertPermission("CREATE", SimpleAclEntry.CREATE);
533: assertPermission("DELETE", SimpleAclEntry.DELETE);
534: assertPermission(new String[] { "WRITE", "CREATE" }, new int[] {
535: SimpleAclEntry.WRITE, SimpleAclEntry.CREATE });
536: }
537:
538: public void testSetRequirePermissionFromStringWrongValues() {
539: BasicAclEntryVoter voter = new BasicAclEntryVoter();
540: try {
541: voter.setRequirePermissionFromString(new String[] { "X" });
542: fail(IllegalArgumentException.class.getName()
543: + " must have been thrown.");
544: } catch (IllegalArgumentException e) {
545: // expected
546: }
547: }
548:
549: private void assertPermission(String text, int value) {
550: assertPermission(new String[] { text }, new int[] { value });
551: }
552:
553: private void assertPermission(String[] text, int[] value) {
554: BasicAclEntryVoter voter = new BasicAclEntryVoter();
555: voter.setRequirePermissionFromString(text);
556: assertEquals("Test incorreclty coded", value.length,
557: text.length);
558: assertEquals(value.length, voter.getRequirePermission().length);
559: for (int i = 0; i < value.length; i++) {
560: assertEquals(value[i], voter.getRequirePermission()[i]);
561: }
562: }
563:
564: //~ Inner Classes ==================================================================================================
565:
566: private class MockAclEntry implements AclEntry {
567: // just so AclTag iterates some different types of AclEntrys
568: }
569: }
|