Wrapping Spring Security custom authentication provider with transaction - java

In my custom authentication provider, I was able to get the domain object through my Service API, but when I crawled from one domain object to another to get certain value to perform additional checks, Spring complains the Hibernate session doesn't exist:-
domain.getAnotherDomain().getProperty(); // epic FAIL
I have the following AOP transaction to wrap all my project APIs with transaction, and I'm pretty sure my custom authentication provider falls into the following pattern:-
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:advisor pointcut="execution(* my.project..*.*(..))" advice-ref="txAdvice" />
</aop:config>
I also have OpenSessionInView filter configured, but I don't think that applies to Spring Security anyway.
I guess I can create a specific Service API to perform all the required checks, but I'm curious why I'm not able to wrap my custom authentication provider with a proper transaction.
Any explanation? Thanks.

My workaround solution is to create a service API to perform the checks to avoid lazy loading errors in my custom authentication provider.

Spring complains the Hibernate session doesn't exist
Not quite sure I follow all your question, but I think the above statement represents your main problem, right? You didn't provide any stacktrace, but I imagine this is the infamous "no session or session closed", typical of the scenario you just described:
domain.getAnotherDomain().getProperty(); // epic FAIL
Maybe I'm missing something, but I think the typical answer would apply here too: map your relationship with fetch=FetchType.EAGER, so that you don't have to lazy load it when the session is already closed.

I ran into this same issue, and the cause was that I had Spring Security's filter declared before the OpenSessionInView filter in the web.xml file. Once I swapped them, the problem went away.
The reason is because Spring Security is being called before the Hibernate session is opened by the OpenSessionInView filter, and so there was no session opened.

You haven't posted any code that would let us do any meaningful suggestions.
But one problem with custom authentication provider might be that you maybe marked as #Transactional an abstract method which you are overriding and is being called from the abstract class instance.
For example retreiveUser from AbstractUserDetailsAuthenticationProvider. This method is called from within the instance (see method authenticate) and therefore cannot initialize the transaction through AOP proxy mechanism. For more details check #Transactional method calling another method without #Transactional anotation?
Spring declarative transaction model uses AOP proxy. so the AOP proxy is responsible for creation of the transactions. The AOP proxy will be active only if the methods with in the instance are called from out side the instance.

Related

What is interface-based proxying?

I was reading this regarding to where to place Transactional(interface vs implementation):
The Spring team's recommendation is that you only annotate concrete classes with the #Transactional annotation, as opposed to annotating interfaces. You certainly can place the #Transactional annotation on an interface (or an interface method), but this will only work as you would expect it to if you are using interface-based proxies. The fact that annotations are not inherited means that if you are using class-based proxies then the transaction settings will not be recognised by the class-based proxying infrastructure and the object will not be wrapped in a transactional proxy (which would be decidedly bad). So please do take the Spring team's advice and only annotate concrete classes (and the methods of concrete classes) with the #Transactional annotation.
So the question is what is interface-based proxy exactly and how can I see if it is used? Is it some configuration or it is the way how I instantiate/use instances?
If Spring cannot create a JDK proxy (or if you force Spring to create a CGLIB proxy by setting proxyTargetClass to true) then the code will not execute in a transactional context because (as the Spring docs state):
The fact that annotations are not inherited means that if you are using class-based proxies then the transaction settings will not be recognised by the class-based proxying infrastructure and the object will not be wrapped in a transactional proxy
So, I think your concerns are:
How can you be sure that Spring does not create a CGLIB proxy
You must be configuring AOP based transactional support. If you are doing this by using <tx:annotation-driven/> then the default value for proxy-target-class (false) will suffice though could be explicit about this by setting: <tx:annotation-driven proxy-target-class=“false"></tx:annotation-driven>. If you are configuring transactional support in some other way (using Java config, for example) then just ensure that the value of TransactionProxyFactoryBean.proxyTargetClass is false.
How can you be sure that your #Transactional annotations are respected
This is easy, just annotate the concrete class with the #Transactional annotation instead of annotating the interfaces. This avoids any issues with proxying.
In summary, Spring should use interface based proxying as long as TransactionProxyFactoryBean.proxyTargetClass is false however, if you annotate a concrete class rather than an implementation then the issue of proxying won't affect transactional support.

Springs #Transactional only works for proxy

I have a method that uses Springs #Transactional for database rollbacks. It works fine when i define the transaction manager like this:
<tx:annotation-driven transaction-manager="txManager" mode="proxy" />
but when i change to mode="aspectj" it does not rollback when the method throws an exception.
are there some differences in how the two modes should be used?
The "aspectj" mode will only work if load-time weaving or compile-time weaving are enabled. If not then the #Transactional annotation will not be applied to the annotated method.
The default proxy mode cannot be used to annotate private methods. This is where aspectj mode is useful. Certain frameworks (such as W2O for Web Services) require the class type itself to work. This can be impossible using proxy mode as the class is wrapped in a proxy class wrapper. This is another reason for using AspectJ.
If public methods are used and there are no special framework restrictions, then proxy mode is sufficient.
See Also: Transaction Management

Spring Security and AspectJ Neo4j Repository Autowiring

I have an application which we are trying to protect our service layer with an authorization check to ensure that the authorized user has the appropriate permission to perform an update. Our first simple rule is that the owner of the object can update the object, so the security check compares the logged in user against the owner of the object. Unfortunately, this is not working because the object is stored in a Neo4j graph database which uses AspectJ to generate the repository level objects. When I try to build the application having the service layer protected with #PreAuthorize I get an error saying that in the AutoWire chain it cannot AutoWire the Neo4j repository object... which makes sense to me because the object being AutoWired is really an interface that AspectJ builds into an object for our use.
I tried updating to Spring-Security 3.1.0, I have aspectj-autoproxy set, and I tried adding in type="aspectj" attribute into my global-method-security definition, but the compiler flags 'type' as an invalid property and I still get the AutoWiring problem.
After reviewing the model a bit more, I'm a little concerned that this approach is doomed to fail. The various controllers and other business logic units call the service layer directly which I believe will end up by-passing the spring-security proxy objects altogether.
Is there a way to use Neo4j repositories objects which are auto-generated from AspectJ as data repositories in the spring-security checks?
Is there a way to protect the service layer using spring-security? Or will direct calls to the service layer bypass the security layer altogether?
user1557993,
There is a section in the manual about this, have you had a look?
http://static.springsource.org/spring-data/data-graph/snapshot-site/reference/html/#tutorial_security
Regards,
Lasse

Spring with BlazeDS Global Method Security not working

I am using BlazeDS and Spring Security and have set up my application using a Spring Security filter chain and Dispatcher Servlet in my web.xml and in my application-context.xml I have set up the following...
<s:http
auto-config="true"
access-decision-manager-ref="accessDecisionManager"/>
<s:authentication-manager>
<s:authentication-provider
user-service-ref="userService"/>
</s:authentication-manager>
<f:message-broker>
<f:secured/>
</f:message-broker>
<s:global-method-security
access-decision-manager-ref="accessDecisionManager">
<s:protect-pointcut
expression="execution(* com.my.app.Server.*(..))"
access="ROLE_USER"/>
</s:global-method-security>
This generally works. The Spring message broker correctly allows me to access my java Server class and the 'secured' tag works and allows me to log into the channel set using my custom authentication manager (via userService). I can call remote methods on the Server class no problem.
However, I cannot get the global method security to work at all. I cannot get Spring to invoke my accessDecisionManager, or even to deny access to methods on the Server class, no matter which access role I use. Does anybody know how I can get this to work?
Incidentally, my Server class is not a Spring bean or anything like that, it is just a standard Java class as would be used in standard Flex remoting. Would this make a difference?
I'm using Spring Security 3 and Flex 4.5
Point cuts and aspects only works for Spring beans, if it is plain java object spring cannot intercept any method calls as it is not proxied. Please create a spring bean for your server class and it should be working fine.
Once you created the spring bean you can expose the bean through blaze DS using flex:remoting-destination

Is it possible in Springframework 2.5.6 to have scope="session" create the object on session create

I've got a project using Jetspeed portal and Springframework 2.5.6 where I need a Jetspeed level service to be unique for each user logged in. This would be best done using Spring AOP and scope="session". The problem is, that these are behind the scenes beans that need to be running as soon as the session in initiated. It appears that Spring's AOP chooses a lazy load design and does not create or init the actual implementation until a method on the bean is called.
Is there a way to force Spring AOP to create the new bean as soon as the session object is created?
An excellent question. The easiest option that springs to mind (if you'll pardon the expression) is to wire your session-scoped bean into the controller that is invoked when the first request of the session comes in (and to do this, the controller would have to either be a session-scoped bean itself, or your bean would need to use aop:scoped-proxy).
If different controllers could be invoked at the start of the session, then you could wire the bean into a session-scoped interceptor instead, and configure your url mapping to pass the requests through the interceptor, ensuring that the bean is initialized right at the start of the session.
I can't really think of a more elegant way to do this. You could potentially create a custom HttpSessionListener which calls getBean("my-session-scoped-bean") on the app context when sessionCreated() is called, but that's a bit clunky.

Categories

Resources