I'm getting ready to implement the Spring Security UI plugin (we've already implemented the Spring Security Core plugin). I know the core plugin has support for users, roles, and groups, however, I don't see any mention of groups in the Spring Security UI plugin's documentation. Does Spring Security UI plugin not support creating, edition, etc. groups? Anyone tried adding this functionality?
A late response, but I had the same question so I thought I would just try it.
I have just attempted this myself and I believe the the answer is No. (out of the box)
The spring security ui plugin doesn't take the groups into consideration. If you try to edit a user
myapp/user/edit/1
you will recieve some sort of error like:
Class groovy.lang.MissingPropertyException
Message
No such property: authority for class: com.myapp.security.SecGroup Possible solutions: authorities
I'm curious if you found a way around this? Or we will have to customize the the plugin.
As Julian noted the UI doesn't provide support for groups out of the box. To avoid the error you can do the following (customize the plugin):
Copy the User controller into your project to override the plugin's controller:
grails s2ui-override user <your-package-for-controller>
Copy the "buildUserModel" from the plugin code in UserController and edit the userRoleNames field:
import grails.plugin.springsecurity.SpringSecurityUtils
class UserController extends grails.plugin.springsecurity.ui.UserController {
protected Map buildUserModel(user) {
...
// Added so that when using groups doesn't cause an error
Set userRoleNames
if (SpringSecurityUtils.securityConfig.useRoleGroups) {
String groupAuthorityFieldName = SpringSecurityUtils.securityConfig.authority.groupAuthorityNameField
userRoleNames = user[authoritiesPropertyName].collect { it[groupAuthorityFieldName].collect { it[authorityFieldName] } }
} else {
userRoleNames = user[authoritiesPropertyName].collect { it[authorityFieldName] }
}
...
}
Related
I'm having a set of Sping Data Repositories which are all exposed over Rest by using Spring-data-rest project. Now I want to secure the HTTP, so that only registered users can access the http://localhost:8080/rest/ So for this purpose I add #Secured(value = { "ROLE_ADMIN" }) to all the repositories and I also enable the security by specifying the
#EnableGlobalMethodSecurity(securedEnabled = true, jsr250Enabled = true, prePostEnabled = true)
So now what happens is I go to the rest and it's all good - i'm asked to authenticate. Next thing I do is I go to my website (which uses all the repositories to access the database) but my request fails with
nested exception is org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
which is correct because i'm browsing my website as anonymous user.
So my question is: is there a way to provide method authentication for the REST layer only? To me it sounds like a new annotation is needed (something like #EnableRestGlobalMethodSecurity or #EnableRestSecurity)
I don't know if this will solve your problem, however I managed to get something similar, working for me by creating an event handler for my specific repository, and then used the #PreAuthorize annotation to check for permissions, say on beforeCreate. For example:
#RepositoryEventHandler(Account.class)
public class AccountEventHandler {
private final Logger logger = LoggerFactory.getLogger(getClass());
#PreAuthorize("isAuthenticated() and (hasRole('ROLE_USER'))")
#HandleBeforeCreate
public void beforeAccountCreate(Account account) {
logger.debug(String.format("In before create for account '%s'", account.getName()));
}
#PreAuthorize("isAuthenticated() and (hasRole('ROLE_ADMIN'))")
#HandleBeforeSave
public void beforeAccountUpdate(Account account) {
logger.debug(String.format("In before update for account '%s'", account.getName()));
//Don't need to add anything to this method, the #PreAuthorize does the job.
}
}
I am trying to write a grails plugin using Spring social core plugin. I get the provider popup and after I enter user and password it is giving me 404. As I debugged the code, it is coming into SpringSocialProviderSignInController handleSignIn() method and it is not getting anything for signup url. In grails plugin this is the code snipet
if (userIds.size() == 0) {
if (log.isDebugEnabled()) {
log.debug("No user found in the repository, creating a new one...")
}
ProviderSignInAttempt signInAttempt = new ProviderSignInAttempt(connection, connectionFactoryLocator, usersConnectionRepository)
request.setAttribute(ProviderSignInAttempt.SESSION_ATTRIBUTE, signInAttempt, RequestAttributes.SCOPE_SESSION)
//TODO: Document this setting
result = request.session.ss_oauth_redirect_on_signIn_attempt ?: config.page.handleSignIn
}
I see that even in the regular spring social web jar this has similar logic. Except in the web there is a default set on signupUrl. I tried giving the same value(/signup) in config.page.handleSignIn but it did not help.
if (userIds.size() == 0) {
ProviderSignInAttempt signInAttempt = new ProviderSignInAttempt(connection, connectionFactoryLocator, usersConnectionRepository);
request.setAttribute(ProviderSignInAttempt.SESSION_ATTRIBUTE, signInAttempt, RequestAttributes.SCOPE_SESSION);
return redirect(signUpUrl);
}
In general, I am trying to understand what this signUpUrl does. I am not able to go further after this. Is it mandatory to give signUpUrl? My understanding was no.
Have asked the same question in spring social forum, but is not getting any response there. Trying my luck here.
Found meaningful answer in spring forum : Spring Forum Link
I am (finally) upgrading my Acegi plugin to Spring Security Core. At the same time, I am upgrading from Grails 1.3.7 to 2.0. My site was fully functional before, but now when I try to get to my default page (which is IS_AUTHENTICATED_ANONYMOUSLY) I am redirected to the auth action of my LoginController. This method was never invoked with Acegi, so I don't know what the problem is. Have I set up my configuration wrong or is there something else I need to be thinking about?
grails.plugins.springsecurity.securityConfigType = SecurityConfigType.InterceptUrlMap
grails.plugins.springsecurity.interceptUrlMap = [
'/blog/**':['IS_AUTHENTICATED_ANONYMOUSLY'],
'/static/**':['IS_AUTHENTICATED_ANONYMOUSLY'],
'/consensus/**':['IS_AUTHENTICATED_FULLY'],
'/login/**':['IS_AUTHENTICATED_ANONYMOUSLY'],
'/signup/**':['IS_AUTHENTICATED_ANONYMOUSLY'],
'/home/**':['IS_AUTHENTICATED_FULLY'],
'/test/**':['ROLE_ADMIN'],
'/admin/**':['ROLE_ADMIN'],
'/adminmanage/**':['ROLE_ADMIN'],
'/quartz/**':['ROLE_ADMIN'],
'/**/*.css':['IS_AUTHENTICATED_ANONYMOUSLY'],
'/js/**':['IS_AUTHENTICATED_ANONYMOUSLY'],
'/images/**':['IS_AUTHENTICATED_ANONYMOUSLY'],
'/monitoring**':['ROLE_ADMIN'],
'/**':['IS_AUTHENTICATED_FULLY']
]
My UrlMappings.groovy is:
class UrlMappings {
static mappings = {
"/"(controller:"x", action:"y")
"/z/?"(controller:"x", action:"y")
"/$controller/$action?/$id?"
{
constraints {
// apply constraints here
}
}
"500"(view: '/error')
}
}
I have been reading through the documentation but am having some problems, so I am not sure if there is more relevant code one would need to see. If there is, please let me know and I will add it. Thanks.
Other options in my Config.groovy were incorrect and this caused the problem. Once I corrected them everything worked fine.
Despite it being called out in the documentation, I had security fields that were not prepended with grails.plugins.springsecurity This caused the engine not to recognize them, which for some reason resulted in the call to auth.
After remove openid plugin all requests redirects me to the login page! I don't know what to do... I've already remove everything related.
I want to implement permission-based access control as discussed in this post.
I am not familiar with the implementation - is there any detailed example on how to implement this from start to finish?
Have you seen the Spring security plugin? Main docs are here
As in this post you could also consider the Shiro plugin as well. I find the Spring security plugin a simpler but the Shiro one does have some advantages as discussed in the post.
I have just solved this (mostly) so I post it here for reference. This solution works on Grails 2.2.4 and Spring Security 2.0 RC
1) Security Domain Model
You model your security domain classes as described in the article, so you will have these domains in the end:
- Permission
- Role
- RolePermission
- User
- UserRole
2) Querying authorities for users
You make sure that your User class returns Permissions instead of Roles as authorities in the getAuthorities() method:
/**
* Gets authorities for the user.
*
* It will return all of the Permissions of the User assigned by the Roles
* which the User has
*/
Set<Permission> getAuthorities() {
Set allPermissions = []
// Collect all Roles of the User
UserRole.findAllByUser(this).each { userRole ->
// Collect all Permissions from the Role
Role role = userRole.role
// Returning the collected permissions
RolePermission.findAllByRole(role).each { rp ->
allPermissions.add(rp.permission)
}
}
return allPermissions
}
3) Spring Security Config
I have this in my Config.groovy for Spring Security configuration (non-relevant parts omitted):
grails {
plugin {
springsecurity {
...
userLookup {
userDomainClassName = 'limes.security.User'
}
authority {
nameField = 'name'
className = 'limes.security.Permission'
}
...
}
}
}
One important highlight is the authority.nameField which MUST conform with your Permission class. The name attribute is called 'name' in my model (and the article).
Naturally, you set your Permission class as the authority.className in order to make it fit with the return values of User.getAuthorities().
4) Using in security expressions
The solution above does not solve the limitation of the Grails Spring Security plugin that you can use only authority name starting with "ROLE_".
So, if you want to call your permissions like "PERM_PERMISSION1", than you have to write EL expressions for checks everywhere (notybly on controller #Secured annotations and static url rules).
So instead of
#Secured(["PERM_PERMISSION1"])
You write
#Secured(["hasRole('PERM_PERMISSION1')"])
I am trying to use the commentable plugin with Spring Security.
I can't manage to write the right
grails.commentable.poster.evaluator
I tried {User.get(springSecurityService.principal.id)},
but from the CommentController, both User and springSecurity seems unaccessible.
What should I do?
For springSecurityService.principal.id since there's no dependency injection field for springSecurityService it can't work, so you need to call what springSecurityService.principal.id calls - org.springframework.security.core.context.SecurityContextHolder.context.authentication.principal.id
To fix the problem with User, you'll need the full class name with package. So combined, this should be
{com.yourcompany.yourapp.User.get(org.springframework.security.core.context.SecurityContextHolder.context.authentication.principal.id)}
I adapted Burt's answer such that it doesn't throw an exception if nobody is logged in
grails.commentable.poster.evaluator = {
def principal = org.springframework.security.core.context.SecurityContextHolder.context.authentication?.principal
if (principal?.hasProperty('id')) {
def currentUserId = principal.id
if (currentUserId) {
com.yourcompany.yourapp.User.get(currentUserId)
}
}
}