Browse Source

SEC-925: BasicLookupStrategy - support for schema qualifier. Added setters for ACL SQL statements.

3.0.x
Luke Taylor 16 years ago
parent
commit
40759ab232
  1. 111
      acl/src/main/java/org/springframework/security/acls/jdbc/BasicLookupStrategy.java
  2. 14
      acl/src/main/java/org/springframework/security/acls/jdbc/JdbcAclService.java
  3. 45
      acl/src/main/java/org/springframework/security/acls/jdbc/JdbcMutableAclService.java

111
acl/src/main/java/org/springframework/security/acls/jdbc/BasicLookupStrategy.java

@ -64,11 +64,47 @@ import org.springframework.util.Assert;
* you are likely to achieve better performance. In such situations you will need to provide your own custom * you are likely to achieve better performance. In such situations you will need to provide your own custom
* <code>LookupStrategy</code>. This class does not support subclassing, as it is likely to change in future releases * <code>LookupStrategy</code>. This class does not support subclassing, as it is likely to change in future releases
* and therefore subclassing is unsupported. * and therefore subclassing is unsupported.
* <p>
* There are two SQL queries executed, one in the <tt>lookupPrimaryKeys</tt> method and one in
* <tt>lookupObjectIdentities</tt>. These are built from the same select and "order by" clause, using a different
* where clause in each case. In order to use custom schema or column names, each of these SQL clauses can be
* customized, but they must be consistent with each other and with the expected result set
* generated by the the default values.
* *
* @author Ben Alex * @author Ben Alex
* @version $Id$ * @version $Id$
*/ */
public final class BasicLookupStrategy implements LookupStrategy { public final class BasicLookupStrategy implements LookupStrategy {
public final static String DEFAULT_SELECT_CLAUSE = "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 "
+ "left join acl_sid acli_sid on acli_sid.id = acl_object_identity.owner_sid "
+ "left join acl_class on acl_class.id = acl_object_identity.object_id_class "
+ "left join acl_entry on acl_object_identity.id = acl_entry.acl_object_identity "
+ "left join acl_sid on acl_entry.sid = acl_sid.id "
+ "where ( ";
private final static String DEFAULT_LOOKUP_KEYS_WHERE_CLAUSE = "(acl_object_identity.id = ?)";
private final static String DEFAULT_LOOKUP_IDENTITIES_WHERE_CLAUSE = "(acl_object_identity.object_id_identity = ? and acl_class.class = ?)";
public final static String DEFAULT_ORDER_BY_CLAUSE = ") order by acl_object_identity.object_id_identity"
+ " asc, acl_entry.ace_order asc";
//~ Instance fields ================================================================================================ //~ Instance fields ================================================================================================
private AclAuthorizationStrategy aclAuthorizationStrategy; private AclAuthorizationStrategy aclAuthorizationStrategy;
@ -81,6 +117,12 @@ public final class BasicLookupStrategy implements LookupStrategy {
private final Field fieldAces = FieldUtils.getField(AclImpl.class, "aces"); private final Field fieldAces = FieldUtils.getField(AclImpl.class, "aces");
private final Field fieldAcl = FieldUtils.getField(AccessControlEntryImpl.class, "acl"); private final Field fieldAcl = FieldUtils.getField(AccessControlEntryImpl.class, "acl");
// SQL Customization fields
private String selectClause = DEFAULT_SELECT_CLAUSE;
private String lookupPrimaryKeysWhereClause = DEFAULT_LOOKUP_KEYS_WHERE_CLAUSE;
private String lookupObjectIdentitiesWhereClause = DEFAULT_LOOKUP_IDENTITIES_WHERE_CLAUSE;
private String orderByClause = DEFAULT_ORDER_BY_CLAUSE;
//~ Constructors =================================================================================================== //~ Constructors ===================================================================================================
/** /**
@ -106,33 +148,12 @@ public final class BasicLookupStrategy implements LookupStrategy {
//~ Methods ======================================================================================================== //~ Methods ========================================================================================================
private static String computeRepeatingSql(String repeatingSql, int requiredRepetitions) { private String computeRepeatingSql(String repeatingSql, int requiredRepetitions) {
assert requiredRepetitions > 0 : "requiredRepetitions must be > 0"; assert requiredRepetitions > 0 : "requiredRepetitions must be > 0";
final String startSql = "select acl_object_identity.object_id_identity, " final String startSql = selectClause;
+ "acl_entry.ace_order, "
+ "acl_object_identity.id as acl_id, " final String endSql = orderByClause;
+ "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 "
+ "left join acl_sid acli_sid on acli_sid.id = acl_object_identity.owner_sid "
+ "left join acl_class on acl_class.id = acl_object_identity.object_id_class "
+ "left join acl_entry on acl_object_identity.id = acl_entry.acl_object_identity "
+ "left join acl_sid on acl_entry.sid = acl_sid.id "
+ "where ( ";
final String endSql = ") order by acl_object_identity.object_id_identity"
+ " asc, acl_entry.ace_order asc";
StringBuilder sqlStringBldr = StringBuilder sqlStringBldr =
new StringBuilder(startSql.length() + endSql.length() + requiredRepetitions * (repeatingSql.length() + 4)); new StringBuilder(startSql.length() + endSql.length() + requiredRepetitions * (repeatingSql.length() + 4));
@ -239,7 +260,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
Assert.notNull(acls, "ACLs are required"); Assert.notNull(acls, "ACLs are required");
Assert.notEmpty(findNow, "Items to find now required"); Assert.notEmpty(findNow, "Items to find now required");
String sql = computeRepeatingSql("(acl_object_identity.id = ?)", findNow.size()); String sql = computeRepeatingSql(lookupPrimaryKeysWhereClause, findNow.size());
Set<Long> parentsToLookup = jdbcTemplate.query(sql, Set<Long> parentsToLookup = jdbcTemplate.query(sql,
new PreparedStatementSetter() { new PreparedStatementSetter() {
@ -358,7 +379,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
// Make the "acls" map contain all requested objectIdentities // Make the "acls" map contain all requested objectIdentities
// (including markers to each parent in the hierarchy) // (including markers to each parent in the hierarchy)
String sql = computeRepeatingSql("(acl_object_identity.object_id_identity = ? and acl_class.class = ?)", String sql = computeRepeatingSql(lookupObjectIdentitiesWhereClause ,
objectIdentities.length); objectIdentities.length);
Set parentsToLookup = (Set) jdbcTemplate.query(sql, Set parentsToLookup = (Set) jdbcTemplate.query(sql,
@ -400,11 +421,41 @@ public final class BasicLookupStrategy implements LookupStrategy {
return resultMap; return resultMap;
} }
public void setBatchSize(int batchSize) { public void setBatchSize(int batchSize) {
this.batchSize = batchSize; this.batchSize = batchSize;
} }
/**
* The SQL for the select clause. If customizing in order to modify
* column names, schema etc, the other SQL customization fields must also be set to match.
*
* @param selectClause the select clause, which defaults to {@link #DEFAULT_SELECT_CLAUSE}.
*/
public 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) {
this.lookupPrimaryKeysWhereClause = lookupPrimaryKeysWhereClause;
}
/**
* The SQL for the where clause used in the <tt>lookupObjectIdentities</tt> method.
*/
public void setLookupObjectIdentitiesWhereClause(String lookupObjectIdentitiesWhereClause) {
this.lookupObjectIdentitiesWhereClause = lookupObjectIdentitiesWhereClause;
}
/**
* The SQL for the "order by" clause used in both queries.
*/
public void setOrderByClause(String orderByClause) {
this.orderByClause = orderByClause;
}
//~ Inner Classes ================================================================================================== //~ Inner Classes ==================================================================================================
private class ProcessResultSet implements ResultSetExtractor<Set<Long>> { private class ProcessResultSet implements ResultSetExtractor<Set<Long>> {
@ -479,13 +530,13 @@ public final class BasicLookupStrategy implements LookupStrategy {
if (acl == null) { if (acl == null) {
// Make an AclImpl and pop it into the Map // Make an AclImpl and pop it into the Map
ObjectIdentity objectIdentity = new ObjectIdentityImpl(rs.getString("class"), ObjectIdentity objectIdentity = new ObjectIdentityImpl(rs.getString("class"),
new Long(rs.getLong("object_id_identity"))); Long.valueOf(rs.getLong("object_id_identity")));
Acl parentAcl = null; Acl parentAcl = null;
long parentAclId = rs.getLong("parent_object"); long parentAclId = rs.getLong("parent_object");
if (parentAclId != 0) { if (parentAclId != 0) {
parentAcl = new StubAclParent(new Long(parentAclId)); parentAcl = new StubAclParent(Long.valueOf(parentAclId));
} }
boolean entriesInheriting = rs.getBoolean("entries_inheriting"); boolean entriesInheriting = rs.getBoolean("entries_inheriting");

14
acl/src/main/java/org/springframework/security/acls/jdbc/JdbcAclService.java

@ -49,7 +49,7 @@ public class JdbcAclService implements AclService {
//~ Static fields/initializers ===================================================================================== //~ Static fields/initializers =====================================================================================
protected static final Log log = LogFactory.getLog(JdbcAclService.class); protected static final Log log = LogFactory.getLog(JdbcAclService.class);
private static final String selectAclObjectWithParent = "select obj.object_id_identity as obj_id, class.class as class " private static final String DEFAULT_SELECT_ACL_WITH_PARENT_SQL = "select obj.object_id_identity as obj_id, class.class as class "
+ "from acl_object_identity obj, acl_object_identity parent, acl_class class " + "from acl_object_identity obj, acl_object_identity parent, acl_class class "
+ "where obj.parent_object = parent.id and obj.object_id_class = class.id " + "where obj.parent_object = parent.id and obj.object_id_class = class.id "
+ "and parent.object_id_identity = ? and parent.object_id_class = (" + "and parent.object_id_identity = ? and parent.object_id_class = ("
@ -59,6 +59,7 @@ public class JdbcAclService implements AclService {
protected JdbcTemplate jdbcTemplate; protected JdbcTemplate jdbcTemplate;
private LookupStrategy lookupStrategy; private LookupStrategy lookupStrategy;
private String findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL;
//~ Constructors =================================================================================================== //~ Constructors ===================================================================================================
@ -73,7 +74,7 @@ public class JdbcAclService implements AclService {
public List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) { public List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) {
Object[] args = {parentIdentity.getIdentifier(), parentIdentity.getType()}; Object[] args = {parentIdentity.getIdentifier(), parentIdentity.getType()};
List<ObjectIdentity> objects = jdbcTemplate.query(selectAclObjectWithParent, args, List<ObjectIdentity> objects = jdbcTemplate.query(findChildrenSql, args,
new RowMapper<ObjectIdentity>() { new RowMapper<ObjectIdentity>() {
public ObjectIdentity mapRow(ResultSet rs, int rowNum) throws SQLException { public ObjectIdentity mapRow(ResultSet rs, int rowNum) throws SQLException {
String javaType = rs.getString("class"); String javaType = rs.getString("class");
@ -118,4 +119,13 @@ public class JdbcAclService implements AclService {
return result; return result;
} }
/**
* Allows customization of the SQL query used to find child object identities.
*
* @param findChildrenSql
*/
public void setFindChildrenQuery(String findChildrenSql) {
this.findChildrenSql = findChildrenSql;
}
} }

45
acl/src/main/java/org/springframework/security/acls/jdbc/JdbcMutableAclService.java

@ -47,7 +47,9 @@ import org.springframework.util.Assert;
* <p> * <p>
* The default settings are for HSQLDB. If you are using a different database you * 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 * will probably need to set the {@link #setSidIdentityQuery(String) sidIdentityQuery} and
* {@link #setClassIdentityQuery(String) classIdentityQuery} properties appropriately. * {@link #setClassIdentityQuery(String) classIdentityQuery} properties appropriately. The other queries,
* SQL inserts and updates can also be customized to accomodate schema variations, but must produce results
* consistent with those expected by the defaults.
* <p> * <p>
* See the appendix of the Spring Security reference manual for more information on the expected schema * 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. * and how it is used. Information on using PostgreSQL is also included.
@ -383,6 +385,47 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
Assert.hasText(sidIdentityQuery, "New sidIdentityQuery query is required"); Assert.hasText(sidIdentityQuery, "New sidIdentityQuery query is required");
this.sidIdentityQuery = sidIdentityQuery; this.sidIdentityQuery = sidIdentityQuery;
} }
public void setDeleteEntryByObjectIdentityForeignKeySql(String deleteEntryByObjectIdentityForeignKey) {
this.deleteEntryByObjectIdentityForeignKey = deleteEntryByObjectIdentityForeignKey;
}
public void setDeleteObjectIdentityByPrimaryKeySql(String deleteObjectIdentityByPrimaryKey) {
this.deleteObjectIdentityByPrimaryKey = deleteObjectIdentityByPrimaryKey;
}
public void setInsertClassSql(String insertClass) {
this.insertClass = insertClass;
}
public void setInsertEntrySql(String insertEntry) {
this.insertEntry = insertEntry;
}
public void setInsertObjectIdentitySql(String insertObjectIdentity) {
this.insertObjectIdentity = insertObjectIdentity;
}
public void setInsertSidSql(String insertSid) {
this.insertSid = insertSid;
}
public void setClassPrimaryKeyQuery(String selectClassPrimaryKey) {
this.selectClassPrimaryKey = selectClassPrimaryKey;
}
public void setObjectIdentityPrimaryKeyQuery(String selectObjectIdentityPrimaryKey) {
this.selectObjectIdentityPrimaryKey = selectObjectIdentityPrimaryKey;
}
public void setSidPrimaryKeyQuery(String selectSidPrimaryKey) {
this.selectSidPrimaryKey = selectSidPrimaryKey;
}
public void setUpdateObjectIdentity(String updateObjectIdentity) {
this.updateObjectIdentity = updateObjectIdentity;
}
/** /**
* @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
* cause deadlocks (the default is true, so deadlocks are avoided but the database is expected to enforce FKs) * cause deadlocks (the default is true, so deadlocks are avoided but the database is expected to enforce FKs)

Loading…
Cancel
Save