I'm unable to get springSecurityService.currentUser from a controller in Grails 3.2.8.
Please note that Grails 3.2.8 made some performance improvements not in previous versions that seem to be breaking Spring Security Core. As per Grails 3.2.8 dependency injection in domain classes, I set grails.gorm.autowire = true, which fixed that incompatibility.
Steps to reproduce:
Create a new Grails 3.2.8 web app with Spring Security 3.1.1 using Roles and Groups.
In application.yml, set grails.gorm.autowire = true
In Bootstrap:
def init = { servletContext ->
User user = new User(username: 'foo', password:'foo').save(flush: true)
Role role = new Role(authority: 'SomeRole').save(flush: true)
RoleGroup roleGroup = new RoleGroup(name: 'SomeRole').save(flush: true)
RoleGroupRole.create(roleGroup, role)
UserRoleGroup.create(user, roleGroup)
}
Create a controller TestController:
#Secured(['SomeRole'])
class TestController {
def springSecurityService
def index() {
println "springSecurityService==null? ${(springSecurityService==null).toString()}"
println "SecurityContextHolder.context==null? ${(SecurityContextHolder.context==null).toString()}"
println "SecurityContextHolder.context?.authentication==null? ${(SecurityContextHolder.context?.authentication==null).toString()}"
println "springSecurityService.principal==null? ${(springSecurityService.principal==null).toString()}"
println "springSecurityService.currentUser==null? ${(springSecurityService.currentUser==null).toString()}"
render "1" //Render something so we don't get an exception.
}
}
Start up the server and go to /test. The output is:
springSecurityService==null? false
SecurityContextHolder.context==null? false
SecurityContextHolder.context?.authentication==null? true
springSecurityService.principal==null? true
springSecurityService.currentUser==null? true`
Is there a good workaround?
If SecurityContextHolder.context is not null (it should never be null) but
SecurityContextHolder.context?.authentication is null, then this is probably not a Grails or a plugin issue - you're not authenticated. So there's no principal to get the cached user id from (i.e. springSecurityService.principal is null as your output shows) and there's no way to retrieve the current User instance.
SOLVED. Since version 3.2.8 there is this default setting in application.yml: grails.gorm.autowire=false. You have to set it to true then the services autowire as always.
Related
I have a modified User class in my spring security which use attribute email instead of username. Now I want to a functionality to switch users, so an admin can login seamlessly as a particular user without logging out. I came across this Link , which shows there is a switchUserFilter to achieve this. So I tried to get it working by passing j_username as email,but it gets redirected to a blank page and the user does not switch.
I have tried all these things but still could not figure out a way around it:
1) Added to Config.groovy:
grails.plugins.springsecurity.userLookup.usernamePropertyName='email'
2) Create a method in User class getUserName() to return email.
P.S: I looked into the source code of springSecurity switchUserFilter(link)and came across this code on line 209:
protected Authentication attemptSwitchUser(HttpServletRequest request)
throws AuthenticationException {
UsernamePasswordAuthenticationToken targetUserRequest;
String username = request.getParameter(usernameParameter);
But I am not sure if that is the issue and do not want to make changes in the plugin.
The usernameParameter property of the SwitchUserFilter is set to username by default. That does seem to be part of your problem.
The SwitchUserFilter has a method named setUsernameParameter() that allows you to change this default. It seems the filter is a bean, so you might be able to do something like this in grails-app/conf/spring/Config.groovy
import org.springframework.security.web.authentication.switchuser.SwitchUserFilter
beans = {
switchUserFilter {
usernameParameter = 'email'
}
}
Or maybe something like this in grails-app/config/BootStrap.groovy
def switchUserFilter
def init = { servletContext ->
switchUserFilter.usernameParameter = 'email'
}
Finally found the solution: Add this to the config.groovy file
grails.plugin.springsecurity.userLookup.usernamePropertyName = 'email'
grails.plugin.springsecurity.useSwitchUserFilter = true
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
....
'/j_spring_security_switch_user': ['ROLE_SWITCH_USER', 'isFullyAuthenticated()'],
'/j_spring_security_exit_user': ['isFullyAuthenticated()'],
'/public/**': ['permitAll']
.....
]
2) Then create a Role ROLE_SWITCH_USER in bootstrap.groovy
def switchUserRole = Role.findByAuthority('ROLE_SWITCH_USER') ?: new Role(authority: 'ROLE_SWITCH_USER').save(flush: true, failOnError: true)
And assign it to a super user
3) Then follow the instruction(here) to update the view to add a switch button
I am using grails 2.3.4 and spring security core 2.0 RC2 and spring security ui 1.0 RC1. Every thing is working fine but when ever there is session time out I get following error "Error in grail layout main" because I have called session variable in my layout's main.gsp file.Now I want to redirect to login page after every session timeout and dont show the error page.To redirect after session time out i have done it in bootstrap.groovy file as
def structureMap1 = Requestmap.findByUrl("/institution/index") ?: new Requestmap(url: "/institution/index",configAttribute: "ROLE_INSTITUTION").save(failOnError:true)
but there are so many pages so it is difficult to write for every page . Is there any other method to do it please help.
How about using SecurityFilters you can place it in your conf folder:
class SecurityFilters {
def filters = {
catchRememberMeCookie(url: "/**") {
before = {
if (!session.user) {
def g = new org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib()
def confirmurl= g.createLink(controller: controllerName, action: actionName, params:params, absolute: 'true' )
session.lastURL=request.getHeader('referer') ?: confirmurl
redirect(controller:'auth',action:'denied')
return false
}
}
}
This segment is an example and will not answer your question at hand since there is insufficient information to give a detailed answer but with a security filter - this sits above all your requests and if you need it to redirect to another location based on a specific value etc then you can so if no session.user do something else which will then kick in for all your actions
I have upgraded My Spring security plugin from spring-security-core:1.2.7.2 to spring-security-core:2.0-RC2 and my application is using Grails 2.3.7.
After upgrade I changed the imports accordingly so all compilation error got fixed but after running my application when I tried to access it http://localhost:8080/login/auth I got exception like :
Caused by: groovy.lang.MissingPropertyException: No such property: id for class: org.springframework.security.core.userdetails.User
as auth.gsp is using custom tag lib and code is like
if(springSecurityService.principal!="anonymousUser")user = SecUser.get(springSecurityService.principal.id)
here it is saying No such property: id for class: org.springframework.security.core.userdetails.User
Not sure how to fix this problem ...
Until i can see what you want is to retrieve current logged user id, there is a special helper that only get the user id "loadCurrentUser()"
i paste this code from grails spring security core plugin in section loadCurrentUser()
class SomeController {
def springSecurityService
def someAction() {
def user = springSecurityService.isLoggedIn() ? springSecurityService.loadCurrentUser() : null
if (user) {
CreditCard card = CreditCard.findByIdAndUser(params.id as Long, user)
…
}
…
}
}
i hope it is usefull
Grails 2.1.1
I can't seem to get a command object to be injected with a service so that I can use custom validator. I've tried several things, including
Grails command object data binding and
what the 2.1.1 docs on custom validator suggest, I just can't figure this one out..
Relevant Code:
class RegistrationCommand {
String username
def registrationService
static constraints = {
username validator: { val, obj ->
obj.registrationService.isUsernameUnique(val) }
}
}
class RegistrationService {
def isUsernameUnique(username){
def user = new User(username:username)
user.validate()
if(user.errors.hasFieldErrors("username")){
return false
}else{
return true
}
}
Resolved.. Issue was due to plugin.
I'm using a plugin for client side jquery validation (jquery-validation-ui-1.4.2). The command object being created by the plugin's controller wasn't getting injected with the service. The issue was reported https://github.com/limcheekin/jquery-validation-ui/issues/17 . The fix does work but has not been pushed upstream yet.
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)
}
}
}