I am trying to access the Config of the grails application via the #Secured annotation of spring security with the aim to externalize the role name later.
Sadly, I wasn't able to get this working. Neither by trying to use deprecated ConfigurationHolder class nor getting reference to grailsApplication object.
import org.codehaus.groovy.grails.commons.ConfigurationHolder as CH
#Secured([CH.config.grails.app.user])
class MyController { ...}
Config.groovy:
...
grails.app.user = "ROLE_APPNAME_USER"
...
Does anyone have an advice how to solve this?
EDIT
Came across Burt's article which was informational.
You can't - annotation element values must be compile-time constants because they're resolved by the compiler and stored as part of the class bytecode.
You may have more luck using one of the other mechanisms to specify security constraints (static rules or Requestmap instances in the database) instead of annotations.
Related
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!
We're using the Grails spring security plugin:
http://grails.org/plugin/spring-security-core
I simply want to change the default access decision manager from the default AffirmativeBased to UnanimousBased. I do not see it documented anywhere in the plugin manual:
http://grails-plugins.github.io/grails-spring-security-core/docs/manual/
Does anyone know if it's possible to change this?
I added one additional voter, "myVoter" which is detected and working fine.
grails.plugins.springsecurity.voterNames = [
'myVoter', 'authenticatedVoter', 'roleVoter',
]
Based on Burt Beckwith's "Hacking the Grails Spring Security Plugin" [http://www.slideshare.net/gr8conf/hacking-the-grails-spring-security-plugins], it should be possible to simply provide a different implementation of the accessDecisionManager bean. Something like this:
accessDecisionManager(org.springframework.security.access.vote.UnanimousBased)
in resources.groovy
When I tried this, I had trouble with the constructor syntax in the bean definition. The access decision manager wants a list of voters in the constructor and I couldn't quote figure out how to get my voters defined in config.groovy as parameters to the constructor. I was about to derive my own decision manager (with parameterless constructor) from UnanimousBased when I stumbled upon the source code for AuthenticatedVetoableDecisionManager in the Grails Spring Security Plugin. This class splits the voters in half... anything deriving from AuthenticatedVoter will immediately fail if any are denied (e.g. AUTHENTICATED_FULLY family), but all other voters will pass if any are granted (e.g. RoleVoter). I wanted the AuthenticatedVoter functionality for my custom voter so I simply derived from AuthenticatedVoter (making sure to override all of the interface methods so I didn't accidentally get any base class functionality) and stuck with the default decision manager.
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();
I'm using the resources.groovy to declare a service e.g.
aService(com.foo.OrganizationService)
so that I can tie aService to my controllers instead of using organizationService which could change in the future.
I've noticed that the OrganizationService doesn't get treated special like other services "not" declared in the resources.groovy. For example it doesn't get injected with grailsApplication, and likely a hibernateSession etc and other things I've not hit yet....
Now, I know I can manually wire in stuff to my service but I'd rather not have to maintain that...
Is there a special way to declare a service in the resources.groovy so that gets treated like another service that grails loads up?
TIA
The short answer to your question is "no".
Under the covers, Grails services are driven by some intelligent code that is referencing a specific location and expecting certain properties.
Viewing the source code (especially around the ServicesGrailsPlugin.groovy) is a good way to see the "magic" in how these are wired together.
Is there a reason you wouldn't want to use a bonafide Grails service to solve your problem? If you are expecting things like a grailsApplication, it seems like that use is pretty specific to Grails and would be a good candidate for porting over to a "true" Grails service.
Good luck!
So I've come full circle on this. This is a timing problem. Where services haven't been grails initialized yet.
Basically when you use the resources.groovy to do service wiring you run the risk of using a Service that might initialize itself e.g. afterPropertiesSet method or static initializers that use grails services (log, hibernate session, ..) that haven't been injected yet.
So... What I've turned to instead is to create my own BeanBuilder in a BootStrap.groovy file.
BeanBuilder builder = new BeanBuilder(grailsApplication.parentContext)
def bb = builder.beans {
LoginListener(com.foo.LoginListener) {
springSecurityService = ref("springSecurityService")
userService = ref("userService")
}
}
bb.registerBeans(grailsApplication.mainContext)
Hi
I am new to Spring Security 3 and was trying out #PostFilter on a method declared in an Interface but the returned Collection is not getting filtered.
Here is the code:
public interface IProductService {
#PostFilter("(!filterObject.customersOnly) or (filterObject.customersOnly and hasRole('ROLE_USER'))")
Collection<Category> getCategories();
}
customerOnly is a boolean attribute in a domain object Category.
I've added the following element on xyz-security.xml:
<global-method-security pre-post-annotations="enabled" />
Could someone help me understand what am i missing?
Thanks
The typical causes for this are:
AspectJ and/or CGLIB JARs are not in your classpath.
You have the annotation on an interface OR on a class (review the Spring AOP docs to determine which is supported for which AOP implementation).
You have added the Spring Security configuration to a different ApplicationContext than where you have declared your secured beans (for example, you are trying to secure a bean in your *-servlet.xml file, when your Spring Security configuration is declared by the ContextLoaderListener).
You have removed or altered the declaration so that the annotated bean is not processed by the same ApplicationContext where Spring Security is configured.
If none of these suggestions applies, please enable DEBUG logging and watch application startup to see if the bean annotation is processed at all.
As an aside, I have had many readers report similar flavors of this problem - the source code for this sample does work, but in all cases it has been true that readers have subsequently changed one of the above 4 items, causing the sample code to "break" ;)