Skip to content

Commit 86193b9

Browse files
Jonas DittrichSteve Riesenberg
authored andcommitted
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 spring-projectsgh-10079
1 parent 04161b9 commit 86193b9

File tree

2 files changed

+142
-123
lines changed

2 files changed

+142
-123
lines changed

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,14 @@
3535
import org.springframework.core.convert.ConversionService;
3636
import org.springframework.jdbc.core.JdbcTemplate;
3737
import org.springframework.jdbc.core.ResultSetExtractor;
38+
import org.springframework.security.acls.domain.*;
3839
import org.springframework.security.acls.domain.AccessControlEntryImpl;
3940
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
4041
import org.springframework.security.acls.domain.AclImpl;
4142
import org.springframework.security.acls.domain.AuditLogger;
4243
import org.springframework.security.acls.domain.DefaultPermissionFactory;
4344
import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy;
4445
import org.springframework.security.acls.domain.GrantedAuthoritySid;
45-
import org.springframework.security.acls.domain.ObjectIdentityImpl;
4646
import org.springframework.security.acls.domain.PermissionFactory;
4747
import org.springframework.security.acls.domain.PrincipalSid;
4848
import org.springframework.security.acls.model.AccessControlEntry;
@@ -51,6 +51,7 @@
5151
import org.springframework.security.acls.model.MutableAcl;
5252
import org.springframework.security.acls.model.NotFoundException;
5353
import org.springframework.security.acls.model.ObjectIdentity;
54+
import org.springframework.security.acls.model.ObjectIdentityGenerator;
5455
import org.springframework.security.acls.model.Permission;
5556
import org.springframework.security.acls.model.PermissionGrantingStrategy;
5657
import org.springframework.security.acls.model.Sid;
@@ -109,6 +110,8 @@ public class BasicLookupStrategy implements LookupStrategy {
109110

110111
private final AclAuthorizationStrategy aclAuthorizationStrategy;
111112

113+
private ObjectIdentityGenerator objectIdentityGenerator;
114+
112115
private PermissionFactory permissionFactory = new DefaultPermissionFactory();
113116

114117
private final AclCache aclCache;
@@ -134,6 +137,7 @@ public class BasicLookupStrategy implements LookupStrategy {
134137

135138
private AclClassIdUtils aclClassIdUtils;
136139

140+
137141
/**
138142
* Constructor accepting mandatory arguments
139143
* @param dataSource to access the database
@@ -152,8 +156,9 @@ public BasicLookupStrategy(DataSource dataSource, AclCache aclCache,
152156
* @param aclAuthorizationStrategy authorization strategy (required)
153157
* @param grantingStrategy the PermissionGrantingStrategy
154158
*/
155-
public BasicLookupStrategy(DataSource dataSource, AclCache aclCache,
156-
AclAuthorizationStrategy aclAuthorizationStrategy, PermissionGrantingStrategy grantingStrategy) {
159+
public BasicLookupStrategy(DataSource dataSource, AclCache aclCache,
160+
AclAuthorizationStrategy aclAuthorizationStrategy, PermissionGrantingStrategy grantingStrategy) {
161+
157162
Assert.notNull(dataSource, "DataSource required");
158163
Assert.notNull(aclCache, "AclCache required");
159164
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
@@ -162,6 +167,7 @@ public BasicLookupStrategy(DataSource dataSource, AclCache aclCache,
162167
this.aclCache = aclCache;
163168
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
164169
this.grantingStrategy = grantingStrategy;
170+
this.objectIdentityGenerator = new ObjectIdentityRetrievalStrategyImpl();
165171
this.aclClassIdUtils = new AclClassIdUtils();
166172
this.fieldAces.setAccessible(true);
167173
this.fieldAcl.setAccessible(true);
@@ -488,6 +494,11 @@ public final void setAclClassIdSupported(boolean aclClassIdSupported) {
488494
}
489495
}
490496

497+
public void setObjectIdentityGenerator(ObjectIdentityGenerator objectIdentityGenerator) {
498+
Assert.notNull(objectIdentityGenerator,"The provided strategy has to be not null!");
499+
this.objectIdentityGenerator = objectIdentityGenerator;
500+
}
501+
491502
public final void setConversionService(ConversionService conversionService) {
492503
this.aclClassIdUtils = new AclClassIdUtils(conversionService);
493504
}
@@ -569,7 +580,7 @@ private void convertCurrentResultIntoObject(Map<Serializable, Acl> acls, ResultS
569580
// target id type, e.g. UUID.
570581
Serializable identifier = (Serializable) rs.getObject("object_id_identity");
571582
identifier = BasicLookupStrategy.this.aclClassIdUtils.identifierFrom(identifier, rs);
572-
ObjectIdentity objectIdentity = new ObjectIdentityImpl(rs.getString("class"), identifier);
583+
ObjectIdentity objectIdentity = objectIdentityGenerator.createObjectIdentity(identifier,rs.getString("class"));
573584

574585
Acl parentAcl = null;
575586
long parentAclId = rs.getLong("parent_object");

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

Lines changed: 127 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,12 @@
3131
import org.springframework.core.convert.ConversionService;
3232
import org.springframework.jdbc.core.JdbcOperations;
3333
import org.springframework.jdbc.core.JdbcTemplate;
34-
import org.springframework.security.acls.domain.ObjectIdentityImpl;
34+
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
3535
import org.springframework.security.acls.model.Acl;
3636
import org.springframework.security.acls.model.AclService;
3737
import org.springframework.security.acls.model.NotFoundException;
3838
import org.springframework.security.acls.model.ObjectIdentity;
39+
import org.springframework.security.acls.model.ObjectIdentityGenerator;
3940
import org.springframework.security.acls.model.Sid;
4041
import org.springframework.util.Assert;
4142

@@ -50,123 +51,130 @@
5051
*/
5152
public class JdbcAclService implements AclService {
5253

53-
protected static final Log log = LogFactory.getLog(JdbcAclService.class);
54-
55-
private static final String DEFAULT_SELECT_ACL_CLASS_COLUMNS = "class.class as class";
56-
57-
private static final String DEFAULT_SELECT_ACL_CLASS_COLUMNS_WITH_ID_TYPE = DEFAULT_SELECT_ACL_CLASS_COLUMNS
58-
+ ", class.class_id_type as class_id_type";
59-
60-
private static final String DEFAULT_SELECT_ACL_WITH_PARENT_SQL = "select obj.object_id_identity as obj_id, "
61-
+ DEFAULT_SELECT_ACL_CLASS_COLUMNS
62-
+ " from acl_object_identity obj, acl_object_identity parent, acl_class class "
63-
+ "where obj.parent_object = parent.id and obj.object_id_class = class.id "
64-
+ "and parent.object_id_identity = ? and parent.object_id_class = ("
65-
+ "select id FROM acl_class where acl_class.class = ?)";
66-
67-
private static final String DEFAULT_SELECT_ACL_WITH_PARENT_SQL_WITH_CLASS_ID_TYPE = "select obj.object_id_identity as obj_id, "
68-
+ DEFAULT_SELECT_ACL_CLASS_COLUMNS_WITH_ID_TYPE
69-
+ " from acl_object_identity obj, acl_object_identity parent, acl_class class "
70-
+ "where obj.parent_object = parent.id and obj.object_id_class = class.id "
71-
+ "and parent.object_id_identity = ? and parent.object_id_class = ("
72-
+ "select id FROM acl_class where acl_class.class = ?)";
73-
74-
protected final JdbcOperations jdbcOperations;
75-
76-
private final LookupStrategy lookupStrategy;
77-
78-
private boolean aclClassIdSupported;
79-
80-
private String findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL;
81-
82-
private AclClassIdUtils aclClassIdUtils;
83-
84-
public JdbcAclService(DataSource dataSource, LookupStrategy lookupStrategy) {
85-
this(new JdbcTemplate(dataSource), lookupStrategy);
86-
}
87-
88-
public JdbcAclService(JdbcOperations jdbcOperations, LookupStrategy lookupStrategy) {
89-
Assert.notNull(jdbcOperations, "JdbcOperations required");
90-
Assert.notNull(lookupStrategy, "LookupStrategy required");
91-
this.jdbcOperations = jdbcOperations;
92-
this.lookupStrategy = lookupStrategy;
93-
this.aclClassIdUtils = new AclClassIdUtils();
94-
}
95-
96-
@Override
97-
public List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) {
98-
Object[] args = { parentIdentity.getIdentifier().toString(), parentIdentity.getType() };
99-
List<ObjectIdentity> objects = this.jdbcOperations.query(this.findChildrenSql, args,
100-
(rs, rowNum) -> mapObjectIdentityRow(rs));
101-
return (!objects.isEmpty()) ? objects : null;
102-
}
103-
104-
private ObjectIdentity mapObjectIdentityRow(ResultSet rs) throws SQLException {
105-
String javaType = rs.getString("class");
106-
Serializable identifier = (Serializable) rs.getObject("obj_id");
107-
identifier = this.aclClassIdUtils.identifierFrom(identifier, rs);
108-
return new ObjectIdentityImpl(javaType, identifier);
109-
}
110-
111-
@Override
112-
public Acl readAclById(ObjectIdentity object, List<Sid> sids) throws NotFoundException {
113-
Map<ObjectIdentity, Acl> map = readAclsById(Collections.singletonList(object), sids);
114-
Assert.isTrue(map.containsKey(object),
115-
() -> "There should have been an Acl entry for ObjectIdentity " + object);
116-
return map.get(object);
117-
}
118-
119-
@Override
120-
public Acl readAclById(ObjectIdentity object) throws NotFoundException {
121-
return readAclById(object, null);
122-
}
123-
124-
@Override
125-
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects) throws NotFoundException {
126-
return readAclsById(objects, null);
127-
}
128-
129-
@Override
130-
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids)
131-
throws NotFoundException {
132-
Map<ObjectIdentity, Acl> result = this.lookupStrategy.readAclsById(objects, sids);
133-
// Check every requested object identity was found (throw NotFoundException if
134-
// needed)
135-
for (ObjectIdentity oid : objects) {
136-
if (!result.containsKey(oid)) {
137-
throw new NotFoundException("Unable to find ACL information for object identity '" + oid + "'");
138-
}
139-
}
140-
return result;
141-
}
142-
143-
/**
144-
* Allows customization of the SQL query used to find child object identities.
145-
* @param findChildrenSql
146-
*/
147-
public void setFindChildrenQuery(String findChildrenSql) {
148-
this.findChildrenSql = findChildrenSql;
149-
}
150-
151-
public void setAclClassIdSupported(boolean aclClassIdSupported) {
152-
this.aclClassIdSupported = aclClassIdSupported;
153-
if (aclClassIdSupported) {
154-
// Change the default children select if it hasn't been overridden
155-
if (this.findChildrenSql.equals(DEFAULT_SELECT_ACL_WITH_PARENT_SQL)) {
156-
this.findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL_WITH_CLASS_ID_TYPE;
157-
}
158-
else {
159-
log.debug("Find children statement has already been overridden, so not overridding the default");
160-
}
161-
}
162-
}
163-
164-
public void setConversionService(ConversionService conversionService) {
165-
this.aclClassIdUtils = new AclClassIdUtils(conversionService);
166-
}
167-
168-
protected boolean isAclClassIdSupported() {
169-
return this.aclClassIdSupported;
170-
}
54+
protected static final Log log = LogFactory.getLog(JdbcAclService.class);
55+
56+
private static final String DEFAULT_SELECT_ACL_CLASS_COLUMNS = "class.class as class";
57+
58+
private static final String DEFAULT_SELECT_ACL_CLASS_COLUMNS_WITH_ID_TYPE = DEFAULT_SELECT_ACL_CLASS_COLUMNS
59+
+ ", class.class_id_type as class_id_type";
60+
61+
private static final String DEFAULT_SELECT_ACL_WITH_PARENT_SQL = "select obj.object_id_identity as obj_id, "
62+
+ DEFAULT_SELECT_ACL_CLASS_COLUMNS
63+
+ " from acl_object_identity obj, acl_object_identity parent, acl_class class "
64+
+ "where obj.parent_object = parent.id and obj.object_id_class = class.id "
65+
+ "and parent.object_id_identity = ? and parent.object_id_class = ("
66+
+ "select id FROM acl_class where acl_class.class = ?)";
67+
68+
private static final String DEFAULT_SELECT_ACL_WITH_PARENT_SQL_WITH_CLASS_ID_TYPE = "select obj.object_id_identity as obj_id, "
69+
+ DEFAULT_SELECT_ACL_CLASS_COLUMNS_WITH_ID_TYPE
70+
+ " from acl_object_identity obj, acl_object_identity parent, acl_class class "
71+
+ "where obj.parent_object = parent.id and obj.object_id_class = class.id "
72+
+ "and parent.object_id_identity = ? and parent.object_id_class = ("
73+
+ "select id FROM acl_class where acl_class.class = ?)";
74+
75+
protected final JdbcOperations jdbcOperations;
76+
77+
private final LookupStrategy lookupStrategy;
78+
79+
private boolean aclClassIdSupported;
80+
81+
private String findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL;
82+
83+
private AclClassIdUtils aclClassIdUtils;
84+
private ObjectIdentityGenerator objectIdentityGenerator;
85+
86+
public JdbcAclService(DataSource dataSource, LookupStrategy lookupStrategy) {
87+
this(new JdbcTemplate(dataSource), lookupStrategy);
88+
}
89+
90+
public JdbcAclService(JdbcOperations jdbcOperations, LookupStrategy lookupStrategy) {
91+
Assert.notNull(jdbcOperations, "JdbcOperations required");
92+
Assert.notNull(lookupStrategy, "LookupStrategy required");
93+
this.jdbcOperations = jdbcOperations;
94+
this.lookupStrategy = lookupStrategy;
95+
this.objectIdentityGenerator = new ObjectIdentityRetrievalStrategyImpl();
96+
this.aclClassIdUtils = new AclClassIdUtils();
97+
}
98+
99+
@Override
100+
public List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) {
101+
Object[] args = {parentIdentity.getIdentifier().toString(), parentIdentity.getType()};
102+
List<ObjectIdentity> objects = this.jdbcOperations.query(this.findChildrenSql, args,
103+
(rs, rowNum) -> mapObjectIdentityRow(rs));
104+
return (!objects.isEmpty()) ? objects : null;
105+
}
106+
107+
private ObjectIdentity mapObjectIdentityRow(ResultSet rs) throws SQLException {
108+
String javaType = rs.getString("class");
109+
Serializable identifier = (Serializable) rs.getObject("obj_id");
110+
identifier = this.aclClassIdUtils.identifierFrom(identifier, rs);
111+
return objectIdentityGenerator.createObjectIdentity(identifier, javaType);
112+
}
113+
114+
@Override
115+
public Acl readAclById(ObjectIdentity object, List<Sid> sids) throws NotFoundException {
116+
Map<ObjectIdentity, Acl> map = readAclsById(Collections.singletonList(object), sids);
117+
Assert.isTrue(map.containsKey(object),
118+
() -> "There should have been an Acl entry for ObjectIdentity " + object);
119+
return map.get(object);
120+
}
121+
122+
@Override
123+
public Acl readAclById(ObjectIdentity object) throws NotFoundException {
124+
return readAclById(object, null);
125+
}
126+
127+
@Override
128+
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects) throws NotFoundException {
129+
return readAclsById(objects, null);
130+
}
131+
132+
@Override
133+
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids)
134+
throws NotFoundException {
135+
Map<ObjectIdentity, Acl> result = this.lookupStrategy.readAclsById(objects, sids);
136+
// Check every requested object identity was found (throw NotFoundException if
137+
// needed)
138+
for (ObjectIdentity oid : objects) {
139+
if (!result.containsKey(oid)) {
140+
throw new NotFoundException("Unable to find ACL information for object identity '" + oid + "'");
141+
}
142+
}
143+
return result;
144+
}
145+
146+
/**
147+
* Allows customization of the SQL query used to find child object identities.
148+
*
149+
* @param findChildrenSql
150+
*/
151+
public void setFindChildrenQuery(String findChildrenSql) {
152+
this.findChildrenSql = findChildrenSql;
153+
}
154+
155+
public void setAclClassIdSupported(boolean aclClassIdSupported) {
156+
this.aclClassIdSupported = aclClassIdSupported;
157+
if (aclClassIdSupported) {
158+
// Change the default children select if it hasn't been overridden
159+
if (this.findChildrenSql.equals(DEFAULT_SELECT_ACL_WITH_PARENT_SQL)) {
160+
this.findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL_WITH_CLASS_ID_TYPE;
161+
} else {
162+
log.debug("Find children statement has already been overridden, so not overridding the default");
163+
}
164+
}
165+
}
166+
167+
public void setConversionService(ConversionService conversionService) {
168+
this.aclClassIdUtils = new AclClassIdUtils(conversionService);
169+
}
170+
171+
public void setObjectIdentityGenerator(ObjectIdentityGenerator objectIdentityGenerator) {
172+
Assert.notNull(objectIdentityGenerator,"The provided strategy has to be not null!");
173+
this.objectIdentityGenerator = objectIdentityGenerator;
174+
}
175+
176+
protected boolean isAclClassIdSupported() {
177+
return this.aclClassIdSupported;
178+
}
171179

172180
}

0 commit comments

Comments
 (0)