Grails Spring Security Expression - How to access Method parameter - grails

Using the Spring Security Plugin for Grails:
Version: 2.0-RC2
For my controllers I am using the #Secured annotation.
Is there a way to access the method parameter from the spring security expression.#paramName does not work for me.
#Secured(['ROLE_ADMIN',"hasRole('ROLE_USER') && #permissionService.updateAllowed( #myInstance )"])
def update(Bug myInstance) {
The problem: myInstance is null!
Software I am using:
Grails: 2.4.3
Intellij 14
JDK 8

I didn't notice that you were doing this in a controller - there's no support for method args in annotated controllers. The reason for this is that in traditional Spring Security, the annotation is applied to Spring Beans and the bean becomes proxied, and the proxy does the security checks before calling the method and only calls the real method if the checks pass. That works well with Spring MVC controllers because they're regular Java classes, and also in Grails services because there isn't much added to services by Grails - they're really just regular Groovy classes that are auto-registered as Spring Beans, and by default are made transactional.
But controllers are weird. There is actually one SpringMVC controller in any Grails app, and it's internally created and used by Grails. It interacts with the rest of SpringMVC, and delegates to the controller that best matches the url mappings rule for the current request to do its work, and it uses that to create the ModelAndView that Spring expects. Additionally, to support databinding, there's an AST transform that runs on your code during compilation which creates a no-arg method for each method with args, and that is what is called from the Grails internal request handling code. It does databinding and type conversions, and calls the "real" method to handle the request.
The support in Spring Security for working with method args depends on debug information being available in the compiled code, and usually this is not available because it's rarely needed - javac connects everything for us at compile time and getting the value of a method arg from outside of the method isn't often needed. Grails does keep that debug info - that's why this works in a service - but it looks like the AST isn't. It might be possible to get that working, but I have no idea if it is or what would be involved, and to be honest it would likely be a lot of work for a feature that wouldn't be used a lot.
But you can rework the check to pass the params to the service and let it lookup the Bug instance and then do its check. You can access the params from the service, so there's no need to pass anything as args:
import org.springframework.web.context.request.RequestContextHolder
...
def params = RequestContextHolder.requestAttributes.params

I've managed to get a workaround for the problem described in the comments to the accepted answer. Use #this in SpEL expression:
#Secured('#securityService.userCanEditOffer(#this)')
def edit(int id) {..}
Then create such methods in your service:
def userCanEditOffer(WebSecurityExpressionRoot webSecurityExpressionRoot) {
UrlMappingInfo urlMappingInfo = Holders.applicationContext.grailsUrlMappingsHolder.match(webSecurityExpressionRoot.request.forwardURI.substring(webSecurityExpressionRoot.request.contextPath.length()))
userCanEditOffer(Integer.valueOf(urlMappingInfo.params.id))
}
#Transactional(readOnly = true)
def userCanEditOffer(Integer id) { .. }
Inside ulrMappingInfo.params you'll have id, action and controller!

Related

Grails 2 app ported to Grails 3 - PooledConnection has already been closed, solved but not sure why

I was getting a "PooledConnection has already been closed" error when executing a controller with a method that performs a groovy sql query against the dataSource like this
class MyController {
def sessionFactory
def viewWeek (ThingCommand cmd) {
def summary = summaryService()
def db = new Sql(sessionFactory.currentSession.connection())
def sqlStrFind = "SELECT * FROM mytable"
def weekList = db.rows(sqlStrFind)
}
}
In Grails 2 I had seen runtime issues when ordering a Service.method call after inline use of a sessionFactory connection, but not the order above.
This led me to try refactoring the inline code into a new Service. This made the code work, but I noticed that #Transactional was annotating the new Service class, so I guessed that annotating class MyController with #Transactional might do the same for the Controller - and I was correct.
What I don't understand is why #Transactional makes a difference when I thought that Controllers and Services were transactional by default - or did something change in Grails 3?
BTW Burt Beckwith promoted the use of sessionFactory connection as this gave you a pooled connection
#virtualdogbert on slack grails-community provided this answer, which answers my question:
Some where in the Grails 3 line they removed the automatic transaction proxies by default, but you could bring them back with a config change
[see application.yml - grails: spring: transactioManagement: proxies: false ]
The #Transaction(Grails version) was added because it used an AST transform rather than a spring proxy, which in my mind makes it more reliable. Using the AST transform, was promoted over using the proxies for this reason.
The #Transactional AST transform also gives you greater control over how your transactions work.
Even though it's shown in examples I wouldn't use #Transactional in controllers, because it's considered bad practice.
Your​ business logic should be in services - controllers should just be use for routing, and rendering.

Is it possible to hack the spring-security-core plugin #Secured annotation to be able to reference request params given to a controller?

I am using Grails 2.3.3 and spring-security-core:2.0-RC4 plugin.
I am trying to protect a controller action by securing it depending on the result of a method call from a service that takes a parameter. This parameter should be something inside the request parameters.
I'd like to be able to do the following:
#Secured("#mySecurityService.myCustomCheck(params.id)")
def myAction(){
//do some things
}
I managed to be able to do the following:
#Secured("#mySecurityService.myCustomCheck()")
but now I have no idea how to access the request parameters that are sent to the controller.
Is it even architecturally possible to reference params variables inside the #Secured notation?
PS: I know you'll ask me to use spring-security-acl plugin. My problem is that it also adds a bunch of other things that I don't think I require.
In 2.0 you can use a closure as the annotation's check; there's a brief writeup and example in the docs: https://grails-plugins.github.io/grails-spring-security-core/v2/guide/newInV2.html
You'd express your example as this:
#Secured(closure={
ctx.mySecurityService.myCustomCheck(
request.getParameter('id'))
})
Return true to allow access.
Note that the ApplicationContext is available as the ctx variable, and the request as request; this is in addition to the other variables and methods that are available when using SpEL (see the Spring Security docs for details). params isn't available, but you can access values using request.getParameter

How do I access UrlMapping variables in grails from a filter?

I'm using Grails 2.1.5 and the Spring Security Core plugin.
I've overridden the WebSecurityExpressionRoot to add 2 signatures of a hasPermission method to the web expression paradigm.
This method delegates to classes by name in the applicationContext calling them with the request as an argument and an arbitrary string to provide further details if any are ever required.
In my delegate class I need to be able to access the parameters to assess whether or not the user may access the requested resource and this is fine but the request does not yet contain the variables defined from the UrlMappings.
I have tried acquiring the grailsUrlMappingsHolder from the applicationContext but when I call it's match method with a valid uri I get nothing.
I'm running out of time and may have to parse the request.getRequestURI() myself to try to infer the id if no request parameters are valid but this will not get urls mapped where the id is not last.
I really hate to re-invent the wheel here and I hate to miss out on using the UrlMappings to their fullest potential but the variables they define (in my circumstance) aren't available until I'm in the controller.
Take a look at what I do in AnnotationFilterInvocationDefinition - there's a bit of setup that you need to do: https://github.com/grails-plugins/grails-spring-security-core/blob/master/src/java/grails/plugin/springsecurity/web/access/intercept/AnnotationFilterInvocationDefinition.java

how to invoke unsecured proxy while using spring security annotations?

I am using spring security annotations in my project. There are scenarios when i want to invoke security-less version of the annotated object. Spring by default creates a security-enabled proxy of the annotated object and uses it for autowiring in the code, is there any way that i can achieve this using spring ?
An obvious way to do this would be to manually create proxy classes corresponding to each class for which i want this feature have those methods annotated and the implementation of these methods just delegate it to the actual object.
As an option in a case of JDK proxies you can get actual bean at runtime:
MyBean proxy;
if(AopUtils.isJdkDynamicProxy(proxy)) {
MyBean actualInstance = (MyBean) ((Advised)proxy).getTargetSource().getTarget()
}
actualInstance.doSomethingSecured(); // no advice related to this method will be called
// so your security annotation will be ignored (transactions, cache, and everething that requires AOP too...)
But from architectural point of view approach with manual proxies looks less error phrone (except if you absolutely sure that you do not need security and all another possible aspects too).
You can improve readability using generics:
MyBean actualInstance = extractProxyTarget(proxy, proxy.getClass());
actualInstance.doSomethingSecured();

Generic method interception in grails (specifically Controllers)

I'm trying to create a generic function in grails that will allow me to specify a class and function name, and intercept any function calls based on that criteria:
getSomeClass().metaClass.invokeMethod = { String methodName, args ->
MetaMethod someAction = getSomeClass().metaClass.getMetaMethod(methodName, args)
def result = someAction.invoke(delegate, args)
if (methodName==getSomeMethodName())
intercept(args, result)
return result
}
This works for POGO, and domain classes, but does not seem to work for controller classes. While I'm fully aware there are Controller interceptors and filters available in Grails, these don't really centralise what I'm trying to achieve, and was trying to create a simple generic function for some centralised behaviour
Any guidance on why this doesn't work on Controllers would be appreciated, thanks
Your approach will work for method calls that are made through the Groovy metaclass mechanism, but in Grails 2 this doesn't apply to controller actions - they're called using normal Java reflection (java.lang.reflect.Method.invoke), and therefore your custom invokeMethod is bypassed.
If you want an AOP mechanism that'll work for calls from Java as well as from Groovy you'll probably have to use something like AspectJ load-time weaving. Spring's proxy-based AOP may work but the Grails 2 controller system relies on the action methods having a particular #Action annotation (which is added at compile time by an AST transformation) and I don't know whether Spring AOP proxies preserve method annotations from the target class on the generated proxy methods.
Could it be that MyController.metaClass.invokeMethod is overwritten by the grails framework after your definition?
Have you tried to check the content of MyController.metaClass.invokeMethod through reflection?

Resources