|
@@ -0,0 +1,209 @@
|
|
|
|
+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.Authentication;
|
|
|
|
+import org.springframework.security.GrantedAuthority;
|
|
|
|
+import org.springframework.security.GrantedAuthorityImpl;
|
|
|
|
+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.context.SecurityContextHolder;
|
|
|
|
+import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
|
|
|
+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", new GrantedAuthority[] {new GrantedAuthorityImpl("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(null, BasePermission.READ,
|
|
|
|
+ new PrincipalSid("john"), true);
|
|
|
|
+ aclService.updateAcl(parent);
|
|
|
|
+
|
|
|
|
+ parent = (AclImpl) aclService.readAclById(rootObject);
|
|
|
|
+ parent.insertAce(null, 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().length);
|
|
|
|
+ assertEquals(1, parent.getEntries()[0].getPermission().getMask());
|
|
|
|
+ assertEquals(new PrincipalSid("john"), parent.getEntries()[0].getSid());
|
|
|
|
+ assertEquals(1, parent.getEntries()[1].getPermission().getMask());
|
|
|
|
+ assertEquals(new PrincipalSid("joe"), parent.getEntries()[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(null, BasePermission.ADMINISTRATION,
|
|
|
|
+ new GrantedAuthoritySid("ROLE_ADMINISTRATOR"), true);
|
|
|
|
+ aclService.updateAcl(parent);
|
|
|
|
+
|
|
|
|
+ parent.insertAce(null, 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().length);
|
|
|
|
+ assertEquals(16, parent.getEntries()[0].getPermission().getMask());
|
|
|
|
+ assertEquals(new GrantedAuthoritySid("ROLE_ADMINISTRATOR"), parent.getEntries()[0].getSid());
|
|
|
|
+ assertEquals(8, parent.getEntries()[1].getPermission().getMask());
|
|
|
|
+ assertEquals(new PrincipalSid("terry"), parent.getEntries()[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;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|