Using Pre/Post Spring-Security Annotations with Grails - grails

I'm developing a Grails (Version 1.3.3) Web-Application using the Grails Spring-Security Plugin, Spring-Security-Core-1.0.1 (which, in turn, uses spring-security-3.0.2.RELEASE).
I would like to provide Spring-Security annotation-based access control on actions within a controller.
I have been able to successfully do basic authentication using the following annotations:
#Secured("hasAnyRole('ROLE_USER')")
def list = {
...
}
This works - providing access to the list action/view only to those with the ROLE_USER role.
However, the set of which roles are allowed to perform certain controller-actions may change over time and is a function of the system's overall state. That is, the set of roles allowed to perform a given action might be returned by a service or domain-object method.
One way I might be able to do something like this would be to use Spring-Security's "Expression Based Access Control" (#Pre and #Post annotations), something like the example at the Spring Security Documentation:
#PreAuthorize("hasPermission(#contact, 'admin')")
public void deletePermission(Contact contact, Sid recipient, Permission permission);
In this example for access control decisions, one can gain access to the objects sent to the method (eg contact) using the #contact syntax.
However, I can't get #PreAuthorize (or #RolesAllowed) annotations to work on a Grails controller-action. If I annotate the list action with #PreAuthorize (rather than #Secured, as above), I get the following error:
Annotation
#org.springframework.security.access.prepost.PreAuthorize
is not allowed on element FIELD
This isn't surprising -- the action is a Groovy closure (a field with executable code), rather than a method. However, I've also tried using the annotation on methods, called from the closure, like:
def list = {
testMethod()
....
}
#PreAuthorize("hasRole('ROLE_USER')")
public boolean testMethod(){
println "testMethod succeess"
return true;
}
While this doesn't throw any errors, it also doesn't appear to provide any access control. ("testMethod success" is printed whether or not the user has ROLE_USER).
So, I've tried a few different things (and read the documentation), but haven't been able to work out a nice way of using #PreAuthorize annotations with a Grails controller-action. Is this possible? Is there a better way in a Grails app to use Spring-Security-Annotations to provide access-control that is a function of the state of the system?

You need to use the ACL plugin to use those annotations, but they won't work on controller actions for the reasons you point out. #Secured works because I created a copy of the Spring Security annotation that allows it to be placed on fields as well as methods and classes, and I look for them and wire them up explicitly. You'll need to use annotated services that you call from your controllers.

Related

How to customize rolePrefix in Grails using Spring Security plugin?

I am working on a grails 2.3.8 project and trying to customize the Role Hierarchy. I am trying to change the default value of rolePrefix = 'ROLE_' in resources.groovy with rolePrefix = 'PERM_'. I understand that to make this work, I need to make the following changes in my Config.groovy into something like:
grails.plugins.springsecurity.userLookup.userDomainClassName = 'tpo.core.acl.AdminAccount'
grails.plugins.springsecurity.userLookup.authorityJoinClassName = 'tpo.core.acl.AdminAccountPermission'
grails.plugins.springsecurity.authority.className = 'tpo.core.acl.Permission'
And to establish hierarchy, I need to add this too in my Config.groovy
grails.plugins.springsecurity.roleHierarchy = '''
PERM_ACCOUNT_ALL > PERM_ACCOUNT_CREATE
PERM_ACCOUNT_ALL > PERM_ACCOUNT_READ
PERM_ACCOUNT_ALL > PERM_ACCOUNT_UPDATE
PERM_ACCOUNT_ALL > PERM_ACCOUNT_DELETE
'''
So in my Controller, it is something like,
#Secured(['PERM_ACCOUNT_ALL'])
def index() {
redirect(action: "list", params: params)
}
When I try to run my application, and access my controller's index() action, I was prompted to log in, this is expected because of the presence of #Secured(), but having successfully logged in, I was not yet able to access the index() action, and it displayed, Sorry, you're not authorized to view this page. The permission was assigned to the user that I used to logged in, but still, I was not able to access it.
Where am I missing?
There's a lot more to it than that :)
The reason that the plugin doesn't allow this change is to support the standard voters. Currently there are three styles of strings that can be used to specify access rules - role names, SPeL expressions, and the funky "IS_AUTHENTICATED" ones - IS_AUTHENTICATED_ANONYMOUSLY, IS_AUTHENTICATED_FULLY, and IS_AUTHENTICATED_REMEMBERED. Additionally there's a new way that was added for the 2.0 release - using a Closure and any arbitrary Groovy code inside of it, but that's unrelated to role names.
Each of the registered voters is queried to determine if they "support" (i.e. can vote on) each of these tokens. The logic is currently rather straightforward - the "IS_AUTHENTICATED_..." strings are handled by one voter, strings starting with "ROLE_" are handled by another, and everything else is assumed to be a SPeL expression.
To be honest, I think since roles would have to have been "registered" at startup anyway (to specify what access rules are allowed for each role in annotations, Config.groovy, etc.) that the role voter could do more than just check that the string starts with some prefix - it could look at its collection of known role names. So it probably wouldn't be too much work to add support for custom role prefixes for the 2.0 release, and I'll look into that. But for now, the plugin is as customizable as much as possible in every way except for this one exception.

Grails Filters vs Interceptor

I have been studying Grails for quite a while now. And scanned a little bit about Filters and Interceptors. Both have almost the same functionality of tracking the sessions or redirecting unauthorized users in a particular controller.
But I'm confused when and why should I use Filter than Interceptor and vice versa.
Given that the Inceptors have two controller methods beforeInterceptor and afterInterceptor and for the Filters a three common closures before, after and afterView.
My questions is what are the pros and cons of using Filter against Interceptor or vise versa. In this manner we, developers, can decide when, where, and why we should use either Filter or Interceptor in a particular Controller to do some tracking, redirect, etc.
Use one or both interceptors in a controller when the interception logic only applies to that controller.
Use a filter when the logic applies to multiple (or all) controllers, or when you need to do something after the view is rendered (there's no interceptor equivalent of afterView), or if you just want to keep everything centralized in one place instead of spread across separate controller files.
The Old Filters (From Grails 2) are deprecated in Grails 3. The replacement to the Filters are Interceptors.
The use of interceptors is for actions such as: authentication, loggin, etc.
The interceptors (as their name implies) are intercepting the incoming web requests and trigger a related actions. The actions are defined in the related Controller.
The Interceptors have some major benefits (over the Filters) such as support for static compilation, and enable flexible configurations.
These are the main 3 methods of the Interceptor:
- boolean before() { true }
- boolean after() { true }
- void afterView() { }
The Iterceptors are configured as Spring Beans (in the Spring application context) and are configured to be auto-wired by their names.

Using #Secured Annotation causes IS_FULLY_AUTHENTICATED problem in grails

I'm using Acegi/Spring Security in grails and when i use the annotations like #Secured(['ROLE_ADMIN']) it denies my login even though the user is part of ROLE_ADMIN.
In looking through the login is it seems that it's getting an IS_AUTHENTICATED_FULLY role also but I have never added that to a page so i'm not sure how to bypass that. I read somewhere to preauthorize the user, but i'm not sure how to do that with grails.
Have you enabled annotations based authentication in the security config?
E.g.
useRequestMapDomainClass = false
useControllerAnnotations = true
Also, triple check that the role is assigned (GORM might be silently failing your save).
You could printout the authorities assigned to the user just to make sure.
E.g.
user.authorities.each {
it.authority
}

How to get started with multi-tenant MVC application

I have searched for examples and found several but they are whole large projects. I am looking for some sample on how to get started building an MVC multi-tenant application. I think, the first part would be to decipher the url.
In ASP.Net this is how I did it. I got this from looking at DNN code. How would I do the same in MVC?
Global.asax
private void Application_BeginRequest(Object source, EventArgs e)
{
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
string domainName = string.Empty;
// domaName now contains 'example' if application.Request was www.example.com
domainName = GetDomainName(application.Request);
// Using domain, get the info for example from the database
object myPortal = // get from database
// Save in context for use on other pages
context.Items.Add("PortalSettings", myPortal);
}
Then in my basepage I get the value from the context.
I think an even more robust means would be to define a custom route. In that custom route is where you extract the domain and put it into the route values.
You then can have the base controller (as Josh described) which defines a Domain property or the like and stores that value there for convenience (or just extracts it on demand; either way).
By pulling it into the route values up front like that, you can make use of that information anywhere in the app along the request path, not just in the controller, so you get more re-use out of it that way. You can, for example, make use of it in a custom Authorize-like filter to handle the user's rights to that domain, and so on.
Get the domain name. You are on the right track with the DNN code. Just poke around the Request static variable in the debugger; there's all kinds of cool stuff there.
You'll probably need a user store. I use a custom database, but you could use the Microsoft membership provider and profile provider. Make the domain a property of the user, or a property of an organization, and the organization a property of the user.
Store the user's domain in the cookie, encrypted. Read the cookie at the beginning of the request, and make the user has access to that org/domain.
Make a BaseController that extends Controller, then have all your controllers inherit from it. In the BaseController, override OnActionExecuting. This is a much easier place to do your initial request rigging than the Global.asax.cs's Begin_request, because you can define protected members which will be available form every controller.

Grails with SpringSecurity, check if the current user can access controller / action

I'm currently developing a menu for my application that should be able to display only the controllers that the current user can access (requestmap defined in the database).
How can I check if the current user has access to a specific controller and action?
To check roles in view :
Spring security plugin provides ifAllGranted, ifAnyGranted, ifNoneGranted etc., tags to check roles
For example, to check Admin Role of logged in User :
<sec:ifLoggedIn>
<sec:ifAllGranted roles="ROLE_ADMIN">
Admin resource
</sec:ifAllGranted>
</sec:ifLoggedIn>
(tested in grails-2.2.2 and springSecurityCorePlugin-1.2.7.3)
org.grails.plugins.springsecurity.service.AuthenticateService authenticateService = new org.grails.plugins.springsecurity.service.AuthenticateService()
def isAdmin = authenticateService.ifAllGranted('ROLE_ADMIN')
if(isAdmin) {
println 'I am Admin'
}
This question is pretty old, but I thought I'd post at least an answer that seems to work with Grails 2.0. If you are using the spring security plugin, there's a tag lib included called grails.plugins.springsecurity.SecurityTagLib.
The tag-lib has a protected method, hasAccess() which can take the same params map that you give the g:link tag. So, if you extend SecurityTagLib, you can call hasAccess() and get the behavior you want. Why this isn't externalized into a service that can be injected is beyond me as the functionality seems to fulfill an obvious need.
We use this to wrap the g:link tag and only generate a link of the user has access to the target page:
def link = { attrs, body ->
if( hasAccess(attrs.clone(), "link") ) {
out << g.link(attrs, body)
}
else {
out << body()
}
}
When dealing with permissions in views and taglibs, you can use the AuthorizeTagLib that's provided by the plugin.
For example, if you don't want a menu item to appear in your list for unauthenticated users, you might use:
<g:isLoggedIn>
<li>Restricted Link</li>
</g:isLoggedIn>
If you have more specific roles defined and those roles are tied to your controller/action request mapping, you can use other tags, such as:
<g:ifAllGranted role="ROLE_ADMINISTRATOR">
<li>Administrator Link</li>
</g:ifAllGranted>
In my experience, there's not yet a good way to tie the request mapping to your markup - I think you're going to have to use some of the above tags to limit access to content within a particular GSP.
I think that Burt Beckwith has a future modification (and is currently providing a beta version) to the plugin that integrates some ACL stuff that might solve this problem better in the future, but for now, I think the best approach is a hybrid request map + GSP tags one.
Not sure of the situation when this question was originally asked, but now you can check to see if a user is in a specific role by using SpringSecurityUtils.ifAllGranted() which takes a single String which is a comma delimited list of roles. It will return true if the current user belongs to all of them.
if(SpringSecurityUtils.ifAllGranted('ROLE_ADMIN,ROLE_USER')) {
Obviously, you can simply pass one role to the function if that is all you need. SpringSecurityUtils also has methods like ifAnyGranted, ifNotGranted, etc, so it should work for whatever it is you are trying to accomplish.
SpringSecurityUtils is a static API, so you don't need to create a private member named springSecurityUtils or anything like that.
You have to configure the file config/SecurityConfig.groovy (if it does not exists, create it, this overrides the default Security Configuration)
Add this entry:
requestMapString = """\
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/=IS_AUTHENTICATED_REMEMBERED
/login/auth=IS_AUTHENTICATED_ANONYMOUSLY
/login/authajax=IS_AUTHENTICATED_ANONYMOUSLY
/login/authfail=IS_AUTHENTICATED_ANONYMOUSLY
/js/**=IS_AUTHENTICATED_ANONYMOUSLY
/css/**=IS_AUTHENTICATED_ANONYMOUSLY
/images/**=IS_AUTHENTICATED_ANONYMOUSLY
/plugins/**=IS_AUTHENTICATED_ANONYMOUSLY
/**=IS_AUTHENTICATED_REMEMBERED
"""
This is means that you have to log in to enter the site. But all the resources (css, js, images, etc) is accessed without authentification.
If you want specific role only enter specific controller:
For example, for UserController:
/user/**=ROLE_ADMIN
/role/**=ROLE_ADMIN
For more information: http://www.grails.org/AcegiSecurity+Plugin+-+Securing+URLs
Regards
As far as I can tell, there doesn't look like there's an easy way to do it.
You can inject an instance of the grails AuthenticatedVetoableDecisionManager which is a concrete class of spring's AbstractAccessDecisionManager by doing this:
def accessDecisionManager
This has a "decide" method on it that takes 3 parameters
decide(Authentication authentication, Object object, ConfigAttributeDefinition config)
This is probably the method that you'd need to call and pass in the right things to figure out if the user with the auth creds can access that "object" (which looks like it's normally a request/response). Some additional digging around might prove out something workable here.
Short term, it's probably easier to use the ifAnyGranted taglib as another poster mentions.
I'm not sure about in Groovy, but in Java (so I assume Groovy too...) you could do (minus NPE checks):
GrantedAuthority[] authorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities();
boolean isAdmin = false;
for(GrantedAuthority authority : authorities) {
String role = authority.getAuthority();
if(role != null && role.equals("ROLE_ADMIN")) {
isAdmin = true;
break;
}
}
As for knowing whether or not the action is supported, you'd have to call the RequestMap service to get the roles for the mapping and see if it contains the found user role.

Resources