From c6dfee69d4623cff7326c333a4b9c4bb366cfb8a Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Wed, 6 May 2009 14:29:53 +0000 Subject: [PATCH] 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. --- acl/pom.xml | 7 + .../acls/jdbc/JdbcMutableAclService.java | 39 +++- acl/src/main/resources/createAclSchema.sql | 77 +++---- .../resources/createAclSchemaPostgres.sql | 46 ++++ acl/src/main/resources/select.sql | 52 +++-- .../jdbc/AclPermissionInheritanceTests.java | 208 ------------------ .../acls/jdbc/JdbcMutableAclServiceTests.java | 139 +++++++----- .../jdbcMutableAclServiceTests-context.xml | 14 ++ 8 files changed, 255 insertions(+), 327 deletions(-) create mode 100644 acl/src/main/resources/createAclSchemaPostgres.sql delete mode 100644 acl/src/test/java/org/springframework/security/acls/jdbc/AclPermissionInheritanceTests.java rename acl/src/{main => test}/resources/jdbcMutableAclServiceTests-context.xml (79%) diff --git a/acl/pom.xml b/acl/pom.xml index 07f9bd9271..d27e35e1ab 100644 --- a/acl/pom.xml +++ b/acl/pom.xml @@ -47,6 +47,13 @@ hsqldb test + + postgresql + postgresql + 8.3-603.jdbc3 + test + + diff --git a/acl/src/main/java/org/springframework/security/acls/jdbc/JdbcMutableAclService.java b/acl/src/main/java/org/springframework/security/acls/jdbc/JdbcMutableAclService.java index d1f6ead2bd..cfb3ddcb1d 100644 --- a/acl/src/main/java/org/springframework/security/acls/jdbc/JdbcMutableAclService.java +++ b/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}. + *

+ * 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. + *

+ * 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 acl_class + * table. + * + * @param classIdentityQuery the query, which should return the identifier. Defaults to call identity() + */ + 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 acl_sid + * table. + * + * @param sidIdentityQuery the query, which should return the identifier. Defaults to call identity() + */ + 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 diff --git a/acl/src/main/resources/createAclSchema.sql b/acl/src/main/resources/createAclSchema.sql index 37422e5cba..1bb65cd0cb 100644 --- a/acl/src/main/resources/createAclSchema.sql +++ b/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) +); diff --git a/acl/src/main/resources/createAclSchemaPostgres.sql b/acl/src/main/resources/createAclSchemaPostgres.sql new file mode 100644 index 0000000000..ca07680065 --- /dev/null +++ b/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) +); diff --git a/acl/src/main/resources/select.sql b/acl/src/main/resources/select.sql index 2a641735ba..4e9486c83c 100644 --- a/acl/src/main/resources/select.sql +++ b/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 +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 +from acl_object_identity, + acl_sid acli_sid, + acl_class -where +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 -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 diff --git a/acl/src/test/java/org/springframework/security/acls/jdbc/AclPermissionInheritanceTests.java b/acl/src/test/java/org/springframework/security/acls/jdbc/AclPermissionInheritanceTests.java deleted file mode 100644 index 2368f1e79e..0000000000 --- a/acl/src/test/java/org/springframework/security/acls/jdbc/AclPermissionInheritanceTests.java +++ /dev/null @@ -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; - } - } -} diff --git a/acl/src/test/java/org/springframework/security/acls/jdbc/JdbcMutableAclServiceTests.java b/acl/src/test/java/org/springframework/security/acls/jdbc/JdbcMutableAclServiceTests.java index a41784c68c..30c8cb6ff1 100644 --- a/acl/src/test/java/org/springframework/security/acls/jdbc/JdbcMutableAclServiceTests.java +++ b/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()); - }*/ + 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()); + } -/* public void testCumulativePermissions() { - setComplete(); - Authentication auth = new TestingAuthenticationToken("ben", "ignored", new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ADMINISTRATOR")}); - auth.setAuthenticated(true); - SecurityContextHolder.getContext().setAuthentication(auth); + /** + * 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)); - ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(110)); - MutableAcl topParent = jdbcMutableAclService.createAcl(topParentOid); + MutableAcl parent = jdbcMutableAclService.createAcl(rootObject); + MutableAcl child = jdbcMutableAclService.createAcl(new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(2))); + child.setParent(parent); + jdbcMutableAclService.updateAcl(child); - // 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); + 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(); } - */ + } diff --git a/acl/src/main/resources/jdbcMutableAclServiceTests-context.xml b/acl/src/test/resources/jdbcMutableAclServiceTests-context.xml similarity index 79% rename from acl/src/main/resources/jdbcMutableAclServiceTests-context.xml rename to acl/src/test/resources/jdbcMutableAclServiceTests-context.xml index 93c7b61dfa..41ae84fb03 100644 --- a/acl/src/main/resources/jdbcMutableAclServiceTests-context.xml +++ b/acl/src/test/resources/jdbcMutableAclServiceTests-context.xml @@ -54,8 +54,22 @@ + + +