浏览代码

Added possibility create custom Sid

Mikhail Stryzhonok 11 年之前
父节点
当前提交
f20219d541

+ 12 - 1
acl/src/main/java/org/springframework/security/acls/domain/AclAuthorizationStrategyImpl.java

@@ -87,7 +87,7 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
         Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
 
         // Check if authorized by virtue of ACL ownership
-        Sid currentUser = new PrincipalSid(authentication);
+        Sid currentUser = createCurrentUser(authentication);
 
         if (currentUser.equals(acl.getOwner())
                 && ((changeType == CHANGE_GENERAL) || (changeType == CHANGE_OWNERSHIP))) {
@@ -123,6 +123,17 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
                 "Principal does not have required ACL permissions to perform requested operation");
     }
 
+    /**
+     * Creates a principal-like sid from the authentication information.
+     *
+     * @param authentication the authentication information that can provide principal and thus the sid's id will be
+     *                       dependant on the value inside
+     * @return a sid with the ID taken from the authentication information
+     */
+    protected Sid createCurrentUser(Authentication authentication) {
+        return new PrincipalSid(authentication);
+    }
+
     public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
         Assert.notNull(sidRetrievalStrategy, "SidRetrievalStrategy required");
         this.sidRetrievalStrategy = sidRetrievalStrategy;

+ 26 - 22
acl/src/main/java/org/springframework/security/acls/jdbc/BasicLookupStrategy.java

@@ -74,7 +74,7 @@ import org.springframework.util.Assert;
  *
  * @author Ben Alex
  */
-public final class BasicLookupStrategy implements LookupStrategy {
+public class BasicLookupStrategy implements LookupStrategy {
 
     public final static String DEFAULT_SELECT_CLAUSE = "select acl_object_identity.object_id_identity, "
         + "acl_entry.ace_order,  "
@@ -256,7 +256,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
      *         should not throw {@link NotFoundException}, as a chain of {@link LookupStrategy}s may be used
      *         to automatically create entries if required)
      */
-    public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) {
+    public final Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) {
         Assert.isTrue(batchSize >= 1, "BatchSize must be >= 1");
         Assert.notEmpty(objects, "Objects to lookup required");
 
@@ -428,17 +428,33 @@ public final class BasicLookupStrategy implements LookupStrategy {
         return result;
     }
 
+    /**
+     * Creates a particular implementation of {@link Sid} depending on the arguments.
+     *
+     * @param sid   the name of the sid representing its unique identifier. In typical ACL database schema it's
+     *                  located in table {@code acl_sid} table, {@code sid} column.
+     * @param isPrincipal whether it's a user or granted authority like role
+     * @return the instance of Sid with the {@code sidName} as an identifier
+     */
+    protected Sid createSid(boolean isPrincipal, String sid) {
+        if (isPrincipal) {
+            return new PrincipalSid(sid);
+        } else {
+            return new GrantedAuthoritySid(sid);
+        }
+    }
+
     /**
      * Sets the {@code PermissionFactory} instance which will be used to convert loaded permission
      * data values to {@code Permission}s. A {@code DefaultPermissionFactory} will be used by default.
      *
      * @param permissionFactory
      */
-    public void setPermissionFactory(PermissionFactory permissionFactory) {
+    public final void setPermissionFactory(PermissionFactory permissionFactory) {
         this.permissionFactory = permissionFactory;
     }
 
-    public void setBatchSize(int batchSize) {
+    public final void setBatchSize(int batchSize) {
         this.batchSize = batchSize;
     }
 
@@ -448,28 +464,28 @@ public final class BasicLookupStrategy implements LookupStrategy {
      *
      * @param selectClause the select clause, which defaults to {@link #DEFAULT_SELECT_CLAUSE}.
      */
-    public void setSelectClause(String selectClause) {
+    public final void setSelectClause(String selectClause) {
         this.selectClause = selectClause;
     }
 
     /**
      * The SQL for the where clause used in the <tt>lookupPrimaryKey</tt> method.
      */
-    public void setLookupPrimaryKeysWhereClause(String lookupPrimaryKeysWhereClause) {
+    public final void setLookupPrimaryKeysWhereClause(String lookupPrimaryKeysWhereClause) {
         this.lookupPrimaryKeysWhereClause = lookupPrimaryKeysWhereClause;
     }
 
     /**
      * The SQL for the where clause used in the <tt>lookupObjectIdentities</tt> method.
      */
-    public void setLookupObjectIdentitiesWhereClause(String lookupObjectIdentitiesWhereClause) {
+    public final void setLookupObjectIdentitiesWhereClause(String lookupObjectIdentitiesWhereClause) {
         this.lookupObjectIdentitiesWhereClause = lookupObjectIdentitiesWhereClause;
     }
 
     /**
      * The SQL for the "order by" clause used in both queries.
      */
-    public void setOrderByClause(String orderByClause) {
+    public final void setOrderByClause(String orderByClause) {
         this.orderByClause = orderByClause;
     }
 
@@ -556,13 +572,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
                 }
 
                 boolean entriesInheriting = rs.getBoolean("entries_inheriting");
-                Sid owner;
-
-                if (rs.getBoolean("acl_principal")) {
-                    owner = new PrincipalSid(rs.getString("acl_sid"));
-                } else {
-                    owner = new GrantedAuthoritySid(rs.getString("acl_sid"));
-                }
+                Sid owner = createSid(rs.getBoolean("acl_principal"), rs.getString("acl_sid"));
 
                 acl = new AclImpl(objectIdentity, id, aclAuthorizationStrategy, grantingStrategy, parentAcl, null,
                         entriesInheriting, owner);
@@ -574,13 +584,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
             // It is permissible to have no ACEs in an ACL (which is detected by a null ACE_SID)
             if (rs.getString("ace_sid") != null) {
                 Long aceId = new Long(rs.getLong("ace_id"));
-                Sid recipient;
-
-                if (rs.getBoolean("ace_principal")) {
-                    recipient = new PrincipalSid(rs.getString("ace_sid"));
-                } else {
-                    recipient = new GrantedAuthoritySid(rs.getString("ace_sid"));
-                }
+                Sid recipient = createSid(rs.getBoolean("ace_principal"), rs.getString("ace_sid"));
 
                 int mask = rs.getInt("mask");
                 Permission permission = permissionFactory.buildFromMask(mask);

+ 13 - 0
acl/src/main/java/org/springframework/security/acls/jdbc/JdbcMutableAclService.java

@@ -209,6 +209,19 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
             throw new IllegalArgumentException("Unsupported implementation of Sid");
         }
 
+        return createOrRetrieveSidPrimaryKey(sidName, sidIsPrincipal, allowCreate);
+    }
+
+    /**
+     * Retrieves the primary key from acl_sid, creating a new row if needed and the allowCreate property is
+     * true.
+     * @param sidName name of Sid to find or to create
+     * @param sidIsPrincipal whether it's a user or granted authority like role
+     * @param allowCreate true if creation is permitted if not found
+     * @return the primary key or null if not found
+     */
+    protected Long createOrRetrieveSidPrimaryKey(String sidName, boolean sidIsPrincipal, boolean allowCreate) {
+
         List<Long> sidIds = jdbcTemplate.queryForList(selectSidPrimaryKey,
                 new Object[] {Boolean.valueOf(sidIsPrincipal), sidName},  Long.class);
 

+ 17 - 9
acl/src/test/java/org/springframework/security/acls/jdbc/BasicLookupStrategyTests.java

@@ -9,15 +9,7 @@ import org.springframework.core.io.ClassPathResource;
 import org.springframework.core.io.Resource;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.jdbc.datasource.SingleConnectionDataSource;
-import org.springframework.security.acls.domain.AclAuthorizationStrategy;
-import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
-import org.springframework.security.acls.domain.BasePermission;
-import org.springframework.security.acls.domain.ConsoleAuditLogger;
-import org.springframework.security.acls.domain.DefaultPermissionFactory;
-import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy;
-import org.springframework.security.acls.domain.EhCacheBasedAclCache;
-import org.springframework.security.acls.domain.ObjectIdentityImpl;
-import org.springframework.security.acls.domain.PrincipalSid;
+import org.springframework.security.acls.domain.*;
 import org.springframework.security.acls.model.Acl;
 import org.springframework.security.acls.model.AuditableAccessControlEntry;
 import org.springframework.security.acls.model.MutableAcl;
@@ -301,4 +293,20 @@ public class BasicLookupStrategyTests {
         strategy.readAclsById(Arrays.asList(oid), Arrays.asList(BEN_SID));
     }
 
+    @Test
+    public void testCreatePrincipalSid() {
+        Sid result = strategy.createSid(true, "sid");
+
+        Assert.assertEquals(PrincipalSid.class, result.getClass());
+        Assert.assertEquals("sid", ((PrincipalSid)result).getPrincipal());
+    }
+
+    @Test
+    public void testCreateGrantedAuthority() {
+        Sid result = strategy.createSid(false, "sid");
+
+        Assert.assertEquals(GrantedAuthoritySid.class, result.getClass());
+        Assert.assertEquals("sid", ((GrantedAuthoritySid)result).getGrantedAuthority());
+    }
+
 }

+ 40 - 1
acl/src/test/java/org/springframework/security/acls/jdbc/JdbcMutableAclServiceTests.java

@@ -15,6 +15,7 @@
 package org.springframework.security.acls.jdbc;
 
 import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
 
 import java.util.Arrays;
 import java.util.List;
@@ -43,6 +44,7 @@ import org.springframework.security.acls.model.NotFoundException;
 import org.springframework.security.acls.model.ObjectIdentity;
 import org.springframework.security.acls.model.Permission;
 import org.springframework.security.acls.model.Sid;
+import org.springframework.security.acls.sid.CustomSid;
 import org.springframework.security.authentication.TestingAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContextHolder;
@@ -489,6 +491,43 @@ public class JdbcMutableAclServiceTests extends AbstractTransactionalJUnit4Sprin
        assertTrue(topParent.isGranted(Arrays.asList(cm), Arrays.asList(benSid), true));
 
        SecurityContextHolder.clearContext();
-   }
+    }
+    @Test
+    public void testProcessingCustomSid() {
+        CustomJdbcMutableAclService customJdbcMutableAclService = spy(new CustomJdbcMutableAclService(dataSource,
+                lookupStrategy, aclCache));
+        CustomSid customSid = new CustomSid("Custom sid");
+        when(customJdbcMutableAclService.createOrRetrieveSidPrimaryKey("Custom sid", false, false)).thenReturn(1L);
+
+        Long result = customJdbcMutableAclService.createOrRetrieveSidPrimaryKey(customSid, false);
+
+        assertEquals(result, new Long(1L));
+    }
+
+    /**
+     * This class needed to show how to extend {@link JdbcMutableAclService} for processing
+     * custom {@link Sid} implementations
+     */
+    private class CustomJdbcMutableAclService extends JdbcMutableAclService {
+
+        private CustomJdbcMutableAclService(DataSource dataSource, LookupStrategy lookupStrategy, AclCache aclCache) {
+            super(dataSource, lookupStrategy, aclCache);
+        }
+
+        @Override
+        protected Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
+            String sidName;
+            boolean isPrincipal = false;
+            if (sid instanceof CustomSid) {
+                sidName = ((CustomSid)sid).getSid();
+            } else if (sid instanceof GrantedAuthoritySid) {
+                sidName = ((GrantedAuthoritySid)sid).getGrantedAuthority();
+            } else {
+                sidName = ((PrincipalSid)sid).getPrincipal();
+                isPrincipal = true;
+            }
+            return createOrRetrieveSidPrimaryKey(sidName, isPrincipal, allowCreate);
+        }
+    }
 
 }

+ 24 - 0
acl/src/test/java/org/springframework/security/acls/sid/CustomSid.java

@@ -0,0 +1,24 @@
+package org.springframework.security.acls.sid;
+
+import org.springframework.security.acls.model.Sid;
+
+/**
+ * This class is example of custom {@link Sid} implementation
+ * @author Mikhail Stryzhonok
+ */
+public class CustomSid implements Sid {
+
+    private String sid;
+
+    public CustomSid(String sid) {
+        this.sid = sid;
+    }
+
+    public String getSid() {
+        return sid;
+    }
+
+    public void setSid(String sid) {
+        this.sid = sid;
+    }
+}