Now, let's add a drop of Security in our model.
Let's say you're working for a big paranoid pharma company where the user "lindenb" is not allowed to use the class
spring.Translator
with the standard genetic code. A naive approach is to extends spring.Translate
package spring;
public class TranslateSecurity extends Translate{
@Override
public String translate(CharSequence sequence)
{
if("lindenb".equals(System.getProperty("user.name")))
{
Translate geneticCode= Translate.class.cast(jp.getTarget());
if(geneticCode.getName().equals("Standard Code"))
{
throw new SecurityException(
"User lindenb is not allowed to use the genetic code \""+geneticCode.getName()+"\" !"
);
}
}
return super.translate(sequence);
}
}
But this strategy is not maintainable because you'll also have to copy this code in all the other classes implementing public class TranslateSecurity extends Translate{
@Override
public String translate(CharSequence sequence)
{
if("lindenb".equals(System.getProperty("user.name")))
{
Translate geneticCode= Translate.class.cast(jp.getTarget());
if(geneticCode.getName().equals("Standard Code"))
{
throw new SecurityException(
"User lindenb is not allowed to use the genetic code \""+geneticCode.getName()+"\" !"
);
}
}
return super.translate(sequence);
}
}
spring.Translate
such as spring.NoProlineTranslate
.Here comes The Aspect Oriented Programming (AOP). You can think of AOP as a dynamic decorator design pattern. The decorator pattern allows additional behavior to be added to an existing class by wrapping the original class and duplicating its interface and then delegating to the original.
Let's create an Aspect:
package spring;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class SecurityAspect
{
@Before("execution(* spring.Translator.*(..))")
public void checkSecurity(JoinPoint jp)
{
if("lindenb".equals(System.getProperty("user.name")))
{
Translate geneticCode= Translate.class.cast(jp.getTarget());
if(geneticCode.getName().equals("Standard Code"))
{
throw new SecurityException(
"User lindenb is not allowed to use the genetic code \""+geneticCode.getName()+"\" !"
);
}
}
}
}
This Aspect calls import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class SecurityAspect
{
@Before("execution(* spring.Translator.*(..))")
public void checkSecurity(JoinPoint jp)
{
if("lindenb".equals(System.getProperty("user.name")))
{
Translate geneticCode= Translate.class.cast(jp.getTarget());
if(geneticCode.getName().equals("Standard Code"))
{
throw new SecurityException(
"User lindenb is not allowed to use the genetic code \""+geneticCode.getName()+"\" !"
);
}
}
}
}
spring.SecurityAspect.checkSecurity()
each time before calling any method of spring.Translator
. This aspect is plugged our original code just by adding a few nodes in the original beans.xml
file.<beans>
(...)
<aop:aspectj-autoproxy proxy-target-class="true"/>
<bean id="aspect01" class="spring.SecurityAspect"/>
(...)
</beans>
(...)
<aop:aspectj-autoproxy proxy-target-class="true"/>
<bean id="aspect01" class="spring.SecurityAspect"/>
(...)
</beans>
Compile & Execute as user "lindenb"
mkdir -p build
javac -d build -cp ${SPRING}/dist/spring.jar:${SPRING}/lib/aspectj/aspectjrt.jar -sourcepath src src/spring/*.java
java -cp build:${SPRING}/dist/spring.jar:${SPRING}/lib/jakarta-commons/commons-logging.jar:${SPRING}/lib/aspectj/aspectjrt.jar:${SPRING}/lib/aspectj/aspectjweaver.jar:${SPRING}/lib/cglib/cglib-nodep-2.1_3.jar spring.SprintTest01
Jul 27, 2009 3:55:38 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@5e3974: display name [org.springframework.context.support.ClassPathXmlApplicationContext@5e3974]; startup date [Mon Jul 27 15:55:38 CEST 2009]; root of context hierarchy
Jul 27, 2009 3:55:38 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [beans.xml]
Jul 27, 2009 3:55:38 PM org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
INFO: Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@5e3974]: org.springframework.beans.factory.support.DefaultListableBeanFactory@c44b88
Jul 27, 2009 3:55:38 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@c44b88: defining beans [gencode1,gencode2,gencode3,listOfGenCodes,org.springframework.aop.config.internalAutoProxyCreator,aspect01]; root of factory hierarchy
java.lang.SecurityException: User lindenb is not allowed to use the genetic code "Standard Code" !
at spring.SecurityAspect.checkSecurity(SecurityAspect.java:18)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:627)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:609)
at org.springframework.aop.aspectj.AspectJMethodBeforeAdvice.before(AspectJMethodBeforeAdvice.java:39)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:49)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:635)
at spring.Translate$$EnhancerByCGLIB$$75c8a9e3.getName(<generated>)
at spring.SprintTest01.main(SprintTest01.java:20)
javac -d build -cp ${SPRING}/dist/spring.jar:${SPRING}/lib/aspectj/aspectjrt.jar -sourcepath src src/spring/*.java
java -cp build:${SPRING}/dist/spring.jar:${SPRING}/lib/jakarta-commons/commons-logging.jar:${SPRING}/lib/aspectj/aspectjrt.jar:${SPRING}/lib/aspectj/aspectjweaver.jar:${SPRING}/lib/cglib/cglib-nodep-2.1_3.jar spring.SprintTest01
Jul 27, 2009 3:55:38 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@5e3974: display name [org.springframework.context.support.ClassPathXmlApplicationContext@5e3974]; startup date [Mon Jul 27 15:55:38 CEST 2009]; root of context hierarchy
Jul 27, 2009 3:55:38 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [beans.xml]
Jul 27, 2009 3:55:38 PM org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
INFO: Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@5e3974]: org.springframework.beans.factory.support.DefaultListableBeanFactory@c44b88
Jul 27, 2009 3:55:38 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@c44b88: defining beans [gencode1,gencode2,gencode3,listOfGenCodes,org.springframework.aop.config.internalAutoProxyCreator,aspect01]; root of factory hierarchy
java.lang.SecurityException: User lindenb is not allowed to use the genetic code "Standard Code" !
at spring.SecurityAspect.checkSecurity(SecurityAspect.java:18)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:627)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:609)
at org.springframework.aop.aspectj.AspectJMethodBeforeAdvice.before(AspectJMethodBeforeAdvice.java:39)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:49)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:635)
at spring.Translate$$EnhancerByCGLIB$$75c8a9e3.getName(<generated>)
at spring.SprintTest01.main(SprintTest01.java:20)
This security layer was added in our model without modifying the original classes.
This security layer was added in our model without modifying the original classes.
This security layer was added in our model without modifying the original classes.
This security layer was added in our model without modifying the original classes
This security layer was added in our model without modifying the original classes
This security layer was added in our model without modifying the original classes.
This security layer was added in our model without modifying the original classes.
This security layer was added in our model without modifying the original classes
This security layer was added in our model without modifying the original classes
That's it.
Pierre
No comments:
Post a Comment