mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-06-26 05:42:31 +00:00
Make MethodDefinitionMap query interfaces defined by secure objects, to properly support MethodDefinitionSourceAdvisor.
This commit is contained in:
parent
8ec0d89fe4
commit
f123e9c333
@ -2,6 +2,8 @@ Changes in version 0.7 (2004-xx-xx)
|
|||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
* Added MethodDefinitionSourceAdvisor for performance and autoproxying
|
* Added MethodDefinitionSourceAdvisor for performance and autoproxying
|
||||||
|
* Added MethodDefinitionMap querying of interfaces defined by secure objects
|
||||||
|
* Documentation improvements
|
||||||
|
|
||||||
Changes in version 0.6.1 (2004-09-25)
|
Changes in version 0.6.1 (2004-09-25)
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
package net.sf.acegisecurity.intercept.method;
|
package net.sf.acegisecurity.intercept.method;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.ConfigAttribute;
|
||||||
import net.sf.acegisecurity.ConfigAttributeDefinition;
|
import net.sf.acegisecurity.ConfigAttributeDefinition;
|
||||||
|
|
||||||
import org.aopalliance.intercept.MethodInvocation;
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
@ -34,6 +35,32 @@ import java.util.Map;
|
|||||||
/**
|
/**
|
||||||
* Stores a {@link ConfigAttributeDefinition} for each method signature defined
|
* Stores a {@link ConfigAttributeDefinition} for each method signature defined
|
||||||
* in a bean context.
|
* in a bean context.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* For consistency with {@link MethodDefinitionAttributes} as well as support
|
||||||
|
* for {@link MethodDefinitionSourceAdvisor}, this implementation will return
|
||||||
|
* a <code>ConfigAttributeDefinition</code> containing all configuration
|
||||||
|
* attributes defined against:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>
|
||||||
|
* The method-specific attributes defined for the intercepted method of the
|
||||||
|
* intercepted class.
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* The method-specific attributes defined by any explicitly implemented
|
||||||
|
* interface if that interface contains a method signature matching that of
|
||||||
|
* the intercepted method.
|
||||||
|
* </li>
|
||||||
|
* </ul>
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* In general you should therefore define the <b>interface method</b>s of your
|
||||||
|
* secure objects, not the implementations. For example, define
|
||||||
|
* <code>com.company.Foo.findAll=ROLE_TEST</code> but not
|
||||||
|
* <code>com.company.FooImpl.findAll=ROLE_TEST</code>.
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
@ -53,10 +80,28 @@ public class MethodDefinitionMap extends AbstractMethodDefinitionSource {
|
|||||||
|
|
||||||
//~ Methods ================================================================
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the configuration attributes explicitly defined against this
|
||||||
|
* bean. This method will not return implicit configuration attributes
|
||||||
|
* that may be returned by {@link #lookupAttributes(MethodInvocation)} as
|
||||||
|
* it does not have access to a method invocation at this time.
|
||||||
|
*
|
||||||
|
* @return the attributes explicitly defined against this bean
|
||||||
|
*/
|
||||||
public Iterator getConfigAttributeDefinitions() {
|
public Iterator getConfigAttributeDefinitions() {
|
||||||
return methodMap.values().iterator();
|
return methodMap.values().iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the number of configuration attributes explicitly defined
|
||||||
|
* against this bean. This method will not return implicit configuration
|
||||||
|
* attributes that may be returned by {@link
|
||||||
|
* #lookupAttributes(MethodInvocation)} as it does not have access to a
|
||||||
|
* method invocation at this time.
|
||||||
|
*
|
||||||
|
* @return the number of configuration attributes explicitly defined
|
||||||
|
* against this bean
|
||||||
|
*/
|
||||||
public int getMethodMapSize() {
|
public int getMethodMapSize() {
|
||||||
return this.methodMap.size();
|
return this.methodMap.size();
|
||||||
}
|
}
|
||||||
@ -165,7 +210,38 @@ public class MethodDefinitionMap extends AbstractMethodDefinitionSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected ConfigAttributeDefinition lookupAttributes(MethodInvocation mi) {
|
protected ConfigAttributeDefinition lookupAttributes(MethodInvocation mi) {
|
||||||
return (ConfigAttributeDefinition) this.methodMap.get(mi.getMethod());
|
ConfigAttributeDefinition definition = new ConfigAttributeDefinition();
|
||||||
|
|
||||||
|
// Add attributes explictly defined for this method invocation
|
||||||
|
ConfigAttributeDefinition directlyAssigned = (ConfigAttributeDefinition) this.methodMap
|
||||||
|
.get(mi.getMethod());
|
||||||
|
merge(definition, directlyAssigned);
|
||||||
|
|
||||||
|
// Add attributes explicitly defined for this method invocation's interfaces
|
||||||
|
Class[] interfaces = mi.getMethod().getDeclaringClass().getInterfaces();
|
||||||
|
|
||||||
|
for (int i = 0; i < interfaces.length; i++) {
|
||||||
|
Class clazz = interfaces[i];
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Look for the method on the current interface
|
||||||
|
Method interfaceMethod = clazz.getDeclaredMethod(mi.getMethod()
|
||||||
|
.getName(),
|
||||||
|
mi.getMethod().getParameterTypes());
|
||||||
|
ConfigAttributeDefinition interfaceAssigned = (ConfigAttributeDefinition) this.methodMap
|
||||||
|
.get(interfaceMethod);
|
||||||
|
merge(definition, interfaceAssigned);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// skip this interface
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return null if empty, as per abstract superclass contract
|
||||||
|
if (definition.size() == 0) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return definition;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -184,4 +260,17 @@ public class MethodDefinitionMap extends AbstractMethodDefinitionSource {
|
|||||||
|| (mappedName.startsWith("*")
|
|| (mappedName.startsWith("*")
|
||||||
&& methodName.endsWith(mappedName.substring(1, mappedName.length())));
|
&& methodName.endsWith(mappedName.substring(1, mappedName.length())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void merge(ConfigAttributeDefinition definition,
|
||||||
|
ConfigAttributeDefinition toMerge) {
|
||||||
|
if (toMerge == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator attribs = toMerge.getConfigAttributes();
|
||||||
|
|
||||||
|
while (attribs.hasNext()) {
|
||||||
|
definition.addConfigAttribute((ConfigAttribute) attribs.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,6 +91,34 @@ public class MethodDefinitionSourceEditorTests extends TestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testConcreteClassInvocationsAlsoReturnDefinitionsAgainstInterface()
|
||||||
|
throws Exception {
|
||||||
|
MethodDefinitionSourceEditor editor = new MethodDefinitionSourceEditor();
|
||||||
|
editor.setAsText(
|
||||||
|
"net.sf.acegisecurity.ITargetObject.makeLower*=ROLE_FROM_INTERFACE\r\nnet.sf.acegisecurity.ITargetObject.makeUpper*=ROLE_FROM_INTERFACE\r\nnet.sf.acegisecurity.TargetObject.makeUpper*=ROLE_FROM_IMPLEMENTATION");
|
||||||
|
|
||||||
|
MethodDefinitionMap map = (MethodDefinitionMap) editor.getValue();
|
||||||
|
assertEquals(3, map.getMethodMapSize());
|
||||||
|
|
||||||
|
ConfigAttributeDefinition returnedMakeLower = map.getAttributes(new MockMethodInvocation(
|
||||||
|
TargetObject.class, "makeLowerCase",
|
||||||
|
new Class[] {String.class}));
|
||||||
|
ConfigAttributeDefinition expectedMakeLower = new ConfigAttributeDefinition();
|
||||||
|
expectedMakeLower.addConfigAttribute(new SecurityConfig(
|
||||||
|
"ROLE_FROM_INTERFACE"));
|
||||||
|
assertEquals(expectedMakeLower, returnedMakeLower);
|
||||||
|
|
||||||
|
ConfigAttributeDefinition returnedMakeUpper = map.getAttributes(new MockMethodInvocation(
|
||||||
|
TargetObject.class, "makeUpperCase",
|
||||||
|
new Class[] {String.class}));
|
||||||
|
ConfigAttributeDefinition expectedMakeUpper = new ConfigAttributeDefinition();
|
||||||
|
expectedMakeUpper.addConfigAttribute(new SecurityConfig(
|
||||||
|
"ROLE_FROM_IMPLEMENTATION"));
|
||||||
|
expectedMakeUpper.addConfigAttribute(new SecurityConfig(
|
||||||
|
"ROLE_FROM_INTERFACE"));
|
||||||
|
assertEquals(expectedMakeUpper, returnedMakeUpper);
|
||||||
|
}
|
||||||
|
|
||||||
public void testEmptyStringReturnsEmptyMap() {
|
public void testEmptyStringReturnsEmptyMap() {
|
||||||
MethodDefinitionSourceEditor editor = new MethodDefinitionSourceEditor();
|
MethodDefinitionSourceEditor editor = new MethodDefinitionSourceEditor();
|
||||||
editor.setAsText("");
|
editor.setAsText("");
|
||||||
|
29
upgrade-06-07.txt
Normal file
29
upgrade-06-07.txt
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
===============================================================================
|
||||||
|
ACEGI SECURITY SYSTEM FOR SPRING - UPGRADING FROM 0.6 TO 0.7
|
||||||
|
===============================================================================
|
||||||
|
|
||||||
|
The following should help most casual users of the project update their
|
||||||
|
applications:
|
||||||
|
|
||||||
|
- MethodDefinitionMap, which is usually used by MethodSecurityInterceptor
|
||||||
|
for its objectDefinitionSource property, has been changed. From 0.7, when
|
||||||
|
MethodDefinitionMap is queried for configuration attributes associated with
|
||||||
|
secure MethodInvocations, it will use any method matching in the method
|
||||||
|
invocation class (as it always has) plus any method matching any interface
|
||||||
|
the MethodInvocation class directly implements. So consider a PersonManager
|
||||||
|
interface, a PersonManagerImpl class that implements it, and a definition of
|
||||||
|
PersonManager.findAll=ROLE_FOO. In this example, any query for either
|
||||||
|
PersonManager.findAll OR PersonManagerImpl.findAll will return ROLE_FOO.
|
||||||
|
As we have always encouraged definition against the interface names (as per
|
||||||
|
this example), this change should not adversely impact users. This change
|
||||||
|
was necessary because of the new MethodDefinitionSourceAdvisor (see below).
|
||||||
|
Refer to the MethodDefinitionMap JavaDocs for further clarification.
|
||||||
|
|
||||||
|
- MethodDefinitionSourceAdvisor can now be used instead of defining proxies
|
||||||
|
for secure business objects. The advisor is fully compatible with both
|
||||||
|
MethodDefinitionMap and MethodDefinitionAttributes. Using an advisor allows
|
||||||
|
caching of which methods the MethodSecurityInterceptor should handle, thus
|
||||||
|
providing a performance benefit as MethodSecurityInterceptor is not called
|
||||||
|
for public (non-secure) objects. It also simplifies configuration.
|
||||||
|
|
||||||
|
$Id$
|
Loading…
x
Reference in New Issue
Block a user