mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-06-01 17:52:13 +00:00
SEC-1165: Relax the requirement that the ObjectIdentity "type" be a Java class. Modified ObjectIdentity, changing the javaType property to "type" which is now a plain String. Also removes the requirement that the class be present on the classpath when creating the ObjectIdentityImpl instance (e.g. in the case of a permissions administration app which doesn't actually use the domain classes itself).
This commit is contained in:
parent
0473cfbfc0
commit
39d76d5b5f
@ -34,37 +34,36 @@ import org.springframework.util.ClassUtils;
|
|||||||
public class ObjectIdentityImpl implements ObjectIdentity {
|
public class ObjectIdentityImpl implements ObjectIdentity {
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
private Class<?> javaType;
|
private final String type;
|
||||||
private Serializable identifier;
|
private Serializable identifier;
|
||||||
|
|
||||||
//~ Constructors ===================================================================================================
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
public ObjectIdentityImpl(String javaType, Serializable identifier) {
|
public ObjectIdentityImpl(String type, Serializable identifier) {
|
||||||
Assert.hasText(javaType, "Java Type required");
|
Assert.hasText(type, "Type required");
|
||||||
Assert.notNull(identifier, "identifier required");
|
Assert.notNull(identifier, "identifier required");
|
||||||
|
|
||||||
try {
|
|
||||||
this.javaType = ClassUtils.forName(javaType, ClassUtils.getDefaultClassLoader());
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
throw new IllegalStateException("Unable to load javaType: " + javaType, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.identifier = identifier;
|
this.identifier = identifier;
|
||||||
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor which uses the name of the supplied class as the <tt>type</tt> property.
|
||||||
|
*/
|
||||||
public ObjectIdentityImpl(Class<?> javaType, Serializable identifier) {
|
public ObjectIdentityImpl(Class<?> javaType, Serializable identifier) {
|
||||||
Assert.notNull(javaType, "Java Type required");
|
Assert.notNull(javaType, "Java Type required");
|
||||||
Assert.notNull(identifier, "identifier required");
|
Assert.notNull(identifier, "identifier required");
|
||||||
this.javaType = javaType;
|
this.type = javaType.getName();
|
||||||
this.identifier = identifier;
|
this.identifier = identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the <code>ObjectIdentityImpl</code> based on the passed
|
* Creates the <code>ObjectIdentityImpl</code> based on the passed
|
||||||
* object instance. The passed object must provide a <code>getId()</code>
|
* object instance. The passed object must provide a <code>getId()</code>
|
||||||
* method, otherwise an exception will be thrown. The object passed will
|
* method, otherwise an exception will be thrown.
|
||||||
* be considered the {@link #javaType}, so if more control is required,
|
* <p>
|
||||||
* an alternate constructor should be used instead.
|
* The class name of the object passed will be considered the {@link #type}, so if more control is required,
|
||||||
|
* a different constructor should be used.
|
||||||
*
|
*
|
||||||
* @param object the domain object instance to create an identity for.
|
* @param object the domain object instance to create an identity for.
|
||||||
*
|
*
|
||||||
@ -73,12 +72,13 @@ public class ObjectIdentityImpl implements ObjectIdentity {
|
|||||||
public ObjectIdentityImpl(Object object) throws IdentityUnavailableException {
|
public ObjectIdentityImpl(Object object) throws IdentityUnavailableException {
|
||||||
Assert.notNull(object, "object cannot be null");
|
Assert.notNull(object, "object cannot be null");
|
||||||
|
|
||||||
this.javaType = ClassUtils.getUserClass(object.getClass());
|
Class<?> typeClass = ClassUtils.getUserClass(object.getClass());
|
||||||
|
type = typeClass.getName();
|
||||||
|
|
||||||
Object result;
|
Object result;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Method method = this.javaType.getMethod("getId", new Class[] {});
|
Method method = typeClass.getMethod("getId", new Class[] {});
|
||||||
result = method.invoke(object, new Object[] {});
|
result = method.invoke(object, new Object[] {});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new IdentityUnavailableException("Could not extract identity from object " + object, e);
|
throw new IdentityUnavailableException("Could not extract identity from object " + object, e);
|
||||||
@ -123,15 +123,15 @@ public class ObjectIdentityImpl implements ObjectIdentity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return javaType.equals(other.javaType);
|
return type.equals(other.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Serializable getIdentifier() {
|
public Serializable getIdentifier() {
|
||||||
return identifier;
|
return identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class<?> getJavaType() {
|
public String getType() {
|
||||||
return javaType;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -141,7 +141,7 @@ public class ObjectIdentityImpl implements ObjectIdentity {
|
|||||||
*/
|
*/
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int code = 31;
|
int code = 31;
|
||||||
code ^= this.javaType.hashCode();
|
code ^= this.type.hashCode();
|
||||||
code ^= this.identifier.hashCode();
|
code ^= this.identifier.hashCode();
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
@ -150,7 +150,7 @@ public class ObjectIdentityImpl implements ObjectIdentity {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(this.getClass().getName()).append("[");
|
sb.append(this.getClass().getName()).append("[");
|
||||||
sb.append("Java Type: ").append(this.javaType.getName());
|
sb.append("Type: ").append(this.type);
|
||||||
sb.append("; Identifier: ").append(this.identifier).append("]");
|
sb.append("; Identifier: ").append(this.identifier).append("]");
|
||||||
|
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
|
@ -365,11 +365,10 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
|||||||
|
|
||||||
Set parentsToLookup = (Set) jdbcTemplate.query(sql,
|
Set parentsToLookup = (Set) jdbcTemplate.query(sql,
|
||||||
new PreparedStatementSetter() {
|
new PreparedStatementSetter() {
|
||||||
public void setValues(PreparedStatement ps)
|
public void setValues(PreparedStatement ps) throws SQLException {
|
||||||
throws SQLException {
|
|
||||||
for (int i = 0; i < objectIdentities.length; i++) {
|
for (int i = 0; i < objectIdentities.length; i++) {
|
||||||
// Determine prepared statement values for this iteration
|
// Determine prepared statement values for this iteration
|
||||||
String javaType = objectIdentities[i].getJavaType().getName();
|
String javaType = objectIdentities[i].getType();
|
||||||
|
|
||||||
// No need to check for nulls, as guaranteed non-null by ObjectIdentity.getIdentifier() interface contract
|
// No need to check for nulls, as guaranteed non-null by ObjectIdentity.getIdentifier() interface contract
|
||||||
String identifier = objectIdentities[i].getIdentifier().toString();
|
String identifier = objectIdentities[i].getIdentifier().toString();
|
||||||
|
@ -72,7 +72,7 @@ public class JdbcAclService implements AclService {
|
|||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
public List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) {
|
public List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) {
|
||||||
Object[] args = {parentIdentity.getIdentifier(), parentIdentity.getJavaType().getName()};
|
Object[] args = {parentIdentity.getIdentifier(), parentIdentity.getType()};
|
||||||
List<ObjectIdentity> objects = jdbcTemplate.query(selectAclObjectWithParent, args,
|
List<ObjectIdentity> objects = jdbcTemplate.query(selectAclObjectWithParent, 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 {
|
||||||
|
@ -148,7 +148,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
|||||||
*/
|
*/
|
||||||
protected void createObjectIdentity(ObjectIdentity object, Sid owner) {
|
protected void createObjectIdentity(ObjectIdentity object, Sid owner) {
|
||||||
Long sidId = createOrRetrieveSidPrimaryKey(owner, true);
|
Long sidId = createOrRetrieveSidPrimaryKey(owner, true);
|
||||||
Long classId = createOrRetrieveClassPrimaryKey(object.getJavaType(), true);
|
Long classId = createOrRetrieveClassPrimaryKey(object.getType(), true);
|
||||||
jdbcTemplate.update(insertObjectIdentity, classId, object.getIdentifier(), sidId, Boolean.TRUE);
|
jdbcTemplate.update(insertObjectIdentity, classId, object.getIdentifier(), sidId, Boolean.TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,15 +161,15 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
|||||||
*
|
*
|
||||||
* @return the primary key or null if not found
|
* @return the primary key or null if not found
|
||||||
*/
|
*/
|
||||||
protected Long createOrRetrieveClassPrimaryKey(Class<?> clazz, boolean allowCreate) {
|
protected Long createOrRetrieveClassPrimaryKey(String type, boolean allowCreate) {
|
||||||
List<Long> classIds = jdbcTemplate.queryForList(selectClassPrimaryKey, new Object[] {clazz.getName()}, Long.class);
|
List<Long> classIds = jdbcTemplate.queryForList(selectClassPrimaryKey, new Object[] {type}, Long.class);
|
||||||
|
|
||||||
if (!classIds.isEmpty()) {
|
if (!classIds.isEmpty()) {
|
||||||
return classIds.get(0);
|
return classIds.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allowCreate) {
|
if (allowCreate) {
|
||||||
jdbcTemplate.update(insertClass, new Object[] {clazz.getName()});
|
jdbcTemplate.update(insertClass, type);
|
||||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(),
|
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(),
|
||||||
"Transaction must be running");
|
"Transaction must be running");
|
||||||
return new Long(jdbcTemplate.queryForLong(classIdentityQuery));
|
return new Long(jdbcTemplate.queryForLong(classIdentityQuery));
|
||||||
@ -290,7 +290,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
|||||||
protected Long retrieveObjectIdentityPrimaryKey(ObjectIdentity oid) {
|
protected Long retrieveObjectIdentityPrimaryKey(ObjectIdentity oid) {
|
||||||
try {
|
try {
|
||||||
return new Long(jdbcTemplate.queryForLong(selectObjectIdentityPrimaryKey,
|
return new Long(jdbcTemplate.queryForLong(selectObjectIdentityPrimaryKey,
|
||||||
new Object[] {oid.getJavaType().getName(), oid.getIdentifier()}));
|
new Object[] {oid.getType(), oid.getIdentifier()}));
|
||||||
} catch (DataAccessException notFound) {
|
} catch (DataAccessException notFound) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -21,11 +21,11 @@ import java.io.Serializable;
|
|||||||
* Represents the identity of an individual domain object instance.
|
* Represents the identity of an individual domain object instance.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* As implementations of <tt>ObjectIdentity</tt> are used as the key to represent
|
* As implementations of <tt>ObjectIdentity</tt> are used as the key to represent
|
||||||
* domain objects in the ACL subsystem, it is essential that implementations provide
|
* domain objects in the ACL subsystem, it is essential that implementations provide
|
||||||
* methods so that object-equality rather than reference-equality can be relied upon
|
* methods so that object-equality rather than reference-equality can be relied upon
|
||||||
* reliably. In other words, the ACL subsystem can consider two
|
* reliably. In other words, the ACL subsystem can consider two
|
||||||
* <tt>ObjectIdentity</tt>s equal if <tt>identity1.equals(identity2)</tt>, rather than
|
* <tt>ObjectIdentity</tt>s equal if <tt>identity1.equals(identity2)</tt>, rather than
|
||||||
* reference-equality of <tt>identity1==identity2</tt>.
|
* reference-equality of <tt>identity1==identity2</tt>.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
@ -46,10 +46,10 @@ public interface ObjectIdentity extends Serializable {
|
|||||||
/**
|
/**
|
||||||
* Obtains the actual identifier. This identifier must not be reused to represent other domain objects with
|
* Obtains the actual identifier. This identifier must not be reused to represent other domain objects with
|
||||||
* the same <tt>javaType</tt>.
|
* the same <tt>javaType</tt>.
|
||||||
*
|
*
|
||||||
* <p>Because ACLs are largely immutable, it is strongly recommended to use
|
* <p>Because ACLs are largely immutable, it is strongly recommended to use
|
||||||
* a synthetic identifier (such as a database sequence number for the primary key). Do not use an identifier with
|
* a synthetic identifier (such as a database sequence number for the primary key). Do not use an identifier with
|
||||||
* business meaning, as that business meaning may change in the future such change will cascade to the ACL
|
* business meaning, as that business meaning may change in the future such change will cascade to the ACL
|
||||||
* subsystem data.</p>
|
* subsystem data.</p>
|
||||||
*
|
*
|
||||||
* @return the identifier (unique within this <tt>javaType</tt>; never <tt>null</tt>)
|
* @return the identifier (unique within this <tt>javaType</tt>; never <tt>null</tt>)
|
||||||
@ -57,12 +57,12 @@ public interface ObjectIdentity extends Serializable {
|
|||||||
Serializable getIdentifier();
|
Serializable getIdentifier();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains the Java type represented by the domain object. The Java type can be an interface or a class, but is
|
* Obtains the "type" metadata for the domain object. This will often be a Java type name (an interface or a class)
|
||||||
* most often the domain object implementation class.
|
* – traditionally it is the name of the domain object implementation class.
|
||||||
*
|
*
|
||||||
* @return the Java type of the domain object (never <tt>null</tt>)
|
* @return the "type" of the domain object (never <tt>null</tt>).
|
||||||
*/
|
*/
|
||||||
Class<?> getJavaType();
|
String getType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return a hash code representation of the <tt>ObjectIdentity</tt>
|
* @return a hash code representation of the <tt>ObjectIdentity</tt>
|
||||||
|
@ -64,7 +64,7 @@ public class ObjectIdentityImplTests {
|
|||||||
public void gettersReturnExpectedValues() throws Exception {
|
public void gettersReturnExpectedValues() throws Exception {
|
||||||
ObjectIdentity obj = new ObjectIdentityImpl(DOMAIN_CLASS, Long.valueOf(1));
|
ObjectIdentity obj = new ObjectIdentityImpl(DOMAIN_CLASS, Long.valueOf(1));
|
||||||
assertEquals(Long.valueOf(1), obj.getIdentifier());
|
assertEquals(Long.valueOf(1), obj.getIdentifier());
|
||||||
assertEquals(MockIdDomainObject.class, obj.getJavaType());
|
assertEquals(MockIdDomainObject.class.getName(), obj.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -106,9 +106,9 @@ public class ObjectIdentityImplTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected=IllegalStateException.class)
|
@Test(expected=IllegalArgumentException.class)
|
||||||
public void testConstructorInvalidClassParameter() throws Exception {
|
public void constructorRejectsInvalidTypeParameter() throws Exception {
|
||||||
new ObjectIdentityImpl("not.a.Class", Long.valueOf(1));
|
new ObjectIdentityImpl("", Long.valueOf(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Loading…
x
Reference in New Issue
Block a user