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
}
Related
I want a way to implement 2 factor authentication. When the user enters their username and password it moves them to another page where they are granted a temporary Role and then they are asked to enter a security token which will be sent to them via email. authtoken image
login image
I have been there and I discovered that its pretty easy to implement this mostly in custom code if you are in conventional old school web app. I think there is something in spring that allows you to do this, but depending on your application it might be just so much easier to do this by yourself and not even that difficult.
One way is to create grails filter that covers all routes that are affected by this. For example all except login page and the second page after that. This filter will check the temp role and if found, it will redirect to the second auth page. Otherwise it lets the request pass. Could be something like this:
twoFactorCheck(controller: '*', controllerExclude: 'privacyPolicy|login|logout|2factor', action: '*') {
before = {
if (process2factorAuthNeed()) {
return true;
}
redirect(controller: "2factor", action: "index");
return false;
}
}
Then another thing you need is an implementation of custom UserDetailsService where you can capture the first normal authentication and set the temp role for the user. This is covered here: https://grails-plugins.github.io/grails-spring-security-core/2.0.x/guide/userDetailsService.html if you are on grails 2.* but your spring security plugins version user guide will have this entry as well.
I have the following questions,
How do I prevent a user to access another using the SpringSecurityCore?
For example, prevent a student to access data from another student. At the time the two have the same role (role student)
and if I do student/show/1 I can see and edit the data. I want to stop it!
I can do with the ACL plugin, using the #PreAuthorize tag but it is deprecated and is giving error with the 2.5.1 version of Grails.
Following as it did in ACL: Only the ADMIN and the student logged in have access.
#PreAuthorize("(hasRole('ROLE_ADMIN')) or (isAuthenticated()) and (principal.id==#studentInstance.id)")
You can use the #Secured annotation at the method level instead. Then compare the principal ID like you're already doing. Finally, render a 403 status when the principal doesn't match.
render(status: 503)
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.
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.
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.