Spring MVC PreAuthorize and private/final methods

Spring MVC has nice feature for adding security controls to Controller methods via @PreAuthorize annotation, but there’s an interesting problem that might occur when those methods are mistakenly marked as private or final.

Spring uses CGLib proxy to add calls to authorization logic declared in @PreAuthorize before calling actual controller method, but CGLib fails to process private or final methods, producing error like this in console:

2016-11-28 17:19:14.186 INFO 97079 --- [ main] o.s.aop.framework.CglibAopProxy : Unable to proxy method [public final java.util.Map com.package.controller.MyController.someMethod(javax.servlet.http.HttpServletResponse)] because it is final: All calls to this method via a proxy will NOT be routed to the target instance.

Well, so far so good – nothing special happens, all is more/less expected.

The problem though is that among most console output produced by Spring MVC yet another INFO log line rarely gets noticed. So what actually happens with those private/final methods of SpringMVC controller? Here weird stuff begins.

Say you’re writing a controller method that has a @PreAuthorize added to it, and accidentally copy-paste in a return type with final predicate before it, thus making your method final. You miss the log line in console because it’s just INFO among many other similar lines. And then… all autowired or otherwise injected fields of a controller are somehow null when calling only that particular method. But we know that in Spring MVC every controller is a singleton, so how is this even possible?

The issue appears to be that we’re actually calling methods on a CGLib proxy, that can’t pass them down to actual controller class instance. But proxy itself looks just like the controller class instance, except all fields that were supposed to be injected by Spring are null. A weird looking symptom which does not intuitively lead us to the cause of the problem.

But once one encounters this issue, I bet one remembers well next time what it is a symptom of.

P.S. I’ve encountered this issue with final method, but seems other people had same issue with private methods.

Advertisements
Posted in MVC

Liferay 5.2.3 services in Spring IoC+MVC powered portlets

A rather important subject today: how to make Spring IoC/MVC powered portlets work with Liferay services (the ones built from service.xml by calling ant with "build-service" target in your plugins SDK) in Liferay 5.2.3.

Situation:
– Spring IoC/MVC
We’re developing portlet with Spring IoC (and maybe Spring MVC) using Plugins SDK. We call create script -> get our sample portlet -> modify web.xml to have Spring WebApp context listener -> if we’re using Spring MVC, modify portlet.xml to use Spring Dispatcher Portlet.
Also in WEB-INF/lib we put spring.jar, and if we’re using Spring MVC also spring-webmvc.jar and spring-webmvc-portlet.jar (and maybe utility stuff like velocity jars etc).

– Liferay services
Now we want to have some persistent data and be able to manipulate it, and since Liferay provides nice facilitation for this in form of so-called "Liferay services" we’ll use it. So we create service.xml and run "ant build-service".

After that we add some logic that will use generated services, hit "ant deploy" and… get some exceptions about Spring context already being initialized for this webapp!

Continue reading