mirror of
				https://github.com/spring-projects/spring-security.git
				synced 2025-10-30 22:28:46 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			144 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			144 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| 
 | |
| [[secure-object-impls]]
 | |
| = Secure Object Implementations
 | |
| 
 | |
| [[aop-alliance]]
 | |
| == AOP Alliance (MethodInvocation) Security Interceptor
 | |
| Prior to Spring Security 2.0, securing ``MethodInvocation``s needed quite a lot of boiler plate configuration.
 | |
| Now the recommended approach for method security is to use xref:servlet/configuration/xml-namespace.adoc#ns-method-security[namespace configuration].
 | |
| This way the method security infrastructure beans are configured automatically for you so you don't really need to know about the implementation classes.
 | |
| We'll just provide a quick overview of the classes that are involved here.
 | |
| 
 | |
| Method security is enforced using a `MethodSecurityInterceptor`, which secures ``MethodInvocation``s.
 | |
| Depending on the configuration approach, an interceptor may be specific to a single bean or shared between multiple beans.
 | |
| The interceptor uses a `MethodSecurityMetadataSource` instance to obtain the configuration attributes that apply to a particular method invocation.
 | |
| `MapBasedMethodSecurityMetadataSource` is used to store configuration attributes keyed by method names (which can be wildcarded) and will be used internally when the attributes are defined in the application context using the `<intercept-methods>` or `<protect-point>` elements.
 | |
| Other implementations will be used to handle annotation-based configuration.
 | |
| 
 | |
| === Explicit MethodSecurityInterceptor Configuration
 | |
| You can of course configure a `MethodSecurityInterceptor` directly in your application context for use with one of Spring AOP's proxying mechanisms:
 | |
| 
 | |
| [source,xml]
 | |
| ----
 | |
| 
 | |
| <bean id="bankManagerSecurity" class=
 | |
| 	"org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor">
 | |
| <property name="authenticationManager" ref="authenticationManager"/>
 | |
| <property name="accessDecisionManager" ref="accessDecisionManager"/>
 | |
| <property name="afterInvocationManager" ref="afterInvocationManager"/>
 | |
| <property name="securityMetadataSource">
 | |
| 	<sec:method-security-metadata-source>
 | |
| 	<sec:protect method="com.mycompany.BankManager.delete*" access="ROLE_SUPERVISOR"/>
 | |
| 	<sec:protect method="com.mycompany.BankManager.getBalance" access="ROLE_TELLER,ROLE_SUPERVISOR"/>
 | |
| 	</sec:method-security-metadata-source>
 | |
| </property>
 | |
| </bean>
 | |
| ----
 | |
| 
 | |
| [[aspectj]]
 | |
| == AspectJ (JoinPoint) Security Interceptor
 | |
| The AspectJ security interceptor is very similar to the AOP Alliance security interceptor discussed in the previous section.
 | |
| Indeed we will only discuss the differences in this section.
 | |
| 
 | |
| The AspectJ interceptor is named `AspectJSecurityInterceptor`.
 | |
| Unlike the AOP Alliance security interceptor, which relies on the Spring application context to weave in the security interceptor via proxying, the `AspectJSecurityInterceptor` is weaved in via the AspectJ compiler.
 | |
| It would not be uncommon to use both types of security interceptors in the same application, with `AspectJSecurityInterceptor` being used for domain object instance security and the AOP Alliance `MethodSecurityInterceptor` being used for services layer security.
 | |
| 
 | |
| Let's first consider how the `AspectJSecurityInterceptor` is configured in the Spring application context:
 | |
| 
 | |
| 
 | |
| [source,xml]
 | |
| ----
 | |
| 
 | |
| <bean id="bankManagerSecurity" class=
 | |
| 	"org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor">
 | |
| <property name="authenticationManager" ref="authenticationManager"/>
 | |
| <property name="accessDecisionManager" ref="accessDecisionManager"/>
 | |
| <property name="afterInvocationManager" ref="afterInvocationManager"/>
 | |
| <property name="securityMetadataSource">
 | |
| 	<sec:method-security-metadata-source>
 | |
| 	<sec:protect method="com.mycompany.BankManager.delete*" access="ROLE_SUPERVISOR"/>
 | |
| 	<sec:protect method="com.mycompany.BankManager.getBalance" access="ROLE_TELLER,ROLE_SUPERVISOR"/>
 | |
| 	</sec:method-security-metadata-source>
 | |
| </property>
 | |
| </bean>
 | |
| ----
 | |
| 
 | |
| 
 | |
| As you can see, aside from the class name, the `AspectJSecurityInterceptor` is exactly the same as the AOP Alliance security interceptor.
 | |
| Indeed the two interceptors can share the same `securityMetadataSource`, as the `SecurityMetadataSource` works with ``java.lang.reflect.Method``s rather than an AOP library-specific class.
 | |
| Of course, your access decisions have access to the relevant AOP library-specific invocation (ie `MethodInvocation` or `JoinPoint`) and as such can consider a range of addition criteria when making access decisions (such as method arguments).
 | |
| 
 | |
| Next you'll need to define an AspectJ `aspect`.
 | |
| For example:
 | |
| 
 | |
| 
 | |
| [source,java]
 | |
| ----
 | |
| 
 | |
| package org.springframework.security.samples.aspectj;
 | |
| 
 | |
| import org.springframework.security.access.intercept.aspectj.AspectJSecurityInterceptor;
 | |
| import org.springframework.security.access.intercept.aspectj.AspectJCallback;
 | |
| import org.springframework.beans.factory.InitializingBean;
 | |
| 
 | |
| public aspect DomainObjectInstanceSecurityAspect implements InitializingBean {
 | |
| 
 | |
| 	private AspectJSecurityInterceptor securityInterceptor;
 | |
| 
 | |
| 	pointcut domainObjectInstanceExecution(): target(PersistableEntity)
 | |
| 		&& execution(public * *(..)) && !within(DomainObjectInstanceSecurityAspect);
 | |
| 
 | |
| 	Object around(): domainObjectInstanceExecution() {
 | |
| 		if (this.securityInterceptor == null) {
 | |
| 			return proceed();
 | |
| 		}
 | |
| 
 | |
| 		AspectJCallback callback = new AspectJCallback() {
 | |
| 			public Object proceedWithObject() {
 | |
| 				return proceed();
 | |
| 			}
 | |
| 		};
 | |
| 
 | |
| 		return this.securityInterceptor.invoke(thisJoinPoint, callback);
 | |
| 	}
 | |
| 
 | |
| 	public AspectJSecurityInterceptor getSecurityInterceptor() {
 | |
| 		return securityInterceptor;
 | |
| 	}
 | |
| 
 | |
| 	public void setSecurityInterceptor(AspectJSecurityInterceptor securityInterceptor) {
 | |
| 		this.securityInterceptor = securityInterceptor;
 | |
| 	}
 | |
| 
 | |
| 	public void afterPropertiesSet() throws Exception {
 | |
| 		if (this.securityInterceptor == null)
 | |
| 			throw new IllegalArgumentException("securityInterceptor required");
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| ----
 | |
| 
 | |
| 
 | |
| In the above example, the security interceptor will be applied to every instance of `PersistableEntity`, which is an abstract class not shown (you can use any other class or `pointcut` expression you like).
 | |
| For those curious, `AspectJCallback` is needed because the `proceed();` statement has special meaning only within an `around()` body.
 | |
| The `AspectJSecurityInterceptor` calls this anonymous `AspectJCallback` class when it wants the target object to continue.
 | |
| 
 | |
| You will need to configure Spring to load the aspect and wire it with the `AspectJSecurityInterceptor`.
 | |
| A bean declaration which achieves this is shown below:
 | |
| 
 | |
| 
 | |
| [source,xml]
 | |
| ----
 | |
| 
 | |
| <bean id="domainObjectInstanceSecurityAspect"
 | |
| 	class="security.samples.aspectj.DomainObjectInstanceSecurityAspect"
 | |
| 	factory-method="aspectOf">
 | |
| <property name="securityInterceptor" ref="bankManagerSecurity"/>
 | |
| </bean>
 | |
| ----
 | |
| 
 | |
| 
 | |
| That's it!
 | |
| Now you can create your beans from anywhere within your application, using whatever means you think fit (e.g. `new Person();`) and they will have the security interceptor applied.
 |