Announcement Announcement Module
No announcement yet.
AclObjectIdentity with no Acls and Acl inheritance Page Title Module
Move Remove Collapse
This topic is closed
Conversation Detail Module
  • Filter
  • Time
  • Show
Clear All
new posts

  • AclObjectIdentity with no Acls and Acl inheritance


    I am working with Acls within Acegi and have found some behaviour which seems odd and contrary to the documentation. It seems that to have an object inherit an acl from its parent you must have at least one acl attached to that object. That is, if you have an object with no acls directly attached to it, but that object has a parent that has acls that should be propagated, the acls won't be passed down unless you add at least one acl to that object. That acl can belong to anybody, it just needs to be there.

    The reason is that acegi relies on acls to work out if there is a parent object. So an object has no acls attached to it, acegi can't find a parent, the inheritance tree isn't walked and no acls are propagated. This is backed up in the BasicAclProvider code. If it gets a null from the BasicAclDao then it doesn't do any further processing.

    My question is. why rely on the Acls, why not on the AclObjectIdentity? If acegi looked at the AclObjectIdentiy for parent information, the system would work as advertised in section 1.14.3 of the reference guide.

    The easy hack around this is to create an acl pointing to an 'imaginary' recipient at object creation time. This would give acegi an Acl to find the parent from and the world would be at peace again. This has been tested to work.

    Am I missing an important concept, or should I look at writing a fix.


  • #2
    From JdbcDaoImplTests:
        public void testGetsEntriesWhichExistInDatabaseButHaveNoAcls()
            throws Exception {
            JdbcDaoImpl dao = makePopulatedJdbcDao();
            AclObjectIdentity identity = new NamedEntityObjectIdentity(OBJECT_IDENTITY,
            BasicAclEntry[] acls = dao.getAcls(identity);
            assertEquals(1, acls.length);
    I just extended BasicAclProviderTests to test BasicAclProvider works properly for entities that have an acl_object_identity but do not have an acl_permission:
        public void testGetAclsForInstanceWithParentLevelsButNoDirectAclsAgainstInstance()
            throws Exception {
            BasicAclProvider provider = new BasicAclProvider();
            Object object = new MockDomain(5);
            AclEntry[] acls = provider.getAcls(object);
            assertEquals(3, acls.length);
            assertEquals("scott", ((BasicAclEntry) acls[0]).getRecipient());
            assertEquals(14, ((BasicAclEntry) acls[0]).getMask());
            assertEquals("ROLE_SUPERVISOR", ((BasicAclEntry) acls[1]).getRecipient());
            assertEquals(1, ((BasicAclEntry) acls[1]).getMask());
                ((BasicAclEntry) acls[2]).getRecipient());
    The test passes (and is now in CVS for you to try out if you wish). Thus I can't reproduce what you're seeing. Could you double-check your setup etc?


    • #3
      Hi Ben,

      Thanks for the reply mate. I have figured out what is doing it. It has to do (again) with my hibernate implementation of BasicAclDao.

      In your first code snippet, you show adding an AclObjectIdentity (domain object #5). I checked the test sources and found that indeed domain object #5 has no acls, and hence it is an object that has no acls, that has a parent that has acls. Perfect test case. Then you create a JdbcDaoImpl object and call the getAcls() method on it. And it seems to return one ACL!! This is odd because there are no ACLs for this object.

      So I looked at the JdbcDaoImpl code - and I find this:

      if (acls.size() == 0) {
          // return merely an inheritence marker (as we know about the object but it has no related ACLs)
          return new BasicAclEntry[] {createBasicAclEntry(propertiesInformation, null)};
      And this is where the 'imaginary' acl that I mentioned before comes from.

      Now, BasicAclProvider uses the ACL in the aary returned from BasicAclDao.getAcls() to work out who the parent of the domain object that this ACL refers to is. So when this imaginary ACL is in play, everything works nicely. Here is the code from BasicAclProvider"

      AclObjectIdentity parent = instanceAclEntries[0].getAclObjectParentIdentity();
      So the solution is to include a 'dummy' ACL that has the correct alcObjectParentIdentity in the array that gets passed back. But then you have another problem. Because I had to implement by own EffectAclsResolver (my domain objects are my AclObjectIdenty objects), I had to then introduce a hack into that my custom EffectiveAclResolver code to make sure that it ALWAYS would ignore my inheritance marker object and never include the dummy ACL.


      The reason why I had an issue is because I implemented BasicAclDao from scratch in Hibernate following the JavaDoc spec for BasicAclDao. The spec says nothing about this behaviour, it just says that if there are no ACLs, return null. So when I plug my Hibernate BasicAclDao into the BasicAclProvider supplied, we have this issue where the tree isn't walked.

      I can see why the problem got in there, the behaviour of BasicAclDao is coupled to BasicAclProvider, but BasicAclDao is an interface that can implemented in whatever and the docco needs to have this little trick spelled out for implementors. Otherwise it doesn't play nicely with BasicAclProvider.

      This problem is caused by parent checking being implemented on Acl objects rather than AclObjectIdentities. I've had a quick think about why it is this way, and can't come up with any good reasons.Surely it is better placed in AclObjectIdentity? Maybe in a class called BasicAclObjectIdentity if you don't want to force implementors to implement ACL inheritance.

      If you agree that this needs a rework, I would be happy to contribute.

      Thanks for your help,


      • #4
        Feel free to contribute back a patch.