    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 }