Disable #PreAuthorize when using the function in a specific context - spring-boot

I'm migrating an application with custom rest controllers to spring data rest. One problem I'm facing is that I had to add #PreAuthrozie annotations directly to my repositories instead of having them at a controller level. This is fine except some special cases.
The whole user repository is protected by a USER_ACCESS privilege. When the user authenticates, a new token is generated and the user has to be saved. Problem is, at this point there is no authentication in the Security Context so the request returns with 403
I have some code that on startup has all classes implementing PermissionProvider and saves new permissions to the database. Again, at this point there is no authentication in the Security Context so this fails since the repository is protected by PERMISSION_ACCESS privilege
I can manually create a tmp authentication that I set before the call then clear the context but this seems like a hack and can be problematic. Is there a way to disable #PreAuthorize in some context?

The only way you can work around this is to in cases 1. and 2. call another method in the repository that is not annotated with #PreAuthorize. This method would then call the methods annotated with #PreAuthorize. Since they are in the same class, #PreAuthorize has no effect. The reason being the way Spring AOP and CGLIB work. A proxy class is created that extends your class, providing the logic behind the #PreAuthorize behavior. When you call a method within the same class, such a call does not go through the proxy class, and as a consequence #PreAuthorize has no effect.

Related

Spring Boot Best approach for validation in facade

I use Spring Boot with Kotlin and my project is splitted on modules where I have application layer with REST controllers and facades, domain layer with services and business logic and infrastructures layer for communication with external services or DBs. I think (but I can be wrong) that the best place for basic validation like notNull, notEmpty, max and min, size etc. is facade because both REST controllers and another modules communicate with it, but the problem is that javax validation annotation like #Valid are working only on REST Controller layer (in classes with annotation #RestController) and when I try to create some tests for this facade then fields with wrong values return NullPointerException instead of MethodArgumentNotValidException. I tried to create WebMvcTest but also returns wrong exception. Is it some solution for it? I saw that I could call some validator inside the method but it looks like much more complex approach than annotation on method's argument.
You can inject the javax.validation.Validator into any Spring component. For example, into a facade component, and perform validation in the facade layer:
#Autowired
Validator validator;
Set<ConstraintViolation<UserRequestDTO>> violations = validator.validate(userRequest);
This way you can remove the #Valid annotation from controllers at all. And this approach puts validation results under the your control.

#Transactional doesnt work whereas DefaultTransactionDefinition works

I am upgrading my application from Spring3 to Spring 4. In my existing application we were using OpenSessionInViewInterceptor which creates the transaction along with new request.
Now I am using JPA also so even if I use OpenEntityManagerInViewInterceptor it doesn't associate transactions with it. So I had to put transaction manually in all my controller methods.
Due to legacy code, the controller classes have lots of business logic instead of distributing it properly to service layer.
Now if I put #Transctional annotation on controller method, then it doesn't work whereas if I use manual transaction through DefaultTransactionDefinition then it works properly.
Also, if I remove the business logic of controller methods to service layer, and put #Transactional annotation to service layer, then it also work fine. But these changes are tedious and my application is very big, so cant do it.
Please let me know why #Transactional doesn't work in my case if I put it in controller, how should I get it working.
I am not using AspectJ for transaction management.
Tried approaches:
Code at both places : code in dispatcher-servlet.xml along with appliacationContext.xml but still the controller transactions are failing.
Moved bean for urlMapping into applicationContext.xml but still it fails.

Lazy loading works, but shouldn't

The context of this question is within spring-boot, using spring-data-jpa and hibernate.
A colleague wrote an #Service and annotated the service method with #Transactional. The service method loads an entity, and subsequently hits a one-to-many lazily loaded collection (fetch = FetchType.LAZY). The service method is invoked by some custom delegator, which i will come back to. This works fine when invoked from a #RestController endpoint.
When i invoked the service from a camel route (again via the custom delegator) it barfed with a lazy initialization exception.
On digging, found that the service implements an interface, the custom delegator looks up the service (it is injected so has proper proxy) and calls a method
on the interface which is actually a java-8 default method. This default-method then locally calls the #Transactional method.
So there's the problem :- this is a LOCAL method call so the aspecting/proxy-ing of the #Transactional annotation is not done (we use aspectJAutoProxy) so the method is NOT invoked within a transaction, so the lazy-loading SHOULD fail. And to double-check, also tried it via an #Scheduled annotation: same behaviour. Barfs like it should.
My Question: So why does it work when called from the #RestController? This is driving me nuts!
There is no transactional annotation on the rest controller endpoint.
I added some debug code to the service using TransactionSynchronizationManager.isActualTransactionActive() and it shows that in no case is there a transaction, even when being called via the controller endpoint.
So why does the lazy loading work when being called from the controller?
I dumped all SQL and at no points are the lazy-collection already loaded, so they are not in any hibernate cache.
I remember reading once that lazy loading was a hint, not a command, but still... why does it work in that one case?
after being perplexed by this on many occasions, have stumbled across the answer:
sprint-boot is doing an open-entity-manager-in-view behind our backs via the OpenEntityManagerInView interceptor. Had no idea this was going on.
See this excellent answer from Vlad Mihalcea https://stackoverflow.com/a/48222934/208687
When your method annotate to transactional hibernate session close after return method , if object that return from method have lazy , lazy property not load and you get exception that session close. You can use fetch in query or using OSIV

When to use #RestController vs #RepositoryRestResource

I have been looking at various examples of how to use Spring with REST. Our end target is a Spring HATEOAS/HAL setup
I have seen two distinct methods for rendering REST within Spring
Via #RestController within a Controller
Via #RepositoryRestResource within a Repository
The thing I am struggling to find is why would you use one over the other. When trying to implement HAL which is best?
Our database backend is Neo4j.
Ok, so the short story is that you want to use the #RepositoryRestResource since this creates a HATEOAS service with Spring JPA.
As you can see here adding this annotation and linking it to your Pojo you have a fully functional HATEOAS service without having to implement the repository method or the REST service methods
If you add the #RestController then you have to implement each method that you want to expose on your own and also it does not export this to a HATEOAS format.
There is a third (and fourth) option that you have not outlined, which is to use either #BasePathAwareController or #RepositoryRestController, depending on whether you are performing entity-specific actions or not.
#RepositoryRestResource is used to set options on the public Repository interface - it will automatically create endpoints as appropriate based on the type of Repository that is being extended (i.e. CrudRepository/PagingAndSortingRepository/etc).
#BasePathAwareController and #RepositoryRestController are used when you want to manually create endpoints, but want to use the Spring Data REST configurations that you have set up.
If you use #RestController, you will create a parallel set of endpoints with different configuration options - i.e. a different message converter, different error handlers, etc - but they will happily coexist (and probably cause confusion).
Specific documentation can be found here.
Well, above answers are correct in their context still I am giving you practical example.
In many scenarios as a part of API we need to provide endpoints for searching an entity based on certain criteria. Now using JPA you don't have to even write queries, just make an interface and methods with specific nomenclature of Spring-JPA. To expose such APIs you will make Service layer which would simply call these repository methods and finally Controllers which will expose endpoints by calling Service layer.
What Spring did here, allow you to expose these endpoints from such interfaces (repositories) which are generally GET calls to search entity and in background generates necessary files to create final endpoints. So if you are using #RepositoryRestResource then there is no need to make Service/Controller layer.
On the other hand #RestController is a controller that specifically deals with json data and rest work as a controller. In short #Controller + #ResponseBody = #RestController.
Hope this helps.
See my working example and blog for the same:
http://sv-technical.blogspot.com/2015/11/spring-boot-and-repositoryrestresource.html
https://github.com/svermaji/Spring-boot-with-hibernate-no-controller
#RepositoryRestController override default generated Spring Data REST controllers from exposed repository.
To take advantage of Spring Data REST’s settings, message converters, exception handling, and more, use the #RepositoryRestController annotation instead of a standard Spring MVC #Controller or #RestController
E.g this controllers use spring.data.rest.basePath Spring Boot setting as base path for routing.
See Overriding Spring Data REST Response Handlers.
Be aware of adding #ResponseBody as it is missed in #RepositoryRestController
If you not exposed repository (marked as #RepositoryRestResource(exported = false)), use #BasePathAwareController annotation instead
Also be aware of bags
ControllerLinkBuilder does not take Spring Data REST's base path into account and #RequestMapping shouldn't be used on class/type level
and
Base path doesn't show up in HAL
Workaround to fix link: https://stackoverflow.com/a/51736503/548473
UPDATE: at last I prefer not to use #RepositoryRestController due to lot of workarounds.

Spring DefaultAdvisorAutoProxyCreator with #Transactional causing problems

I'm working on a Spring MVC project and trying to integrate Apache Shiro for the security. Everything was going just swimmingly until I realized Hibernate was prematurely closing the session/connection after a single query and causing a lazyinit exception. Not surprising, what I was doing should be done within a transaction so the session isn't closed.
Dilemmas…
I tried putting #Transactional on my controller method, but I get 404's then. Looking at my logs, I can see that when Spring is bootstrapping it ignores any mappings in my HomeController if that #Transactional annotation is on any method within the controller.
Without the #Transactional and it loads up just fine, and Ih can see the RequestMappingHandlerMapping bean sees all the #RequestMapping annotations in my controller.
With #Transactional but without DefaultAdvisorAutoProxyCreator, and it works except Shiro annotations are simply ignored.
tldr: Shiro requires DefaultAdvisorAutoProxyCreator, but if I create that bean, Spring blows up when using the #Transactional annotation.
I'm asking for help because I'm completely at a loss for how to proceed at this point.
This is typically because when you put #Transactional on a method, Spring creates a dynamic proxy for that bean - if the bean implements an interface then dynamic proxy is created based on that interface, otherwise CGLIB will be used for creating the proxy.
The problem in your case, I am guessing is because you probably have based your controller on some interface, or you are extending it based on a base class. This is ending up creating a proxy based on that interface, because of this when it comes time for mappings to be created for your request, Spring MVC is probably not finding your mappings from your bean.
The fix could be a few:
a. You can try and force proxies to be based on CGLIB for your transactions:
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
b. You can use pure Aspectj,either load time weaving or compile time weaving
c. You can move the #Transactional into a Service (which has an interface) and delegate the call from the controller to the service, this way avoiding #Transaction on the controller

Resources