mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-07-14 22:33:31 +00:00
SEC-936: NPE in AbstractFallbackMethodDefinitionSource
http://jira.springframework.org/browse/SEC-936. Changed to check if the value of MethodInvocation.getThis() is null to prevent NPE. MapBasedMethodDefinitionSource now ignores calls to findAttributes() with a null target class (all its entries require a class) and the fallback option in AbstractFallbackMethodDefinitionSource is used if the targetClass is null (i.e. Method.getDeclaringClass() will be used as the Class)
This commit is contained in:
parent
6a68a2531c
commit
3bf5e406b7
@ -39,15 +39,16 @@ import org.springframework.util.ObjectUtils;
|
|||||||
public abstract class AbstractFallbackMethodDefinitionSource implements MethodDefinitionSource {
|
public abstract class AbstractFallbackMethodDefinitionSource implements MethodDefinitionSource {
|
||||||
|
|
||||||
private static final Log logger = LogFactory.getLog(AbstractFallbackMethodDefinitionSource.class);
|
private static final Log logger = LogFactory.getLog(AbstractFallbackMethodDefinitionSource.class);
|
||||||
private final static Object NULL_CONFIG_ATTRIBUTE = new Object();
|
private final static Object NULL_CONFIG_ATTRIBUTE = new Object();
|
||||||
private final Map attributeCache = new HashMap();
|
private final Map attributeCache = new HashMap();
|
||||||
|
|
||||||
public ConfigAttributeDefinition getAttributes(Object object) throws IllegalArgumentException {
|
public ConfigAttributeDefinition getAttributes(Object object) throws IllegalArgumentException {
|
||||||
Assert.notNull(object, "Object cannot be null");
|
Assert.notNull(object, "Object cannot be null");
|
||||||
|
|
||||||
if (object instanceof MethodInvocation) {
|
if (object instanceof MethodInvocation) {
|
||||||
MethodInvocation mi = (MethodInvocation) object;
|
MethodInvocation mi = (MethodInvocation) object;
|
||||||
return getAttributes(mi.getMethod(), mi.getThis().getClass());
|
Object target = mi.getThis();
|
||||||
|
return getAttributes(mi.getMethod(), target == null ? null : target.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object instanceof JoinPoint) {
|
if (object instanceof JoinPoint) {
|
||||||
@ -71,70 +72,70 @@ public abstract class AbstractFallbackMethodDefinitionSource implements MethodDe
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ConfigAttributeDefinition getAttributes(Method method, Class targetClass) {
|
public ConfigAttributeDefinition getAttributes(Method method, Class targetClass) {
|
||||||
// First, see if we have a cached value.
|
// First, see if we have a cached value.
|
||||||
Object cacheKey = new DefaultCacheKey(method, targetClass);
|
Object cacheKey = new DefaultCacheKey(method, targetClass);
|
||||||
synchronized (this.attributeCache) {
|
synchronized (this.attributeCache) {
|
||||||
Object cached = this.attributeCache.get(cacheKey);
|
Object cached = this.attributeCache.get(cacheKey);
|
||||||
if (cached != null) {
|
if (cached != null) {
|
||||||
// Value will either be canonical value indicating there is no config attribute,
|
// Value will either be canonical value indicating there is no config attribute,
|
||||||
// or an actual config attribute.
|
// or an actual config attribute.
|
||||||
if (cached == NULL_CONFIG_ATTRIBUTE) {
|
if (cached == NULL_CONFIG_ATTRIBUTE) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return (ConfigAttributeDefinition) cached;
|
return (ConfigAttributeDefinition) cached;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// We need to work it out.
|
// We need to work it out.
|
||||||
ConfigAttributeDefinition cfgAtt = computeAttributes(method, targetClass);
|
ConfigAttributeDefinition cfgAtt = computeAttributes(method, targetClass);
|
||||||
// Put it in the cache.
|
// Put it in the cache.
|
||||||
if (cfgAtt == null) {
|
if (cfgAtt == null) {
|
||||||
this.attributeCache.put(cacheKey, NULL_CONFIG_ATTRIBUTE);
|
this.attributeCache.put(cacheKey, NULL_CONFIG_ATTRIBUTE);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Adding security method [" + cacheKey + "] with attribute [" + cfgAtt + "]");
|
logger.debug("Adding security method [" + cacheKey + "] with attribute [" + cfgAtt + "]");
|
||||||
}
|
}
|
||||||
this.attributeCache.put(cacheKey, cfgAtt);
|
this.attributeCache.put(cacheKey, cfgAtt);
|
||||||
}
|
}
|
||||||
return cfgAtt;
|
return cfgAtt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param method the method for the current invocation (never <code>null</code>)
|
* @param method the method for the current invocation (never <code>null</code>)
|
||||||
* @param targetClass the target class for this invocation (may be <code>null</code>)
|
* @param targetClass the target class for this invocation (may be <code>null</code>)
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private ConfigAttributeDefinition computeAttributes(Method method, Class targetClass) {
|
private ConfigAttributeDefinition computeAttributes(Method method, Class targetClass) {
|
||||||
// The method may be on an interface, but we need attributes from the target class.
|
// The method may be on an interface, but we need attributes from the target class.
|
||||||
// If the target class is null, the method will be unchanged.
|
// If the target class is null, the method will be unchanged.
|
||||||
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
|
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
|
||||||
// First try is the method in the target class.
|
// First try is the method in the target class.
|
||||||
ConfigAttributeDefinition attr = findAttributes(specificMethod, targetClass);
|
ConfigAttributeDefinition attr = findAttributes(specificMethod, targetClass);
|
||||||
if (attr != null) {
|
if (attr != null) {
|
||||||
return attr;
|
return attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Second try is the config attribute on the target class.
|
// Second try is the config attribute on the target class.
|
||||||
attr = findAttributes(specificMethod.getDeclaringClass());
|
attr = findAttributes(specificMethod.getDeclaringClass());
|
||||||
if (attr != null) {
|
if (attr != null) {
|
||||||
return attr;
|
return attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (specificMethod != method) {
|
if (specificMethod != method || targetClass == null) {
|
||||||
// Fallback is to look at the original method.
|
// Fallback is to look at the original method.
|
||||||
attr = findAttributes(method, method.getDeclaringClass());
|
attr = findAttributes(method, method.getDeclaringClass());
|
||||||
if (attr != null) {
|
if (attr != null) {
|
||||||
return attr;
|
return attr;
|
||||||
}
|
}
|
||||||
// Last fallback is the class of the original method.
|
// Last fallback is the class of the original method.
|
||||||
return findAttributes(method.getDeclaringClass());
|
return findAttributes(method.getDeclaringClass());
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,35 +168,35 @@ public abstract class AbstractFallbackMethodDefinitionSource implements MethodDe
|
|||||||
*/
|
*/
|
||||||
protected abstract ConfigAttributeDefinition findAttributes(Class clazz);
|
protected abstract ConfigAttributeDefinition findAttributes(Class clazz);
|
||||||
|
|
||||||
private static class DefaultCacheKey {
|
private static class DefaultCacheKey {
|
||||||
|
|
||||||
private final Method method;
|
private final Method method;
|
||||||
private final Class targetClass;
|
private final Class targetClass;
|
||||||
|
|
||||||
public DefaultCacheKey(Method method, Class targetClass) {
|
public DefaultCacheKey(Method method, Class targetClass) {
|
||||||
this.method = method;
|
this.method = method;
|
||||||
this.targetClass = targetClass;
|
this.targetClass = targetClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if (this == other) {
|
if (this == other) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!(other instanceof DefaultCacheKey)) {
|
if (!(other instanceof DefaultCacheKey)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
DefaultCacheKey otherKey = (DefaultCacheKey) other;
|
DefaultCacheKey otherKey = (DefaultCacheKey) other;
|
||||||
return (this.method.equals(otherKey.method) &&
|
return (this.method.equals(otherKey.method) &&
|
||||||
ObjectUtils.nullSafeEquals(this.targetClass, otherKey.targetClass));
|
ObjectUtils.nullSafeEquals(this.targetClass, otherKey.targetClass));
|
||||||
}
|
}
|
||||||
|
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return this.method.hashCode() * 21 + (this.targetClass != null ? this.targetClass.hashCode() : 0);
|
return this.method.hashCode() * 21 + (this.targetClass != null ? this.targetClass.hashCode() : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "CacheKey[" + (targetClass == null ? "-" : targetClass.getName()) + "; " + method + "]";
|
return "CacheKey[" + (targetClass == null ? "-" : targetClass.getName()) + "; " + method + "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -88,6 +88,10 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
|
|||||||
* Will walk the method inheritance tree to find the most specific declaration applicable.
|
* Will walk the method inheritance tree to find the most specific declaration applicable.
|
||||||
*/
|
*/
|
||||||
protected ConfigAttributeDefinition findAttributes(Method method, Class targetClass) {
|
protected ConfigAttributeDefinition findAttributes(Method method, Class targetClass) {
|
||||||
|
if (targetClass == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return findAttributesSpecifiedAgainst(method, targetClass);
|
return findAttributesSpecifiedAgainst(method, targetClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user