Add ObjectIdentityGenerator customization to JdbcAclService

Providing the possibility to change, how ObjectIdentitys are created inside the BasicLookupStrategy,JdbcAclService

There was a problem with hard coded object identity creation inside the BasicLookupStrategy and the JdbcAclService. It was overkill to overwrite
these classes only for changing this, so introducing an ObjectIdentityGenerator seems the be the better solution here. At default, the standard
ObjectIdentityRetrievalStrategyImpl is used, but can be customized due to setters.

Closes gh-10079
This commit is contained in:
Jonas Dittrich 2021-07-15 14:03:05 +02:00 committed by Steve Riesenberg
parent 04161b9288
commit 86193b9540
2 changed files with 121 additions and 102 deletions

View File

@ -35,6 +35,7 @@ import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.security.acls.domain.*;
import org.springframework.security.acls.domain.AccessControlEntryImpl; import org.springframework.security.acls.domain.AccessControlEntryImpl;
import org.springframework.security.acls.domain.AclAuthorizationStrategy; import org.springframework.security.acls.domain.AclAuthorizationStrategy;
import org.springframework.security.acls.domain.AclImpl; import org.springframework.security.acls.domain.AclImpl;
@ -42,7 +43,6 @@ import org.springframework.security.acls.domain.AuditLogger;
import org.springframework.security.acls.domain.DefaultPermissionFactory; import org.springframework.security.acls.domain.DefaultPermissionFactory;
import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy; import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy;
import org.springframework.security.acls.domain.GrantedAuthoritySid; import org.springframework.security.acls.domain.GrantedAuthoritySid;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.domain.PermissionFactory; import org.springframework.security.acls.domain.PermissionFactory;
import org.springframework.security.acls.domain.PrincipalSid; import org.springframework.security.acls.domain.PrincipalSid;
import org.springframework.security.acls.model.AccessControlEntry; import org.springframework.security.acls.model.AccessControlEntry;
@ -51,6 +51,7 @@ import org.springframework.security.acls.model.AclCache;
import org.springframework.security.acls.model.MutableAcl; import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.NotFoundException; import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.ObjectIdentity; import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.ObjectIdentityGenerator;
import org.springframework.security.acls.model.Permission; import org.springframework.security.acls.model.Permission;
import org.springframework.security.acls.model.PermissionGrantingStrategy; import org.springframework.security.acls.model.PermissionGrantingStrategy;
import org.springframework.security.acls.model.Sid; import org.springframework.security.acls.model.Sid;
@ -109,6 +110,8 @@ public class BasicLookupStrategy implements LookupStrategy {
private final AclAuthorizationStrategy aclAuthorizationStrategy; private final AclAuthorizationStrategy aclAuthorizationStrategy;
private ObjectIdentityGenerator objectIdentityGenerator;
private PermissionFactory permissionFactory = new DefaultPermissionFactory(); private PermissionFactory permissionFactory = new DefaultPermissionFactory();
private final AclCache aclCache; private final AclCache aclCache;
@ -134,6 +137,7 @@ public class BasicLookupStrategy implements LookupStrategy {
private AclClassIdUtils aclClassIdUtils; private AclClassIdUtils aclClassIdUtils;
/** /**
* Constructor accepting mandatory arguments * Constructor accepting mandatory arguments
* @param dataSource to access the database * @param dataSource to access the database
@ -154,6 +158,7 @@ public class BasicLookupStrategy implements LookupStrategy {
*/ */
public BasicLookupStrategy(DataSource dataSource, AclCache aclCache, public BasicLookupStrategy(DataSource dataSource, AclCache aclCache,
AclAuthorizationStrategy aclAuthorizationStrategy, PermissionGrantingStrategy grantingStrategy) { AclAuthorizationStrategy aclAuthorizationStrategy, PermissionGrantingStrategy grantingStrategy) {
Assert.notNull(dataSource, "DataSource required"); Assert.notNull(dataSource, "DataSource required");
Assert.notNull(aclCache, "AclCache required"); Assert.notNull(aclCache, "AclCache required");
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required"); Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
@ -162,6 +167,7 @@ public class BasicLookupStrategy implements LookupStrategy {
this.aclCache = aclCache; this.aclCache = aclCache;
this.aclAuthorizationStrategy = aclAuthorizationStrategy; this.aclAuthorizationStrategy = aclAuthorizationStrategy;
this.grantingStrategy = grantingStrategy; this.grantingStrategy = grantingStrategy;
this.objectIdentityGenerator = new ObjectIdentityRetrievalStrategyImpl();
this.aclClassIdUtils = new AclClassIdUtils(); this.aclClassIdUtils = new AclClassIdUtils();
this.fieldAces.setAccessible(true); this.fieldAces.setAccessible(true);
this.fieldAcl.setAccessible(true); this.fieldAcl.setAccessible(true);
@ -488,6 +494,11 @@ public class BasicLookupStrategy implements LookupStrategy {
} }
} }
public void setObjectIdentityGenerator(ObjectIdentityGenerator objectIdentityGenerator) {
Assert.notNull(objectIdentityGenerator,"The provided strategy has to be not null!");
this.objectIdentityGenerator = objectIdentityGenerator;
}
public final void setConversionService(ConversionService conversionService) { public final void setConversionService(ConversionService conversionService) {
this.aclClassIdUtils = new AclClassIdUtils(conversionService); this.aclClassIdUtils = new AclClassIdUtils(conversionService);
} }
@ -569,7 +580,7 @@ public class BasicLookupStrategy implements LookupStrategy {
// target id type, e.g. UUID. // target id type, e.g. UUID.
Serializable identifier = (Serializable) rs.getObject("object_id_identity"); Serializable identifier = (Serializable) rs.getObject("object_id_identity");
identifier = BasicLookupStrategy.this.aclClassIdUtils.identifierFrom(identifier, rs); identifier = BasicLookupStrategy.this.aclClassIdUtils.identifierFrom(identifier, rs);
ObjectIdentity objectIdentity = new ObjectIdentityImpl(rs.getString("class"), identifier); ObjectIdentity objectIdentity = objectIdentityGenerator.createObjectIdentity(identifier,rs.getString("class"));
Acl parentAcl = null; Acl parentAcl = null;
long parentAclId = rs.getLong("parent_object"); long parentAclId = rs.getLong("parent_object");

View File

@ -31,11 +31,12 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.acls.domain.ObjectIdentityImpl; import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
import org.springframework.security.acls.model.Acl; import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.AclService; import org.springframework.security.acls.model.AclService;
import org.springframework.security.acls.model.NotFoundException; import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.ObjectIdentity; import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.ObjectIdentityGenerator;
import org.springframework.security.acls.model.Sid; import org.springframework.security.acls.model.Sid;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -80,6 +81,7 @@ public class JdbcAclService implements AclService {
private String findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL; private String findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL;
private AclClassIdUtils aclClassIdUtils; private AclClassIdUtils aclClassIdUtils;
private ObjectIdentityGenerator objectIdentityGenerator;
public JdbcAclService(DataSource dataSource, LookupStrategy lookupStrategy) { public JdbcAclService(DataSource dataSource, LookupStrategy lookupStrategy) {
this(new JdbcTemplate(dataSource), lookupStrategy); this(new JdbcTemplate(dataSource), lookupStrategy);
@ -90,12 +92,13 @@ public class JdbcAclService implements AclService {
Assert.notNull(lookupStrategy, "LookupStrategy required"); Assert.notNull(lookupStrategy, "LookupStrategy required");
this.jdbcOperations = jdbcOperations; this.jdbcOperations = jdbcOperations;
this.lookupStrategy = lookupStrategy; this.lookupStrategy = lookupStrategy;
this.objectIdentityGenerator = new ObjectIdentityRetrievalStrategyImpl();
this.aclClassIdUtils = new AclClassIdUtils(); this.aclClassIdUtils = new AclClassIdUtils();
} }
@Override @Override
public List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) { public List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) {
Object[] args = { parentIdentity.getIdentifier().toString(), parentIdentity.getType() }; Object[] args = {parentIdentity.getIdentifier().toString(), parentIdentity.getType()};
List<ObjectIdentity> objects = this.jdbcOperations.query(this.findChildrenSql, args, List<ObjectIdentity> objects = this.jdbcOperations.query(this.findChildrenSql, args,
(rs, rowNum) -> mapObjectIdentityRow(rs)); (rs, rowNum) -> mapObjectIdentityRow(rs));
return (!objects.isEmpty()) ? objects : null; return (!objects.isEmpty()) ? objects : null;
@ -105,7 +108,7 @@ public class JdbcAclService implements AclService {
String javaType = rs.getString("class"); String javaType = rs.getString("class");
Serializable identifier = (Serializable) rs.getObject("obj_id"); Serializable identifier = (Serializable) rs.getObject("obj_id");
identifier = this.aclClassIdUtils.identifierFrom(identifier, rs); identifier = this.aclClassIdUtils.identifierFrom(identifier, rs);
return new ObjectIdentityImpl(javaType, identifier); return objectIdentityGenerator.createObjectIdentity(identifier, javaType);
} }
@Override @Override
@ -142,6 +145,7 @@ public class JdbcAclService implements AclService {
/** /**
* Allows customization of the SQL query used to find child object identities. * Allows customization of the SQL query used to find child object identities.
*
* @param findChildrenSql * @param findChildrenSql
*/ */
public void setFindChildrenQuery(String findChildrenSql) { public void setFindChildrenQuery(String findChildrenSql) {
@ -154,8 +158,7 @@ public class JdbcAclService implements AclService {
// Change the default children select if it hasn't been overridden // Change the default children select if it hasn't been overridden
if (this.findChildrenSql.equals(DEFAULT_SELECT_ACL_WITH_PARENT_SQL)) { if (this.findChildrenSql.equals(DEFAULT_SELECT_ACL_WITH_PARENT_SQL)) {
this.findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL_WITH_CLASS_ID_TYPE; this.findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL_WITH_CLASS_ID_TYPE;
} } else {
else {
log.debug("Find children statement has already been overridden, so not overridding the default"); log.debug("Find children statement has already been overridden, so not overridding the default");
} }
} }
@ -165,6 +168,11 @@ public class JdbcAclService implements AclService {
this.aclClassIdUtils = new AclClassIdUtils(conversionService); this.aclClassIdUtils = new AclClassIdUtils(conversionService);
} }
public void setObjectIdentityGenerator(ObjectIdentityGenerator objectIdentityGenerator) {
Assert.notNull(objectIdentityGenerator,"The provided strategy has to be not null!");
this.objectIdentityGenerator = objectIdentityGenerator;
}
protected boolean isAclClassIdSupported() { protected boolean isAclClassIdSupported() {
return this.aclClassIdSupported; return this.aclClassIdSupported;
} }