浏览代码

SEC-1038: Changed JdbcMutableAclServiceTests to facilitate testing with PostgreSQL and updated JdbcMutableAclService to use a the id obtained from the ObjectIdentity directly rather than calling toString() on it before passing to the JDBC call.

Luke Taylor 16 年之前
父节点
当前提交
c6dfee69d4

+ 7 - 0
acl/pom.xml

@@ -47,6 +47,13 @@
             <artifactId>hsqldb</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+            <version>8.3-603.jdbc3</version>
+            <scope>test</scope>
+        </dependency>
+
     </dependencies>
 
     <build>

+ 29 - 10
acl/src/main/java/org/springframework/security/acls/jdbc/JdbcMutableAclService.java

@@ -42,7 +42,14 @@ import org.springframework.util.Assert;
 
 
 /**
- * Provides a base implementation of {@link MutableAclService}.
+ * Provides a base JDBC implementation of {@link MutableAclService}.
+ * <p>
+ * The default settings are for HSQLDB. If you are using a different database you
+ * will probably need to set the {@link #setSidIdentityQuery(String) sidIdentityQuery} and
+ * {@link #setClassIdentityQuery(String) classIdentityQuery} properties appropriately.
+ * <p>
+ * See the appendix of the Spring Security reference manual for more information on the expected schema
+ * and how it is used. Information on using PostgreSQL is also included.
  *
  * @author Ben Alex
  * @author Johannes Zlattinger
@@ -55,8 +62,8 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
     private AclCache aclCache;
     private String deleteEntryByObjectIdentityForeignKey = "delete from acl_entry where acl_object_identity=?";
     private String deleteObjectIdentityByPrimaryKey = "delete from acl_object_identity where id=?";
-    private String classIdentityQuery = "call identity()"; // should be overridden for postgres : select currval('acl_class_seq')
-    private String sidIdentityQuery = "call identity()"; // should be overridden for postgres : select currval('acl_siq_seq')
+    private String classIdentityQuery = "call identity()";
+    private String sidIdentityQuery = "call identity()";
     private String insertClass = "insert into acl_class (class) values (?)";
     private String insertEntry = "insert into acl_entry "
         + "(acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure)"
@@ -142,7 +149,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
     protected void createObjectIdentity(ObjectIdentity object, Sid owner) {
         Long sidId = createOrRetrieveSidPrimaryKey(owner, true);
         Long classId = createOrRetrieveClassPrimaryKey(object.getJavaType(), true);
-        jdbcTemplate.update(insertObjectIdentity, classId, object.getIdentifier().toString(), sidId, Boolean.TRUE);
+        jdbcTemplate.update(insertObjectIdentity, classId, object.getIdentifier(), sidId, Boolean.TRUE);
     }
 
     /**
@@ -354,14 +361,26 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
         }
     }
 
-    public void setClassIdentityQuery(String identityQuery) {
-        Assert.hasText(identityQuery, "New identity query is required");
-        this.classIdentityQuery = identityQuery;
+    /**
+     * Sets the query that will be used to retrieve the identity of a newly created row in the <tt>acl_class</tt>
+     * table.
+     *
+     * @param classIdentityQuery the query, which should return the identifier. Defaults to <tt>call identity()</tt>
+     */
+    public void setClassIdentityQuery(String classIdentityQuery) {
+        Assert.hasText(classIdentityQuery, "New classIdentityQuery query is required");
+        this.classIdentityQuery = classIdentityQuery;
     }
 
-    public void setSidIdentityQuery(String identityQuery) {
-        Assert.hasText(identityQuery, "New identity query is required");
-        this.sidIdentityQuery = identityQuery;
+    /**
+     * Sets the query that will be used to retrieve the identity of a newly created row in the <tt>acl_sid</tt>
+     * table.
+     *
+     * @param sidIdentityQuery the query, which should return the identifier. Defaults to <tt>call identity()</tt>
+     */
+    public void setSidIdentityQuery(String sidIdentityQuery) {
+        Assert.hasText(sidIdentityQuery, "New sidIdentityQuery query is required");
+        this.sidIdentityQuery = sidIdentityQuery;
     }
     /**
      * @param foreignKeysInDatabase if false this class will perform additional FK constrain checking, which may

+ 40 - 37
acl/src/main/resources/createAclSchema.sql

@@ -1,43 +1,46 @@
--- ACL Schema SQL
+-- ACL schema sql used in HSQLDB
 
--- DROP TABLE ACL_ENTRY;
--- DROP TABLE ACL_OBJECT_IDENTITY;
--- DROP TABLE ACL_CLASS;
--- DROP TABLE ACL_SID;
+-- drop table acl_entry;
+-- drop table acl_object_identity;
+-- drop table acl_class;
+-- drop table acl_sid;
 
 
-CREATE TABLE ACL_SID(
-ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,
-PRINCIPAL BOOLEAN NOT NULL,
-SID VARCHAR_IGNORECASE(100) NOT NULL,
-CONSTRAINT UNIQUE_UK_1 UNIQUE(SID,PRINCIPAL));
+create table acl_sid(
+    id bigint generated by default as identity(start with 100) not null primary key,
+    principal boolean not null,
+    sid varchar_ignorecase(100) not null,
+    constraint unique_uk_1 unique(sid,principal));
 
-CREATE TABLE ACL_CLASS(
-ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,
-CLASS VARCHAR_IGNORECASE(100) NOT NULL,
-CONSTRAINT UNIQUE_UK_2 UNIQUE(CLASS));
+create table acl_class(
+    id bigint generated by default as identity(start with 100) not null primary key,
+    class varchar_ignorecase(100) not null,
+    constraint unique_uk_2 unique(class)
+);
 
-CREATE TABLE ACL_OBJECT_IDENTITY(
-ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,
-OBJECT_ID_CLASS BIGINT NOT NULL,
-OBJECT_ID_IDENTITY BIGINT NOT NULL,
-PARENT_OBJECT BIGINT,
-OWNER_SID BIGINT,
-ENTRIES_INHERITING BOOLEAN NOT NULL,
-CONSTRAINT UNIQUE_UK_3 UNIQUE(OBJECT_ID_CLASS,OBJECT_ID_IDENTITY),
-CONSTRAINT FOREIGN_FK_1 FOREIGN KEY(PARENT_OBJECT)REFERENCES ACL_OBJECT_IDENTITY(ID),
-CONSTRAINT FOREIGN_FK_2 FOREIGN KEY(OBJECT_ID_CLASS)REFERENCES ACL_CLASS(ID),
-CONSTRAINT FOREIGN_FK_3 FOREIGN KEY(OWNER_SID)REFERENCES ACL_SID(ID));
+create table acl_object_identity(
+    id bigint generated by default as identity(start with 100) not null primary key,
+    object_id_class bigint not null,
+    object_id_identity bigint not null,
+    parent_object bigint,
+    owner_sid bigint,
+    entries_inheriting boolean not null,
+    constraint unique_uk_3 unique(object_id_class,object_id_identity),
+    constraint foreign_fk_1 foreign key(parent_object)references acl_object_identity(id),
+    constraint foreign_fk_2 foreign key(object_id_class)references acl_class(id),
+    constraint foreign_fk_3 foreign key(owner_sid)references acl_sid(id)
+);
 
-CREATE TABLE ACL_ENTRY(
-ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,
-ACL_OBJECT_IDENTITY BIGINT NOT NULL,
-ACE_ORDER INT NOT NULL,
-SID BIGINT NOT NULL,
-MASK INTEGER NOT NULL,
-GRANTING BOOLEAN NOT NULL,
-AUDIT_SUCCESS BOOLEAN NOT NULL,
-AUDIT_FAILURE BOOLEAN NOT NULL,
-CONSTRAINT UNIQUE_UK_4 UNIQUE(ACL_OBJECT_IDENTITY,ACE_ORDER),
-CONSTRAINT FOREIGN_FK_4 FOREIGN KEY(ACL_OBJECT_IDENTITY) REFERENCES ACL_OBJECT_IDENTITY(ID),
-CONSTRAINT FOREIGN_FK_5 FOREIGN KEY(SID) REFERENCES ACL_SID(ID));
+create table acl_entry(
+    id bigint generated by default as identity(start with 100) not null primary key,
+    acl_object_identity bigint not null,
+    ace_order int not null,
+    sid bigint not null,
+    mask integer not null,
+    granting boolean not null,
+    audit_success boolean not null,
+    audit_failure boolean not null,
+    constraint unique_uk_4 unique(acl_object_identity,ace_order),
+    constraint foreign_fk_4 foreign key(acl_object_identity) references acl_object_identity(id),
+    constraint foreign_fk_5 foreign key(sid) references acl_sid(id)
+);

+ 46 - 0
acl/src/main/resources/createAclSchemaPostgres.sql

@@ -0,0 +1,46 @@
+-- ACL Schema SQL for PostgreSQL
+
+-- drop table acl_entry;
+-- drop table acl_object_identity;
+-- drop table acl_class;
+-- drop table acl_sid;
+
+create table acl_sid(
+    id bigserial not null primary key,
+    principal boolean not null,
+    sid varchar(100) not null,
+    constraint unique_uk_1 unique(sid,principal)
+);
+
+create table acl_class(
+    id bigserial not null primary key,
+    class varchar(100) not null,
+    constraint unique_uk_2 unique(class)
+);
+
+create table acl_object_identity(
+    id bigserial primary key,
+    object_id_class bigint not null,
+    object_id_identity bigint not null,
+    parent_object bigint,
+    owner_sid bigint,
+    entries_inheriting boolean not null,
+    constraint unique_uk_3 unique(object_id_class,object_id_identity),
+    constraint foreign_fk_1 foreign key(parent_object)references acl_object_identity(id),
+    constraint foreign_fk_2 foreign key(object_id_class)references acl_class(id),
+    constraint foreign_fk_3 foreign key(owner_sid)references acl_sid(id)
+);
+
+create table acl_entry(
+    id bigserial primary key,
+    acl_object_identity bigint not null,
+    ace_order int not null,
+    sid bigint not null,
+    mask integer not null,
+    granting boolean not null,
+    audit_success boolean not null,
+    audit_failure boolean not null,
+    constraint unique_uk_4 unique(acl_object_identity,ace_order),
+    constraint foreign_fk_4 foreign key(acl_object_identity) references acl_object_identity(id),
+    constraint foreign_fk_5 foreign key(sid) references acl_sid(id)
+);

+ 35 - 23
acl/src/main/resources/select.sql

@@ -1,27 +1,39 @@
 -- Not required. Just shows the sort of queries being sent to DB.
 
 
-select ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY, ACL_ENTRY.ACE_ORDER, 
-ACL_OBJECT_IDENTITY.ID as ACL_ID,
-ACL_OBJECT_IDENTITY.PARENT_OBJECT,
-ACL_OBJECT_IDENTITY,ENTRIES_INHERITING,
-ACL_ENTRY.ID as ACE_ID, ACL_ENTRY.MASK, ACL_ENTRY.GRANTING, ACL_ENTRY.AUDIT_SUCCESS, ACL_ENTRY.AUDIT_FAILURE,
-ACL_SID.PRINCIPAL as ACE_PRINCIPAL, ACL_SID.SID as ACE_SID,
-ACLI_SID.PRINCIPAL as ACL_PRINCIPAL, ACLI_SID.SID as ACL_SID,
-ACL_CLASS.CLASS
-
-from ACL_OBJECT_IDENTITY, ACL_SID ACLI_SID, ACL_CLASS
-LEFT JOIN ACL_ENTRY ON ACL_OBJECT_IDENTITY.ID = ACL_ENTRY.ACL_OBJECT_IDENTITY
-LEFT JOIN ACL_SID ON ACL_ENTRY.SID = ACL_SID.ID
-
-where 
-
-ACLI_SID.ID = ACL_OBJECT_IDENTITY.OWNER_SID
-and ACL_CLASS.ID = ACL_OBJECT_IDENTITY.OBJECT_ID_CLASS
+select  acl_object_identity.object_id_identity,
+        acl_entry.ace_order,
+        acl_object_identity.id as acl_id,
+        acl_object_identity.parent_object,
+        acl_object_identity,
+        entries_inheriting,
+        acl_entry.id as ace_id,
+        acl_entry.mask,
+        acl_entry.granting,
+        acl_entry.audit_success,
+        acl_entry.audit_failure,
+        acl_sid.principal as ace_principal,
+        acl_sid.sid as ace_sid,
+        acli_sid.principal as acl_principal,
+        acli_sid.sid as acl_sid,
+        acl_class.class
+
+from    acl_object_identity,
+        acl_sid acli_sid,
+        acl_class
+
+left join acl_entry on acl_object_identity.id = acl_entry.acl_object_identity
+left join acl_sid on acl_entry.sid = acl_sid.id
+
+where
+    acli_sid.id = acl_object_identity.owner_sid
+
+and acl_class.id = acl_object_identity.object_id_class
+
 and (
-(ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY = 1 
-and ACL_CLASS.CLASS = 'sample.contact.Contact')
-or 
-(ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY = 2000
-and ACL_CLASS.CLASS = 'sample.contact.Contact')
-) order by ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY asc, ACL_ENTRY.ACE_ORDER asc
+
+    (acl_object_identity.object_id_identity = 1 and acl_class.class = 'sample.contact.contact')
+or
+    (acl_object_identity.object_id_identity = 2000 and acl_class.class = 'sample.contact.contact')
+
+) order by acl_object_identity.object_id_identity asc, acl_entry.ace_order asc

+ 0 - 208
acl/src/test/java/org/springframework/security/acls/jdbc/AclPermissionInheritanceTests.java

@@ -1,208 +0,0 @@
-package org.springframework.security.acls.jdbc;
-
-import java.io.IOException;
-
-import junit.framework.TestCase;
-import net.sf.ehcache.CacheManager;
-import net.sf.ehcache.Ehcache;
-
-import org.springframework.cache.ehcache.EhCacheFactoryBean;
-import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.jdbc.datasource.DataSourceTransactionManager;
-import org.springframework.jdbc.datasource.DriverManagerDataSource;
-import org.springframework.security.acls.MutableAcl;
-import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
-import org.springframework.security.acls.domain.AclImpl;
-import org.springframework.security.acls.domain.BasePermission;
-import org.springframework.security.acls.domain.ConsoleAuditLogger;
-import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
-import org.springframework.security.acls.sid.GrantedAuthoritySid;
-import org.springframework.security.acls.sid.PrincipalSid;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.authority.AuthorityUtils;
-import org.springframework.security.core.authority.GrantedAuthorityImpl;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.transaction.TransactionStatus;
-import org.springframework.transaction.support.DefaultTransactionDefinition;
-
-public class AclPermissionInheritanceTests extends TestCase {
-
-    private JdbcMutableAclService aclService;
-    private JdbcTemplate jdbcTemplate;
-    private DriverManagerDataSource dataSource;
-    private DataSourceTransactionManager txManager;
-    private TransactionStatus txStatus;
-
-    protected void setUp() throws Exception {
-
-        dataSource = new DriverManagerDataSource();
-        dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
-        dataSource.setUrl("jdbc:hsqldb:mem:permissiontest");
-        dataSource.setUsername("sa");
-        dataSource.setPassword("");
-
-        jdbcTemplate = new JdbcTemplate(dataSource);
-
-        txManager = new DataSourceTransactionManager();
-        txManager.setDataSource(dataSource);
-
-        txStatus = txManager.getTransaction(new DefaultTransactionDefinition());
-
-        aclService = createAclService(dataSource);
-
-        Authentication auth = new UsernamePasswordAuthenticationToken("system", "secret",
-                AuthorityUtils.createAuthorityList("ROLE_IGNORED"));
-        SecurityContextHolder.getContext().setAuthentication(auth);
-    }
-
-    protected void tearDown() throws Exception {
-        txManager.rollback(txStatus);
-        SecurityContextHolder.clearContext();
-    }
-
-    public void test1() throws Exception {
-
-        createAclSchema(jdbcTemplate);
-
-        ObjectIdentityImpl rootObject =
-            new ObjectIdentityImpl(TestDomainObject.class, new Long(1));
-
-        MutableAcl parent = aclService.createAcl(rootObject);
-        MutableAcl child = aclService.createAcl(new ObjectIdentityImpl(TestDomainObject.class, new Long(2)));
-        child.setParent(parent);
-        aclService.updateAcl(child);
-
-        parent = (AclImpl) aclService.readAclById(rootObject);
-        parent.insertAce(0, BasePermission.READ,
-                new PrincipalSid("john"), true);
-        aclService.updateAcl(parent);
-
-        parent = (AclImpl) aclService.readAclById(rootObject);
-        parent.insertAce(1, BasePermission.READ,
-                new PrincipalSid("joe"), true);
-        aclService.updateAcl(parent);
-
-        child = (MutableAcl) aclService.readAclById(
-                new ObjectIdentityImpl(TestDomainObject.class, new Long(2)));
-
-        parent = (MutableAcl) child.getParentAcl();
-
-        assertEquals("Fails because child has a stale reference to its parent", 2, parent.getEntries().size());
-        assertEquals(1, parent.getEntries().get(0).getPermission().getMask());
-        assertEquals(new PrincipalSid("john"), parent.getEntries().get(0).getSid());
-        assertEquals(1, parent.getEntries().get(1).getPermission().getMask());
-        assertEquals(new PrincipalSid("joe"), parent.getEntries().get(1).getSid());
-
-    }
-    public void test2() throws Exception {
-
-        createAclSchema(jdbcTemplate);
-
-        ObjectIdentityImpl rootObject =
-            new ObjectIdentityImpl(TestDomainObject.class, new Long(1));
-
-        MutableAcl parent = aclService.createAcl(rootObject);
-        MutableAcl child = aclService.createAcl(new ObjectIdentityImpl(TestDomainObject.class, new Long(2)));
-        child.setParent(parent);
-        aclService.updateAcl(child);
-
-        parent.insertAce(0, BasePermission.ADMINISTRATION,
-                new GrantedAuthoritySid("ROLE_ADMINISTRATOR"), true);
-        aclService.updateAcl(parent);
-
-        parent.insertAce(1, BasePermission.DELETE, new PrincipalSid("terry"), true);
-        aclService.updateAcl(parent);
-
-        child = (MutableAcl) aclService.readAclById(
-                new ObjectIdentityImpl(TestDomainObject.class, new Long(2)));
-
-        parent = (MutableAcl) child.getParentAcl();
-
-        assertEquals(2, parent.getEntries().size());
-        assertEquals(16, parent.getEntries().get(0).getPermission().getMask());
-        assertEquals(new GrantedAuthoritySid("ROLE_ADMINISTRATOR"), parent.getEntries().get(0).getSid());
-        assertEquals(8, parent.getEntries().get(1).getPermission().getMask());
-        assertEquals(new PrincipalSid("terry"), parent.getEntries().get(1).getSid());
-
-    }
-
-    private JdbcMutableAclService createAclService(DriverManagerDataSource ds)
-        throws IOException {
-
-        GrantedAuthorityImpl adminAuthority = new GrantedAuthorityImpl("ROLE_ADMINISTRATOR");
-        AclAuthorizationStrategyImpl authStrategy = new AclAuthorizationStrategyImpl(
-                new GrantedAuthorityImpl[]{adminAuthority,adminAuthority,adminAuthority});
-
-        EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean();
-        ehCacheManagerFactoryBean.afterPropertiesSet();
-        CacheManager cacheManager = (CacheManager) ehCacheManagerFactoryBean.getObject();
-
-        EhCacheFactoryBean ehCacheFactoryBean = new EhCacheFactoryBean();
-        ehCacheFactoryBean.setCacheName("aclAche");
-        ehCacheFactoryBean.setCacheManager(cacheManager);
-        ehCacheFactoryBean.afterPropertiesSet();
-        Ehcache ehCache = (Ehcache) ehCacheFactoryBean.getObject();
-
-        AclCache aclAche = new EhCacheBasedAclCache(ehCache);
-
-        BasicLookupStrategy lookupStrategy =
-            new BasicLookupStrategy(ds, aclAche, authStrategy, new ConsoleAuditLogger());
-
-        return new JdbcMutableAclService(ds,lookupStrategy, aclAche);
-    }
-
-    private void createAclSchema(JdbcTemplate jdbcTemplate) {
-
-        jdbcTemplate.execute("DROP TABLE ACL_ENTRY IF EXISTS;");
-        jdbcTemplate.execute("DROP TABLE ACL_OBJECT_IDENTITY IF EXISTS;");
-        jdbcTemplate.execute("DROP TABLE ACL_CLASS IF EXISTS");
-        jdbcTemplate.execute("DROP TABLE ACL_SID IF EXISTS");
-
-        jdbcTemplate.execute(
-                "CREATE TABLE ACL_SID(" +
-                        "ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY," +
-                        "PRINCIPAL BOOLEAN NOT NULL," +
-                        "SID VARCHAR_IGNORECASE(100) NOT NULL," +
-                        "CONSTRAINT UNIQUE_UK_1 UNIQUE(SID,PRINCIPAL));");
-        jdbcTemplate.execute(
-                "CREATE TABLE ACL_CLASS(" +
-                        "ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY," +
-                        "CLASS VARCHAR_IGNORECASE(100) NOT NULL," +
-                        "CONSTRAINT UNIQUE_UK_2 UNIQUE(CLASS));");
-        jdbcTemplate.execute(
-                "CREATE TABLE ACL_OBJECT_IDENTITY(" +
-                        "ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY," +
-                        "OBJECT_ID_CLASS BIGINT NOT NULL," +
-                        "OBJECT_ID_IDENTITY BIGINT NOT NULL," +
-                        "PARENT_OBJECT BIGINT," +
-                        "OWNER_SID BIGINT," +
-                        "ENTRIES_INHERITING BOOLEAN NOT NULL," +
-                        "CONSTRAINT UNIQUE_UK_3 UNIQUE(OBJECT_ID_CLASS,OBJECT_ID_IDENTITY)," +
-                        "CONSTRAINT FOREIGN_FK_1 FOREIGN KEY(PARENT_OBJECT)REFERENCES ACL_OBJECT_IDENTITY(ID)," +
-                        "CONSTRAINT FOREIGN_FK_2 FOREIGN KEY(OBJECT_ID_CLASS)REFERENCES ACL_CLASS(ID)," +
-                        "CONSTRAINT FOREIGN_FK_3 FOREIGN KEY(OWNER_SID)REFERENCES ACL_SID(ID));");
-        jdbcTemplate.execute(
-                "CREATE TABLE ACL_ENTRY(" +
-                        "ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY," +
-                        "ACL_OBJECT_IDENTITY BIGINT NOT NULL,ACE_ORDER INT NOT NULL,SID BIGINT NOT NULL," +
-                        "MASK INTEGER NOT NULL,GRANTING BOOLEAN NOT NULL,AUDIT_SUCCESS BOOLEAN NOT NULL," +
-                        "AUDIT_FAILURE BOOLEAN NOT NULL,CONSTRAINT UNIQUE_UK_4 UNIQUE(ACL_OBJECT_IDENTITY,ACE_ORDER)," +
-                        "CONSTRAINT FOREIGN_FK_4 FOREIGN KEY(ACL_OBJECT_IDENTITY) REFERENCES ACL_OBJECT_IDENTITY(ID)," +
-                        "CONSTRAINT FOREIGN_FK_5 FOREIGN KEY(SID) REFERENCES ACL_SID(ID));");
-    }
-
-    public static class TestDomainObject {
-
-        private Long id;
-
-        public Long getId() {
-            return id;
-        }
-
-        public void setId(Long id) {
-            this.id = id;
-        }
-    }
-}

+ 90 - 55
acl/src/test/java/org/springframework/security/acls/jdbc/JdbcMutableAclServiceTests.java

@@ -16,15 +16,12 @@ package org.springframework.security.acls.jdbc;
 
 import static org.junit.Assert.*;
 
-import java.io.IOException;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 
 import javax.sql.DataSource;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.io.ClassPathResource;
@@ -37,17 +34,21 @@ import org.springframework.security.acls.MutableAcl;
 import org.springframework.security.acls.NotFoundException;
 import org.springframework.security.acls.Permission;
 import org.springframework.security.acls.TargetObject;
+import org.springframework.security.acls.domain.AclImpl;
 import org.springframework.security.acls.domain.BasePermission;
+import org.springframework.security.acls.domain.CumulativePermission;
 import org.springframework.security.acls.objectidentity.ObjectIdentity;
 import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
+import org.springframework.security.acls.sid.GrantedAuthoritySid;
 import org.springframework.security.acls.sid.PrincipalSid;
 import org.springframework.security.acls.sid.Sid;
 import org.springframework.security.authentication.TestingAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.test.annotation.Rollback;
 import org.springframework.test.context.ContextConfiguration;
 import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
+import org.springframework.test.context.transaction.AfterTransaction;
+import org.springframework.test.context.transaction.BeforeTransaction;
 import org.springframework.transaction.annotation.Transactional;
 
 /**
@@ -69,9 +70,9 @@ public class JdbcMutableAclServiceTests extends AbstractTransactionalJUnit4Sprin
 
     //~ Instance fields ================================================================================================
 
-    private final ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
-    private final ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(101));
-    private final ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(102));
+    private final ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(100));
+    private final ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(101));
+    private final ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(102));
 
     @Autowired
     private JdbcMutableAclService jdbcMutableAclService;
@@ -86,12 +87,18 @@ public class JdbcMutableAclServiceTests extends AbstractTransactionalJUnit4Sprin
 
     //~ Methods ========================================================================================================
 
-    @Before
-    public void createTables() throws IOException {
-        new DatabaseSeeder(dataSource, new ClassPathResource("createAclSchema.sql"));
+    @BeforeTransaction
+    public void createTables() throws Exception {
+        try {
+            new DatabaseSeeder(dataSource, new ClassPathResource("createAclSchema.sql"));
+//            new DatabaseSeeder(dataSource, new ClassPathResource("createAclSchemaPostgres.sql"));
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw e;
+        }
     }
 
-    @After
+    @AfterTransaction
     public void clearContextAndData() throws Exception {
         SecurityContextHolder.clearContext();
         jdbcTemplate.execute("drop table acl_entry");
@@ -102,7 +109,6 @@ public class JdbcMutableAclServiceTests extends AbstractTransactionalJUnit4Sprin
 
     @Test
     @Transactional
-    @Rollback
     public void testLifecycle() {
         SecurityContextHolder.getContext().setAuthentication(auth);
 
@@ -239,8 +245,7 @@ public class JdbcMutableAclServiceTests extends AbstractTransactionalJUnit4Sprin
      */
     @Test
     @Transactional
-    @Rollback
-    public void testDeleteAclAlsoDeletesChildren() throws Exception {
+    public void deleteAclAlsoDeletesChildren() throws Exception {
         SecurityContextHolder.getContext().setAuthentication(auth);
 
         jdbcMutableAclService.createAcl(topParentOid);
@@ -313,10 +318,9 @@ public class JdbcMutableAclServiceTests extends AbstractTransactionalJUnit4Sprin
 
     @Test
     @Transactional
-    @Rollback
-    public void testCreateAclForADuplicateDomainObject() throws Exception {
+    public void createAclForADuplicateDomainObject() throws Exception {
         SecurityContextHolder.getContext().setAuthentication(auth);
-        ObjectIdentity duplicateOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
+        ObjectIdentity duplicateOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(100));
         jdbcMutableAclService.createAcl(duplicateOid);
         // Try to add the same object second time
         try {
@@ -329,8 +333,7 @@ public class JdbcMutableAclServiceTests extends AbstractTransactionalJUnit4Sprin
 
     @Test
     @Transactional
-    @Rollback
-    public void testDeleteAclRejectsNullParameters() throws Exception {
+    public void deleteAclRejectsNullParameters() throws Exception {
         try {
             jdbcMutableAclService.deleteAcl(null, true);
             fail("It should have thrown IllegalArgumentException");
@@ -341,8 +344,7 @@ public class JdbcMutableAclServiceTests extends AbstractTransactionalJUnit4Sprin
 
     @Test
     @Transactional
-    @Rollback
-    public void testDeleteAclWithChildrenThrowsException() throws Exception {
+    public void deleteAclWithChildrenThrowsException() throws Exception {
         SecurityContextHolder.getContext().setAuthentication(auth);
         MutableAcl parent = jdbcMutableAclService.createAcl(topParentOid);
         MutableAcl child = jdbcMutableAclService.createAcl(middleParentOid);
@@ -364,8 +366,7 @@ public class JdbcMutableAclServiceTests extends AbstractTransactionalJUnit4Sprin
 
     @Test
     @Transactional
-    @Rollback
-    public void testDeleteAclRemovesRowsFromDatabase() throws Exception {
+    public void deleteAclRemovesRowsFromDatabase() throws Exception {
         SecurityContextHolder.getContext().setAuthentication(auth);
         MutableAcl child = jdbcMutableAclService.createAcl(childOid);
         child.insertAce(0, BasePermission.DELETE, new PrincipalSid(auth), false);
@@ -379,13 +380,12 @@ public class JdbcMutableAclServiceTests extends AbstractTransactionalJUnit4Sprin
 
         // Check the cache
         assertNull(aclCache.getFromCache(childOid));
-        assertNull(aclCache.getFromCache(new Long(102)));
+        assertNull(aclCache.getFromCache(Long.valueOf(102)));
     }
 
     /** SEC-1107 */
     @Test
     @Transactional
-    @Rollback
     public void identityWithIntegerIdIsSupportedByCreateAcl() throws Exception {
         SecurityContextHolder.getContext().setAuthentication(auth);
         ObjectIdentity oid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(101));
@@ -397,14 +397,15 @@ public class JdbcMutableAclServiceTests extends AbstractTransactionalJUnit4Sprin
     /**
      * SEC-655
      */
-/*    public void testClearChildrenFromCacheWhenParentIsUpdated() throws Exception {
-        Authentication auth = new TestingAuthenticationToken("ben", "ignored",
-                new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ADMINISTRATOR")});
+    @Test
+    @Transactional
+    public void childrenAreClearedFromCacheWhenParentIsUpdated() throws Exception {
+        Authentication auth = new TestingAuthenticationToken("ben", "ignored","ROLE_ADMINISTRATOR");
         auth.setAuthenticated(true);
         SecurityContextHolder.getContext().setAuthentication(auth);
 
-        ObjectIdentity parentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(104));
-        ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(105));
+        ObjectIdentity parentOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(104));
+        ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(105));
 
         MutableAcl parent = jdbcMutableAclService.createAcl(parentOid);
         MutableAcl child = jdbcMutableAclService.createAcl(childOid);
@@ -413,46 +414,80 @@ public class JdbcMutableAclServiceTests extends AbstractTransactionalJUnit4Sprin
         jdbcMutableAclService.updateAcl(child);
 
         parent = (AclImpl) jdbcMutableAclService.readAclById(parentOid);
-        parent.insertAce(null, BasePermission.READ, new PrincipalSid("ben"), true);
+        parent.insertAce(0, BasePermission.READ, new PrincipalSid("ben"), true);
         jdbcMutableAclService.updateAcl(parent);
 
         parent = (AclImpl) jdbcMutableAclService.readAclById(parentOid);
-        parent.insertAce(null, BasePermission.READ, new PrincipalSid("scott"), true);
+        parent.insertAce(1, BasePermission.READ, new PrincipalSid("scott"), true);
         jdbcMutableAclService.updateAcl(parent);
 
         child = (MutableAcl) jdbcMutableAclService.readAclById(childOid);
         parent = (MutableAcl) child.getParentAcl();
 
         assertEquals("Fails because child has a stale reference to its parent", 2, parent.getEntries().size());
-        assertEquals(1, parent.getEntries()[0].getPermission().getMask());
-        assertEquals(new PrincipalSid("ben"), parent.getEntries()[0].getSid());
-        assertEquals(1, parent.getEntries()[1].getPermission().getMask());
-        assertEquals(new PrincipalSid("scott"), parent.getEntries()[1].getSid());
-    }*/
-
-/*    public void testCumulativePermissions() {
-   setComplete();
-   Authentication auth = new TestingAuthenticationToken("ben", "ignored", new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ADMINISTRATOR")});
-   auth.setAuthenticated(true);
-   SecurityContextHolder.getContext().setAuthentication(auth);
-
-   ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(110));
-   MutableAcl topParent = jdbcMutableAclService.createAcl(topParentOid);
-
-   // Add an ACE permission entry
-   CumulativePermission cm = new CumulativePermission().set(BasePermission.READ).set(BasePermission.ADMINISTRATION);
-   assertEquals(17, cm.getMask());
-       topParent.insertAce(null, cm, new PrincipalSid(auth), true);
+        assertEquals(1, parent.getEntries().get(0).getPermission().getMask());
+        assertEquals(new PrincipalSid("ben"), parent.getEntries().get(0).getSid());
+        assertEquals(1, parent.getEntries().get(1).getPermission().getMask());
+        assertEquals(new PrincipalSid("scott"), parent.getEntries().get(1).getSid());
+    }
+
+    /**
+     * SEC-655
+     */
+    @Test
+    @Transactional
+    public void childrenAreClearedFromCacheWhenParentisUpdated2() throws Exception {
+        Authentication auth = new TestingAuthenticationToken("system", "secret","ROLE_IGNORED");
+        SecurityContextHolder.getContext().setAuthentication(auth);
+        ObjectIdentityImpl rootObject = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(1));
+
+        MutableAcl parent = jdbcMutableAclService.createAcl(rootObject);
+        MutableAcl child = jdbcMutableAclService.createAcl(new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(2)));
+        child.setParent(parent);
+        jdbcMutableAclService.updateAcl(child);
+
+        parent.insertAce(0, BasePermission.ADMINISTRATION, new GrantedAuthoritySid("ROLE_ADMINISTRATOR"), true);
+        jdbcMutableAclService.updateAcl(parent);
+
+        parent.insertAce(1, BasePermission.DELETE, new PrincipalSid("terry"), true);
+        jdbcMutableAclService.updateAcl(parent);
+
+        child = (MutableAcl) jdbcMutableAclService.readAclById(new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(2)));
+
+        parent = (MutableAcl) child.getParentAcl();
+
+        assertEquals(2, parent.getEntries().size());
+        assertEquals(16, parent.getEntries().get(0).getPermission().getMask());
+        assertEquals(new GrantedAuthoritySid("ROLE_ADMINISTRATOR"), parent.getEntries().get(0).getSid());
+        assertEquals(8, parent.getEntries().get(1).getPermission().getMask());
+        assertEquals(new PrincipalSid("terry"), parent.getEntries().get(1).getSid());
+    }
+
+    @Test
+    @Transactional
+    public void cumulativePermissions() {
+       Authentication auth = new TestingAuthenticationToken("ben", "ignored", "ROLE_ADMINISTRATOR");
+       auth.setAuthenticated(true);
+       SecurityContextHolder.getContext().setAuthentication(auth);
+
+       ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(110));
+       MutableAcl topParent = jdbcMutableAclService.createAcl(topParentOid);
+
+       // Add an ACE permission entry
+       Permission cm = new CumulativePermission().set(BasePermission.READ).set(BasePermission.ADMINISTRATION);
+       assertEquals(17, cm.getMask());
+       Sid benSid = new PrincipalSid(auth);
+       topParent.insertAce(0, cm, benSid, true);
        assertEquals(1, topParent.getEntries().size());
 
-       // Explictly save the changed ACL
+       // Explicitly save the changed ACL
        topParent = jdbcMutableAclService.updateAcl(topParent);
 
        // Check the mask was retrieved correctly
-       assertEquals(17, topParent.getEntries()[0].getPermission().getMask());
-       assertTrue(topParent.isGranted(new Permission[] {cm}, pSid, true));
+       assertEquals(17, topParent.getEntries().get(0).getPermission().getMask());
+       assertTrue(topParent.isGranted(Arrays.asList(cm), Arrays.asList(benSid), true));
 
        SecurityContextHolder.clearContext();
    }
- */
+
 }

+ 14 - 0
acl/src/main/resources/jdbcMutableAclServiceTests-context.xml → acl/src/test/resources/jdbcMutableAclServiceTests-context.xml

@@ -54,8 +54,22 @@
         <constructor-arg ref="dataSource"/>
         <constructor-arg ref="lookupStrategy"/>
         <constructor-arg ref="aclCache"/>
+
+<!-- Uncomment to use PostgreSQL
+        <property name="classIdentityQuery" value="select currval(pg_get_serial_sequence('acl_class', 'id'))"/>
+        <property name="sidIdentityQuery" value="select currval(pg_get_serial_sequence('acl_sid', 'id'))"/>
+ -->
     </bean>
 
+<!-- PostgreSQL DataSource configuration
+
+    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
+        <property name="driverClassName" value="org.postgresql.Driver"/>
+        <property name="url" value="jdbc:postgresql://localhost:5432/acltest"/>
+        <property name="username" value="acltest"/>
+        <property name="password" value="acltest"/>
+    </bean>
+ -->
     <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
         <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
         <property name="url" value="jdbc:hsqldb:mem:acltest"/>