1   /* Copyright 2004, 2005 Acegi Technology Pty Limited
2    *
3    * Licensed under the Apache License, Version 2.0 (the "License");
4    * you may not use this file except in compliance with the License.
5    * You may obtain a copy of the License at
6    *
7    *     http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  
16  package org.acegisecurity.acl.basic;
17  
18  import junit.framework.TestCase;
19  
20  import org.acegisecurity.Authentication;
21  import org.acegisecurity.PopulatedDatabase;
22  import org.acegisecurity.acl.AclEntry;
23  import org.acegisecurity.acl.basic.cache.BasicAclEntryHolder;
24  import org.acegisecurity.acl.basic.cache.NullAclEntryCache;
25  import org.acegisecurity.acl.basic.jdbc.JdbcDaoImpl;
26  import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
27  
28  import java.util.HashMap;
29  import java.util.Map;
30  
31  
32  /***
33   * Tests {@link BasicAclProvider}.
34   *
35   * @author Ben Alex
36   * @version $Id: BasicAclProviderTests.java,v 1.6 2005/11/17 00:56:09 benalex Exp $
37   */
38  public class BasicAclProviderTests extends TestCase {
39      //~ Static fields/initializers =============================================
40  
41      public static final String OBJECT_IDENTITY = "org.acegisecurity.acl.DomainObject";
42  
43      //~ Constructors ===========================================================
44  
45      public BasicAclProviderTests() {
46          super();
47      }
48  
49      public BasicAclProviderTests(String arg0) {
50          super(arg0);
51      }
52  
53      //~ Methods ================================================================
54  
55      public final void setUp() throws Exception {
56          super.setUp();
57      }
58  
59      public static void main(String[] args) {
60          junit.textui.TestRunner.run(BasicAclProviderTests.class);
61      }
62  
63      public void testCachingUsedProperly() throws Exception {
64          BasicAclProvider provider = new BasicAclProvider();
65          provider.setBasicAclDao(makePopulatedJdbcDao());
66  
67          MockCache cache = new MockCache();
68          provider.setBasicAclEntryCache(cache);
69  
70          assertEquals(0, cache.getGets());
71          assertEquals(0, cache.getGetsHits());
72          assertEquals(0, cache.getPuts());
73          assertEquals(0, cache.getBackingMap().size());
74  
75          Object object = new MockDomain(1); // has no parents
76          provider.getAcls(object);
77  
78          assertEquals(1, cache.getGets());
79          assertEquals(0, cache.getGetsHits());
80          assertEquals(1, cache.getPuts());
81          assertEquals(1, cache.getBackingMap().size());
82  
83          provider.getAcls(object);
84  
85          assertEquals(2, cache.getGets());
86          assertEquals(1, cache.getGetsHits());
87          assertEquals(1, cache.getPuts());
88          assertEquals(1, cache.getBackingMap().size());
89  
90          object = new MockDomain(1000); // does not exist
91  
92          provider.getAcls(object);
93  
94          assertEquals(3, cache.getGets());
95          assertEquals(1, cache.getGetsHits());
96          assertEquals(2, cache.getPuts());
97          assertEquals(2, cache.getBackingMap().size());
98  
99          provider.getAcls(object);
100 
101         assertEquals(4, cache.getGets());
102         assertEquals(2, cache.getGetsHits());
103         assertEquals(2, cache.getPuts());
104         assertEquals(2, cache.getBackingMap().size());
105 
106         provider.getAcls(object);
107 
108         assertEquals(5, cache.getGets());
109         assertEquals(3, cache.getGetsHits());
110         assertEquals(2, cache.getPuts());
111         assertEquals(2, cache.getBackingMap().size());
112     }
113 
114     public void testExceptionThrownIfUnsupportedObjectIsSubmitted()
115         throws Exception {
116         BasicAclProvider provider = new BasicAclProvider();
117         provider.setBasicAclDao(makePopulatedJdbcDao());
118 
119         // this one should NOT be supported, as it has no getId() method
120         assertFalse(provider.supports(new Integer(34)));
121 
122         // try anyway
123         try {
124             provider.getAcls(new Integer(34));
125             fail("Should have thrown IllegalArgumentException");
126         } catch (IllegalArgumentException expected) {
127             assertTrue(true);
128         }
129     }
130 
131     public void testGetAclsForInstanceNotFound() throws Exception {
132         BasicAclProvider provider = new BasicAclProvider();
133         provider.setBasicAclDao(makePopulatedJdbcDao());
134 
135         Object object = new MockDomain(546464646);
136         AclEntry[] acls = provider.getAcls(object);
137         assertNull(acls);
138     }
139 
140     public void testGetAclsForInstanceWithParentLevels()
141         throws Exception {
142         BasicAclProvider provider = new BasicAclProvider();
143         provider.setBasicAclDao(makePopulatedJdbcDao());
144 
145         Object object = new MockDomain(6);
146         AclEntry[] acls = provider.getAcls(object);
147         assertEquals(2, acls.length);
148 
149         assertEquals("scott", ((BasicAclEntry) acls[0]).getRecipient());
150         assertEquals(1, ((BasicAclEntry) acls[0]).getMask());
151         assertEquals("ROLE_SUPERVISOR", ((BasicAclEntry) acls[1]).getRecipient());
152     }
153 
154     public void testGetAclsForInstanceWithParentLevelsButNoDirectAclsAgainstInstance()
155         throws Exception {
156         BasicAclProvider provider = new BasicAclProvider();
157         provider.setBasicAclDao(makePopulatedJdbcDao());
158 
159         Object object = new MockDomain(5);
160         AclEntry[] acls = provider.getAcls(object);
161 
162         assertEquals(3, acls.length);
163 
164         assertEquals("scott", ((BasicAclEntry) acls[0]).getRecipient());
165         assertEquals(14, ((BasicAclEntry) acls[0]).getMask());
166         assertEquals("ROLE_SUPERVISOR", ((BasicAclEntry) acls[1]).getRecipient());
167         assertEquals(1, ((BasicAclEntry) acls[1]).getMask());
168         assertEquals(JdbcDaoImpl.RECIPIENT_USED_FOR_INHERITENCE_MARKER,
169             ((BasicAclEntry) acls[2]).getRecipient());
170     }
171 
172     public void testGetAclsWithAuthentication() throws Exception {
173         BasicAclProvider provider = new BasicAclProvider();
174         provider.setBasicAclDao(makePopulatedJdbcDao());
175 
176         Authentication scott = new UsernamePasswordAuthenticationToken("scott",
177                 "unused");
178 
179         Object object = new MockDomain(6);
180         AclEntry[] acls = provider.getAcls(object, scott);
181 
182         assertEquals(1, acls.length);
183         assertEquals("scott", ((BasicAclEntry) acls[0]).getRecipient());
184     }
185 
186     public void testGettersSetters() {
187         BasicAclProvider provider = new BasicAclProvider();
188         assertEquals(NullAclEntryCache.class,
189             provider.getBasicAclEntryCache().getClass());
190         assertEquals(NamedEntityObjectIdentity.class,
191             provider.getDefaultAclObjectIdentityClass());
192         assertEquals(GrantedAuthorityEffectiveAclsResolver.class,
193             provider.getEffectiveAclsResolver().getClass());
194 
195         provider.setBasicAclEntryCache(null);
196         assertNull(provider.getBasicAclEntryCache());
197 
198         provider.setDefaultAclObjectIdentityClass(null);
199         assertNull(provider.getDefaultAclObjectIdentityClass());
200 
201         provider.setEffectiveAclsResolver(null);
202         assertNull(provider.getEffectiveAclsResolver());
203 
204         provider.setBasicAclDao(new MockDao());
205         assertNotNull(provider.getBasicAclDao());
206 
207         assertNull(provider.getRestrictSupportToClass());
208         provider.setRestrictSupportToClass(SomeDomain.class);
209         assertEquals(SomeDomain.class, provider.getRestrictSupportToClass());
210     }
211 
212     public void testStartupFailsIfNullAclDao() throws Exception {
213         BasicAclProvider provider = new BasicAclProvider();
214 
215         try {
216             provider.afterPropertiesSet();
217             fail("Should have thrown IllegalArgumentException");
218         } catch (IllegalArgumentException expected) {
219             assertTrue(true);
220         }
221     }
222 
223     public void testStartupFailsIfNullEffectiveAclsResolver()
224         throws Exception {
225         BasicAclProvider provider = new BasicAclProvider();
226         provider.setBasicAclDao(makePopulatedJdbcDao());
227 
228         provider.setEffectiveAclsResolver(null);
229 
230         try {
231             provider.afterPropertiesSet();
232             fail("Should have thrown IllegalArgumentException");
233         } catch (IllegalArgumentException expected) {
234             assertTrue(true);
235         }
236     }
237 
238     public void testStartupFailsIfNullEntryCache() throws Exception {
239         BasicAclProvider provider = new BasicAclProvider();
240         provider.setBasicAclDao(makePopulatedJdbcDao());
241 
242         provider.setBasicAclEntryCache(null);
243 
244         try {
245             provider.afterPropertiesSet();
246             fail("Should have thrown IllegalArgumentException");
247         } catch (IllegalArgumentException expected) {
248             assertTrue(true);
249         }
250     }
251 
252     public void testStartupFailsIfProblemWithAclObjectIdentityClass()
253         throws Exception {
254         BasicAclProvider provider = new BasicAclProvider();
255         provider.setBasicAclDao(makePopulatedJdbcDao());
256 
257         // check nulls rejected
258         provider.setDefaultAclObjectIdentityClass(null);
259 
260         try {
261             provider.afterPropertiesSet();
262             fail("Should have thrown IllegalArgumentException");
263         } catch (IllegalArgumentException expected) {
264             assertTrue(true);
265         }
266 
267         // check non-AclObjectIdentity classes are also rejected
268         provider.setDefaultAclObjectIdentityClass(String.class);
269 
270         try {
271             provider.afterPropertiesSet();
272             fail("Should have thrown IllegalArgumentException");
273         } catch (IllegalArgumentException expected) {
274             assertTrue(true);
275         }
276 
277         // check AclObjectIdentity class without constructor accepting a
278         // domain object is also rejected
279         provider.setDefaultAclObjectIdentityClass(MockAclObjectIdentity.class);
280 
281         try {
282             provider.afterPropertiesSet();
283             fail("Should have thrown IllegalArgumentException");
284         } catch (IllegalArgumentException expected) {
285             assertEquals("defaultAclObjectIdentityClass must provide a constructor that accepts the domain object instance!",
286                 expected.getMessage());
287         }
288     }
289 
290     public void testSupports() throws Exception {
291         BasicAclProvider provider = new BasicAclProvider();
292         provider.setBasicAclDao(makePopulatedJdbcDao());
293 
294         // this one should NOT be supported, as it has no getId() method
295         assertFalse(provider.supports(new Integer(34)));
296 
297         // this one SHOULD be supported, as it has a getId() method
298         assertTrue(provider.supports(new SomeDomain()));
299 
300         // this one SHOULD be supported, as it implements AclObjectIdentityAware
301         assertTrue(provider.supports(new MockDomain(4)));
302 
303         // now restrict the provider to only respond to SomeDomain.class requests
304         provider.setRestrictSupportToClass(SomeDomain.class);
305         assertEquals(SomeDomain.class, provider.getRestrictSupportToClass());
306 
307         // this one SHOULD be supported, as it has a getId() method AND it meets the restrictSupportToClass criteria
308         assertTrue(provider.supports(new SomeDomain()));
309 
310         // this one should NOT be suported, as whilst it implement AclObjectIdentityAware (as proven earlier in the test), it does NOT meet the restrictSupportToClass criteria
311         assertFalse(provider.supports(new MockDomain(4)));
312     }
313 
314     public void testSupportsReturnsNullIfObjectNull() {
315         BasicAclProvider provider = new BasicAclProvider();
316         assertFalse(provider.supports(new Integer(34)));
317     }
318 
319     private JdbcDaoImpl makePopulatedJdbcDao() throws Exception {
320         JdbcDaoImpl dao = new JdbcDaoImpl();
321         dao.setDataSource(PopulatedDatabase.getDataSource());
322         dao.afterPropertiesSet();
323 
324         return dao;
325     }
326 
327     //~ Inner Classes ==========================================================
328 
329     private class MockCache implements BasicAclEntryCache {
330         private Map map = new HashMap();
331         private int gets = 0;
332         private int getsHits = 0;
333         private int puts = 0;
334 
335         public Map getBackingMap() {
336             return map;
337         }
338 
339         public BasicAclEntry[] getEntriesFromCache(
340             AclObjectIdentity aclObjectIdentity) {
341             gets++;
342 
343             Object result = map.get(aclObjectIdentity);
344 
345             if (result == null) {
346                 return null;
347             }
348 
349             getsHits++;
350 
351             BasicAclEntryHolder holder = (BasicAclEntryHolder) result;
352 
353             return holder.getBasicAclEntries();
354         }
355 
356         public int getGets() {
357             return gets;
358         }
359 
360         public int getGetsHits() {
361             return getsHits;
362         }
363 
364         public int getPuts() {
365             return puts;
366         }
367 
368         public void putEntriesInCache(BasicAclEntry[] basicAclEntry) {
369             puts++;
370 
371             BasicAclEntryHolder holder = new BasicAclEntryHolder(basicAclEntry);
372             map.put(basicAclEntry[0].getAclObjectIdentity(), holder);
373         }
374     }
375 
376     private class MockDao implements BasicAclDao {
377         public BasicAclEntry[] getAcls(AclObjectIdentity aclObjectIdentity) {
378             return null;
379         }
380     }
381 
382     private class MockDomain implements AclObjectIdentityAware {
383         private int id;
384 
385         public MockDomain(int id) {
386             this.id = id;
387         }
388 
389         public AclObjectIdentity getAclObjectIdentity() {
390             return new NamedEntityObjectIdentity(OBJECT_IDENTITY,
391                 new Integer(id).toString());
392         }
393     }
394 }