SEC-925: BasicLookupStrategy - support for schema qualifier. Added setters for ACL SQL statements.
This commit is contained in:
parent
c34d719004
commit
40759ab232
|
@ -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
|
||||
* <code>LookupStrategy</code>. This class does not support subclassing, as it is likely to change in future releases
|
||||
* 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
|
||||
* @version $Id$
|
||||
*/
|
||||
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 ================================================================================================
|
||||
|
||||
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 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 ===================================================================================================
|
||||
|
||||
/**
|
||||
|
@ -106,33 +148,12 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
|||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
private static String computeRepeatingSql(String repeatingSql, int requiredRepetitions) {
|
||||
private String computeRepeatingSql(String repeatingSql, int requiredRepetitions) {
|
||||
assert requiredRepetitions > 0 : "requiredRepetitions must be > 0";
|
||||
|
||||
final String startSql = "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 ( ";
|
||||
final String startSql = selectClause;
|
||||
|
||||
final String endSql = ") order by acl_object_identity.object_id_identity"
|
||||
+ " asc, acl_entry.ace_order asc";
|
||||
final String endSql = orderByClause;
|
||||
|
||||
StringBuilder sqlStringBldr =
|
||||
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.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,
|
||||
new PreparedStatementSetter() {
|
||||
|
@ -358,7 +379,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
|||
|
||||
// Make the "acls" map contain all requested objectIdentities
|
||||
// (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);
|
||||
|
||||
Set parentsToLookup = (Set) jdbcTemplate.query(sql,
|
||||
|
@ -400,11 +421,41 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
|||
return resultMap;
|
||||
}
|
||||
|
||||
|
||||
public void setBatchSize(int 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 ==================================================================================================
|
||||
|
||||
private class ProcessResultSet implements ResultSetExtractor<Set<Long>> {
|
||||
|
@ -479,13 +530,13 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
|||
if (acl == null) {
|
||||
// Make an AclImpl and pop it into the Map
|
||||
ObjectIdentity objectIdentity = new ObjectIdentityImpl(rs.getString("class"),
|
||||
new Long(rs.getLong("object_id_identity")));
|
||||
Long.valueOf(rs.getLong("object_id_identity")));
|
||||
|
||||
Acl parentAcl = null;
|
||||
long parentAclId = rs.getLong("parent_object");
|
||||
|
||||
if (parentAclId != 0) {
|
||||
parentAcl = new StubAclParent(new Long(parentAclId));
|
||||
parentAcl = new StubAclParent(Long.valueOf(parentAclId));
|
||||
}
|
||||
|
||||
boolean entriesInheriting = rs.getBoolean("entries_inheriting");
|
||||
|
|
|
@ -49,7 +49,7 @@ public class JdbcAclService implements AclService {
|
|||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
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 "
|
||||
+ "where obj.parent_object = parent.id and obj.object_id_class = class.id "
|
||||
+ "and parent.object_id_identity = ? and parent.object_id_class = ("
|
||||
|
@ -59,6 +59,7 @@ public class JdbcAclService implements AclService {
|
|||
|
||||
protected JdbcTemplate jdbcTemplate;
|
||||
private LookupStrategy lookupStrategy;
|
||||
private String findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
|
@ -73,7 +74,7 @@ public class JdbcAclService implements AclService {
|
|||
|
||||
public List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) {
|
||||
Object[] args = {parentIdentity.getIdentifier(), parentIdentity.getType()};
|
||||
List<ObjectIdentity> objects = jdbcTemplate.query(selectAclObjectWithParent, args,
|
||||
List<ObjectIdentity> objects = jdbcTemplate.query(findChildrenSql, args,
|
||||
new RowMapper<ObjectIdentity>() {
|
||||
public ObjectIdentity mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
String javaType = rs.getString("class");
|
||||
|
@ -118,4 +119,13 @@ public class JdbcAclService implements AclService {
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows customization of the SQL query used to find child object identities.
|
||||
*
|
||||
* @param findChildrenSql
|
||||
*/
|
||||
public void setFindChildrenQuery(String findChildrenSql) {
|
||||
this.findChildrenSql = findChildrenSql;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,9 @@ import org.springframework.util.Assert;
|
|||
* <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.
|
||||
* {@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>
|
||||
* 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.
|
||||
|
@ -383,6 +385,47 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
|||
Assert.hasText(sidIdentityQuery, "New sidIdentityQuery query is required");
|
||||
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
|
||||
* cause deadlocks (the default is true, so deadlocks are avoided but the database is expected to enforce FKs)
|
||||
|
|
Loading…
Reference in New Issue