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.
Related
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.
Anybody who already have implemented something similar using Grails could tell me please which are the good pratices (if there are any) to create user profile URLs with the format "http://www.myservice.com/username", as in Facebook, Twitter, Linkedin?
I'm trying to implement it through the UrlMappings and appears to me I'll need to break with the code conventions, at least for the Controllers.
So, any suggestions are welcome, thanks.
UPDATE 1
When I mentioned my concern about breaking the code conventions, what I'm saying is that I want to show the user profile using this mapping, but I do have other objects in my application which I would like to access using the default mapping:
"/$controller/$action?/$id?"()
SOLUTION
Thanks to the great contributions I've received here, I've camed up with this solution, which solves my problem.
As was pointed out, to do this kind of mapping, I'll need to control more closely how my requests are handled. That means I'll need to tell to Grails which controllers I don't want to be mapped to the "username" rule.
Since that will be a very tedious task (because I have several controllers), I did this to automate it:
UrlMappings.groovy
static mappings = {
getGrailsApplication().controllerClasses.each{ controllerClass ->
"/${controllerClass.logicalPropertyName}/$action?/$id?"(controller: controllerClass.logicalPropertyName)
}
"/$username/$action?"(controller: "user", action: "profile")
}
...
}
And of course, I'll need to do something similar in my user registration process to avoid usernames to be equal to some controller name.
That's it, thank you all.
Assuming you have a UserController and you are going to map any domain.com/username to the show action of user controller, your url mapping could be something like this :
In my example, name will become a parameter in your params.
for further details refer to here
Hope this helps.
static mappings = {
"/$name"(controller: "user", action: "show")
...
}
Given your requirements, everything after http://yourdomain.com/ can be a username or one of your other controllers, which can have undesired effects depending on which url mapping is defined first (e.g. user controller vs nonuser controller). But most likely the nonuser controller list will be the smaller list, so you should place that first and filter against it, then treat all other url mappings as user mappings.
Here is an example:
static mapping = {
"/$controller/$action?/$id?" {
constraints {
controller inList: ['nonUserController1', 'nonUserController2',...]
}
}
//this should work for /username and /username/whateveraction
"/$username/$action?"(controller: 'user')
}
Some things to note here:
you need to place the non user controller url mapping first, since everything else after http://yourdomain.com/ may be a username - correct?
second you need to place a constraint to catch all the non user controllers, while ignore the user url mappings
also you need to prevent a user from signing up with a username that matches one of your non user controllers
Is it possible at all for me to use a wildcard in the access property of the <sec:authorize /> tag.
Currently I have
<sec:authorize access="hasRole('TICKET_VIEW') or hasRole('TICKET_EDIT')">
but I would like to be able to use
<sec:authorize access="hasRole('TICKET_*')">
Is this possible or does anyone know a work-around that would accomplish the same thing?
Thanks
It's possible in Spring EL starting from Spring 3.x. The expression you're looking for is hasAnyRole(..).
So it should look like this:
<sec:authorize access="hasAnyRole('TICKET_VIEW', 'TICKET_EDIT')">
...
</sec:authorize>
Here's a link for some more Spring EL expressions:
http://static.springsource.org/spring-security/site/docs/3.0.x/reference/el-access.html
I realize that this is an old question, but this answer might help future searchers.
1) Allow Single Role from a Fixed Set: This is the simple base case.
<security:authorize access="hasRole('ROLE_ADMIN_ABC')">
You are allowed to see these admin links.
</security:authorize>
2) Allow Any Role from a Fixed Set: For cases where you want to allow "any role that starts with ADMIN", you know all of the role names in advance, and you just have a few roles, jzelenkov's answer is perfectly correct. However, if you have too many roles to deal with, you will probably want to create a custom method call that can make the access decision, and insert it into the access attribute with SpEL. This solution is closer to the wildcard question that was originally asked.
<bean id="mySecurityBean" class="com.sample.MySecurityBean" />
<security:authorize access="#mySecurityBean.roleStartsWith(principal, 'ROLE_ADMIN_')">
You are allowed to see these admin links.
</security:authorize>
public class MySecurityBean {
/**
* Returns true if any role starts with some prefix.
*/
public boolean roleStartsWith(UserDetails user, String rolePrefix) {
for (GrantedAuthority auth : user.getAuthorities()) {
if (auth.getAuthority().startsWith(rolePrefix)
return (true);
}
return (false);
}
}
3) Allow Single Role from a Dynamic Set: For cases where you want to allow "a specific role that starts with ADMIN", but you don't necessarily know all of the allowed role suffixes, you can insert the role name at render time with JSTL. As an example, consider an app with many workspaces, each with a unique code. You want to create a ROLE_ADMIN_workspaceName role for each workspace. When someone is visiting the ABC workspace page, you only want the admin links to appear if the user has the ROLE_ADMIN_ABC role. Let us assume that every workspace uses the same JSP view, and the name is passed into the model as ${workspaceName}.
<sec:authorize access="hasRole('ROLE_ADMIN_${workspaceName}')">
You are allowed to see these admin links.
</sec:authorize>
4) Allow Any Role from a Dynamic Set: This is identical to the solution for #2.
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 understand that you can use forms authentication to grant/deny access to certain pages based on the criteria of your choosing.
However I wish to go in a little more specific than that and say, have different buttons appear for users based on thier permissions.
I know I could do something like
if(((User)ViewData["CurrentUser"]).IsEmployee).....
But that doesn't seem very elegant and could get messy very quickly.
Are there any guidelines/tools/framework features that could help me out here?
Use role-based authentication, then set roles appropriately. Then you can do things like:
if (ViewContext.HttpContext.User.IsInRole("vEmployee") {
The advantage of this is that it's core ASP.NET functionality -- not even MVC-specific -- so it's going to work with every possible membership provider.
Then you can add a view helper overload for whatever control you want to conditionally display:
public static string TextBox(this HtmlHelper helper,
string name, string value, string role, object htmlAttributes)
{
if helper.ViewContext.HttpContext.User.IsInRole(role) {
return helper.TextBox(name, value, htmlAttributes);
}
else
{
return null;
}
}
...and call it:
<%= Html.TextBox("name", "value", "vEmployee", null) %>
I had the same issue a while ago for a WPF application. It could work for ASP.NET as well.
For every "button" (UserControl in WPF) you set by attribute the role needed to execute its functionality.
At the begninning of your Action, you create a list of all the "Buttons" that require a special authorization.
Before calling the "return View()" you call a functions that iterate all you special "Buttons" and sets is visibility based on the role of the user.
For WPF that works because you can't call the method by a get/post request... For the web you should make something more sophisticated not just hide/show the button...
I hope this gives you at least a clue... It worked pretty fine for my implementation, but it was just a prototype...But I think I'll use it in future.
PS: Sample code can be found here
Don't do it. Use the controller for that kind of logic