Using Spring ACL with #PreAuthorize annotations on Interfaces which use Generics does not seem to work.
Eg; I have an interface using generics;
public interface MyService<T> {
#PreAuthorize("hasPermission(#objectToProtect, 'WRITE')")
void doStuff(T objectToProtect, UserIdentity... user);
}
And an implementation;
public class MyServiceImpl implements MyService<MyObject> {
#Override
public synchronized void doStuff(MyObject objectToProtect, UserIdentity... userIdentity) {
// Do some stuff here... THis should be protected, the authenticated user should have write permissions.
}
}
I can see that PrePostAnnotationSecurityMetadataSource is picking up the annotations on the implementation, however it looks like its getting lost in the AOP passing further up and its never used when the acutal method is called. It works if I add the annotation to the concrete implementation (i.e. on the doStuff method in MyServiceImpl).
If I dont use generics in my interface and use something like Object it seems to work fine too. So is this a bug in Spring/Spring Security ACL or can we not use generics and expect them to be proxied.
My Spring config for the annotations looks like this;
<sec:global-method-security pre-post-annotations="enabled" proxy-target-class="true">
<sec:expression-handler ref="expressionHandler" />
</sec:global-method-security>
I'm using the latest GA version of Spring (3.2.3) and Spring Security (3.1.4)
There is open bug in spring Jira: https://jira.spring.io/browse/SPR-16060
Related
I was reading some articles about Spring AOP and encountered this:
AOP proxy: the object created by AOP to implement the aspect
contracts. In Spring, proxy objects can be JDK dynamic proxies or
CGLIB proxies. By default, the proxy objects will be JDK dynamic
proxies, and the object being proxied must implement an interface,
that will also be implemented by the proxy object. But a library like
CGLIB can be used to create proxies by subclassing too, so an
interface is not needed.
Could you look at the following structure and imagine that we want to advise bar() method.
public interface Foo {
void foo();
}
public class FooImpl implements Foo {
#Override
public void foo() {
System.out.println("");
}
public void bar() {
System.out.println("");
}
}
Does it mean that in this case CGLIB proxy will be used?
Since JDK dynamic proxy isn't able to implement any interface in order to override bar() method.
Spring will only use CGLIB if you tell it to. This is enabled (for annotation based configurations) by setting the proxyTargetClass element of #EnableAspectJAutoProxy to true.
#EnableAspectJAutoProxy(proxyTargetClass = true)
Consider this minimal example (assuming your FooImpl is annotated with #Component)
#Aspect
#Component
class FooAspect {
#Before("execution(public void bar())")
public void method() {
System.out.println("before");
}
}
#Configuration
#EnableAspectJAutoProxy
#ComponentScan
public class Example {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Example.class);
FooImpl f = ctx.getBean(FooImpl.class); // throw exception here
f.bar();
}
}
By default, proxyTargetClass is false. In this case, Spring will not use CGLIB. Because of the #Before advice in the #Aspect class, Spring will decide that it needs to proxy the FooImpl with a JDK proxy. Unfortunately, because of this proxying behavior, the bean actually stored in the context will be of a dynamic JDK Proxy type (also a subtype of the Foo interface) and therefore trying to get the bean with FooImpl.class will fail.
Even if you tried to retrieve it as a Foo, you wouldn't be able to invoke a bar() method since the proxy object isn't a FooImpl.
If you enable the proxyTargetClass, the code above works as intended, a CGLIB proxy is created, and the #Before advice is invoked.
See AOP Proxies in the Spring documentation:
Spring AOP defaults to using standard JDK dynamic proxies for AOP proxies. This enables any interface (or set of interfaces) to be proxied.
Spring AOP can also use CGLIB proxies. This is necessary to proxy classes rather than interfaces. By default, CGLIB is used if a business object does not implement an interface.
Spring AOP defaults to using standard JDK dynamic proxies for AOP proxies. This enables any interface (or set of interfaces) to be proxied.
Spring AOP can also use CGLIB proxies. This is necessary to proxy classes rather than interfaces. CGLIB is used by default if a business object does not implement an interface. As it is good practice to program to interfaces rather than classes; business classes normally will implement one or more business interfaces. It is possible to force the use of CGLIB, in those (hopefully rare) cases where you need to advise a method that is not declared on an interface, or where you need to pass a proxied object to a method as a concrete type.
It is important to grasp the fact that Spring AOP is proxy-based. See Understanding AOP proxies for a thorough examination of exactly what this implementation detail actually means.
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-introduction
Is it possible to use #DeclareMixin with Spring AOP? Or do they only support #DeclareParents?
I want to write an aspect that mixes in the java.beans.PropertyChangeSupport into a java bean:
public class PropertyChangeSupportWithInterface extends PropertyChangeSupport
implements IObservableBean {
public PropertyChangeSupportWithInterface(Object sourceBean) {
super(sourceBean);
}
}
(IObservableBean simply contains all public methods from the PropertyChangeSupport)
#Aspect
#Named
public class ObservableAspect{
#DeclareMixin("#ObservableBean *")
public static IObservableBean createDelegate(Object object) {
return new PropertyChangeSupportWithInterface(object);
}
}
It seems that this aspect is never used, which makes me think that the #DeclareMixin is not supported by the runtime weaving done by Spring AOP.
Is there any way to get this working with Spring AOP?
You can find a (not) running example here (Maven multi module project):
https://github.com/BernhardBln/SpringAOPObservableBean
See the (only) test case in the springaop-observable-bean-aspect submodule.
No, it's not supported by Spring AOP out the box. I see two options:
Create a DeclareMixinIntroductionInterceptor for Spring AOP.
Switch to Aspectj
I think that PropertyChange interface fits better in Aspectj because usually you will create a lot of proxies for prototype beans and them could be created easily out of the framework, by an ORM for example.
Edit
However I'm interested in this feature too and I already done some work for use it:
A DelegateFactoryIntroductionInterceptor to support creating delegates from the aspect instance.
A DeclareMixinAdvisor to join the inteceptor with the type pattern.
A DeclareMixinAspectJAdvisorFactory to support the DeclareMixin annotation.
To use it you only need to declare a bean of type DeclareMixinAutoProxyCreatorConfigurer
for configuring the AnnotationAwareAspectJAutoProxyCreator with the AdvisorFactory above.
I'm just testing, but seem that work fine.
Here is my Spring AOP configuration.
<bean id="myObject" class="com.madzone.learn.spring.aop.OriginalClass"></bean>
<bean id="aspect" class="com.madzone.learn.spring.aop.AspectClass"></bean>
<aop:config>
<aop:aspect ref="aspect">
<aop:declare-parents
types-matching="com.madzone.learn.spring.aop.OriginalClass+"
implement-interface="com.madzone.learn.spring.aop.IntroducedInterface"
default-impl="com.madzone.learn.spring.aop.IntroducedInterfaceImpl" />
</aop:aspect>
ApplicationContext context = new ClassPathXmlApplicationContext("myApp.xml");
Object myObject = context.getBean("myObject");
if (myObject instanceof OriginalClass) {
System.out.println("This is OriginalClass");
}
if(myObject instanceof IntroducedInterface) {
System.out.println("This is IntroducedInterface");
}
With this introduction I was able to call the methods in the IntroducedInterface. But, I was not able to access the OriginalClass' methods. In the code snippet above, I never got the 'This is OriginalClass' printed out.
From the definition of 'Introduction' I understood that the proxy that implements the new interface will extend from OriginalClass and make its' methods accessible too.
Am I missing something here? Can someone explain the reasons, if any?
PS:
The following is a picture from Spring in Action (3rd Edition) that depicts this.
From the definition of 'Introduction' I understood that the proxy that
implements the new interface will extend from OriginalClass and make
its' methods accessible too.
I'm not sure where you got that impression from. All of Spring AOP is built, by default, on JDK dynamic proxies, which only work for interfaces. It's impossible to proxy a concrete class. There is support in Spring for using CGLIB proxies in order to proxy classes instead, but its use is discouraged by the reference guide in favor of programming to interfaces to reduce coupling.
I am new to Spring AOP.
Using annotation based Spring configuration:
#Configuration
#EnableAspectJAutoProxy(proxyTargetClass=true)
#ComponentScan({"sk.lkrnac"})
Aspect:
#Aspect
#Component
public class TestAspect {
#Before("execution(* *(..))")
public void logJoinPoint(JoinPoint joinPoint){
....
}
}
Spring compoment:
package sk.lkrnac.testaop;
#Component
public class TestComponent{
#PostConstruct
public void init(){
testMethod();
}
public void testMethod() {
return;
}
}
How can I intercept all public methods that are called by Spring framework itself? (e.g. TestComponent.init() during creation of the TestComponent instance by Spring)
Currently I am able to intercept only TestComponent.testMethod() by invoking:
TestComponent testComponent = springContext.getBean(TestComponent.class);
testComponent.testMethod();
This is a common issue you run into with Spring AOP. Spring accomplishes AOP by proxying advised classes. In your case, your TestComponent instances will be wrapped in a run-time proxy class that provides the "hooks" for any aspect advice to be applied. This works very well when methods are called from outside the class, but as you have discovered it doesn't work on internal calls. The reason is that internal calls will not pass the proxy barrier, thus will not trigger the aspect.
There are primarily two ways around this. One is to fetch an instance of the (proxied) bean from the context. This is what you have already tried with success.
The other way is to use something called load-time weaving. When using this, AOP advices are added to a class ("weaved" into it) by a custom class-loader by injecting byte-code into the class definition. The Spring documentation has more on this.
There is a third way, which is called "compile time weaving". In this scenario, your AOP advices are statically weaved into each advised class when you compile it.
You can't intercept init() without any explicit means, please see the SpringSource Jira for details.
You can also try to call inner testMethod() from init() by self via proxy object like Don explained in https://stackoverflow.com/a/5786362/6786382.
I have a Spring MVC sample application it uses UserDaoImpl class to save a User type object to database. Following is the UserDaoImpl code.
public class UserDaoImpl implements UserDao<User> {
private EntityManagerFactory emf;
#PersistenceContext
private EntityManager em;
#Transactional
public void saveUser(User user){
em.persist(user);
}
}
and my UserDao interface looks like this.
public interface UserDao<User> {
public void saveUser(User user);
}
Weird thing is happening when when my UserDaoImpl class implements the UserDao interface. When trying to persist it gives the following error.
java.lang.ClassCastException: $Proxy71 cannot be cast to org.samith.UserDaoImpl
When I remove the "implements UserDao" part from the UserDaoImpl class user is persisted to database as expected.
Also I tried UserDao interface without User parameter(that is non generic version). Still above error occurs.
This may be a trivial question to answer but I am scratching my head finding a solution for about few hours.
What wrong am I doing ??
You're not providing the problem code, (or the full stack trace) but the rundown is this:
When you annotate a class as #Transactional, and Spring creates an instance for you, what you get is not that class, but a Java Dynamic Proxy that implements that classes' interfaces. http://download.oracle.com/javase/1.3/docs/guide/reflection/proxy.html
Because of this, you cannot cast that object to the original type (it's not that type anymore!) and must use it's interface(s) instead.
If there aren't interfaces to implement, it will give you a CGLib proxy of the class, which is basically just a runtime modified version of your class, and so is assignable to the class itself.
Search for where you're injecting, or casting to type UserDaoImpl, and change the reference to UserDao instead, and it will work properly.
I've read the performance difference between CGLib proxies and Dynamic Java Proxies is quite minimal, so you can also add the following to your spring config to force it to use CGLib proxies instead of Java Dynamic Proxies:
<aop:config proxy-target-class="true">
In general however, I'd recommend you not use CGLib Proxies, but instead access your class from its interface. Loose coupling will allow you to do runtime substitution, and limits your ability to accidentally introduce brittle class dependencies.
There are some problems that using Java Dynamic Proxies will introduce however, and what you're doing is close enough to what I was doing that you should be aware of this:
How to use Dynamic Proxies with JSF when the method signature contains Object ... args
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
worked for me too. the point was proxy-target-class="true" thanks to owner of the accepted answer. But then cglib dependency will be needed.