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.

This commit is contained in:
Luke Taylor 2009-05-06 14:29:53 +00:00
parent 29fafbbf18
commit c6dfee69d4
8 changed files with 255 additions and 327 deletions

View File

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

View File

@ -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 Ben Alex
* @author Johannes Zlattinger * @author Johannes Zlattinger
@ -55,8 +62,8 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
private AclCache aclCache; private AclCache aclCache;
private String deleteEntryByObjectIdentityForeignKey = "delete from acl_entry where acl_object_identity=?"; private String deleteEntryByObjectIdentityForeignKey = "delete from acl_entry where acl_object_identity=?";
private String deleteObjectIdentityByPrimaryKey = "delete from acl_object_identity where id=?"; 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 classIdentityQuery = "call identity()";
private String sidIdentityQuery = "call identity()"; // should be overridden for postgres : select currval('acl_siq_seq') private String sidIdentityQuery = "call identity()";
private String insertClass = "insert into acl_class (class) values (?)"; private String insertClass = "insert into acl_class (class) values (?)";
private String insertEntry = "insert into acl_entry " private String insertEntry = "insert into acl_entry "
+ "(acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure)" + "(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) { protected void createObjectIdentity(ObjectIdentity object, Sid owner) {
Long sidId = createOrRetrieveSidPrimaryKey(owner, true); Long sidId = createOrRetrieveSidPrimaryKey(owner, true);
Long classId = createOrRetrieveClassPrimaryKey(object.getJavaType(), 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"); * Sets the query that will be used to retrieve the identity of a newly created row in the <tt>acl_class</tt>
this.classIdentityQuery = identityQuery; * 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"); * Sets the query that will be used to retrieve the identity of a newly created row in the <tt>acl_sid</tt>
this.sidIdentityQuery = identityQuery; * 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 * @param foreignKeysInDatabase if false this class will perform additional FK constrain checking, which may

View File

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

View File

@ -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)
);

View File

@ -1,27 +1,39 @@
-- Not required. Just shows the sort of queries being sent to DB. -- Not required. Just shows the sort of queries being sent to DB.
select ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY, ACL_ENTRY.ACE_ORDER, select acl_object_identity.object_id_identity,
ACL_OBJECT_IDENTITY.ID as ACL_ID, acl_entry.ace_order,
ACL_OBJECT_IDENTITY.PARENT_OBJECT, acl_object_identity.id as acl_id,
ACL_OBJECT_IDENTITY,ENTRIES_INHERITING, acl_object_identity.parent_object,
ACL_ENTRY.ID as ACE_ID, ACL_ENTRY.MASK, ACL_ENTRY.GRANTING, ACL_ENTRY.AUDIT_SUCCESS, ACL_ENTRY.AUDIT_FAILURE, acl_object_identity,
ACL_SID.PRINCIPAL as ACE_PRINCIPAL, ACL_SID.SID as ACE_SID, entries_inheriting,
ACLI_SID.PRINCIPAL as ACL_PRINCIPAL, ACLI_SID.SID as ACL_SID, acl_entry.id as ace_id,
ACL_CLASS.CLASS 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 from acl_object_identity,
LEFT JOIN ACL_ENTRY ON ACL_OBJECT_IDENTITY.ID = ACL_ENTRY.ACL_OBJECT_IDENTITY acl_sid acli_sid,
LEFT JOIN ACL_SID ON ACL_ENTRY.SID = ACL_SID.ID 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 ( and (
(ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY = 1
and ACL_CLASS.CLASS = 'sample.contact.Contact') (acl_object_identity.object_id_identity = 1 and acl_class.class = 'sample.contact.contact')
or or
(ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY = 2000 (acl_object_identity.object_id_identity = 2000 and acl_class.class = 'sample.contact.contact')
and ACL_CLASS.CLASS = 'sample.contact.Contact')
) order by ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY asc, ACL_ENTRY.ACE_ORDER asc ) order by acl_object_identity.object_id_identity asc, acl_entry.ace_order asc

View File

@ -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;
}
}
}

View File

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

View File

@ -54,8 +54,22 @@
<constructor-arg ref="dataSource"/> <constructor-arg ref="dataSource"/>
<constructor-arg ref="lookupStrategy"/> <constructor-arg ref="lookupStrategy"/>
<constructor-arg ref="aclCache"/> <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> </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"> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/> <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:mem:acltest"/> <property name="url" value="jdbc:hsqldb:mem:acltest"/>