i'm using Grails 2.1.1 in my project, right now i'm using springSecurityService.currentUser to get user credential, etc.
in the past 2 days, my project need some CMS extension and i've stumbled upon Weceem plugins.
set things here and there, in the end my project with Weceem plugins is now running, but getting Null Pointer Exception each time the springSecurityService.currentUser method is called.
Without weceem grails-plugin everything is running fine, so i assume there's some settings that i need to make. the question is where and what?
this is my user class
class User {
transient springSecurityService
String username
String password
boolean enabled = true
boolean accountExpired = false
boolean accountLocked = false
boolean passwordExpired = false
Person person
static hasOne = [Person]
static hasMany = [roles: Role]
static constraints = {
username blank: false, unique: true
password blank: false
}
static mapping = {
password column: '`password`'
}
Set<Role> getAuthorities() {
roles as Set
}
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
protected void encodePassword() {
password = springSecurityService.encodePassword(password)
}}
and this is my controller that called the springSecurityService
//show the list of all person
def list = {
//get all the sorting params
params.sort = params.sort ?: 'firstName'
params.order = params.order ?: 'asc'
params.max = params.max ?: 10
params.offset = params.offset ?: 0
def test = springSecurityService.getCurrentUser()
def personList = Person.createCriteria().list (max: params.max, offset: params.offset) {
if (springSecurityService.currentUser.person.affiliate.value != 'Admin'){
eq("affiliate", springSecurityService.currentUser.person.affiliate)
eq("deleted", false)
}
order(params.sort, params.order)
}
render view:'list', model:[persons: personList, personTotal: personList.totalCount]
}
Related
I'm writing an application on Grails. I'm trying to add child database record to parent table using addTo-method. I follow this documentation about addTo-method. And for example, documentation says create parent-class:
class Author { String name
static hasMany = [fiction: Book, nonFiction: Book]
}
Follow this I created my parent-class:
class Cafee {
String cafeeName = ""
int totalReservationPlaces = 0
double placeCost = 0
String currencyType = ""
boolean isReservationAvailable = false
boolean reservationTimeLimit = false
boolean reservationDateLimit = false
int totalPlaces = 0
long startTimeLimit = 0
long endTimeLimit = 0
Date startDateLimit = new Date()
Date endDateLimit = new Date()
static constraints = {
cafeeName blank: false, unique: true
}
String getCafeeName(){
return cafeeName
}
static hasMany = [admin: Person]
}
Documentation says create child-class:
class Book { String title
static belongsTo = [author: Author]
}
Follow this I've created my child-class:
class Person {
transient springSecurityService
String username
String password
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired
String firstName
String lastName
String email
String inn = ""
boolean isAdminCafee = false
static transients = ['springSecurityService']
static belongsTo = [cafee:Cafee]
static constraints = {
username blank: false, unique: true
firstName blank: false
lastName blank: false
password blank: false
email blank: false, unique: true
}
static mapping = {
password column: '`password`'
}
Set<Authority> getAuthorities() {
PersonAuthority.findAllByPerson(this).collect { it.authority }
}
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
protected void encodePassword() {
password = springSecurityService?.passwordEncoder ? springSecurityService.encodePassword(password) : password
}
}
And documentation says to add child record to parent I must do something this:
def fictBook = new Book(title: "IT")
def nonFictBook = new Book(title: "On Writing: A Memoir of the Craft")
def a = new Author(name: "Stephen King")
.addToFiction(fictBook)
.addToNonFiction(nonFictBook)
.save()
Follow it in Bootstrap I've done this:
def user = Person.findOrSaveWhere(username: 'testerAndrewRes', password:'password', firstName:'Andrew', lastName:'Bobkov', email:'pragm#gmail.com', isAdminCafee: true,
inn: '1234567890')
println user
if(!user.authorities.contains(adminRole))
{
PersonAuthority.create(user, adminRole, true)
}
def newCafe = new Cafee(cafeeName: "Tarelka").addToAdmin(user).save()
But I get an error:
ERROR context.GrailsContextLoaderListener - Error initializing the application: object references an unsaved transient instance - save the transient instance before flushing: restorator.auth.Person; nested exception is org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: restorator.auth.Person
Message: object references an unsaved transient instance - save the transient instance before flushing: restorator.auth.Person; nested exception is org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: restorator.auth.Person
What I do wrong?
The error message is clear I think.
Try adding:
user.save(flush:true)
before:
def newCafe = new Cafee(cafeeName: "Tarelka").addToAdmin(user).save()
How I can hide password column from GORM view:
My domain class:
class SecUser {
static scaffold = true
transient springSecurityService
String username
String password
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired
static transients = ['springSecurityService']
static constraints = {
username blank: false, unique: true
password (display:false, blank: false)
}
static mapping = {
password column: '`password`'
}
Set<SecRole> getAuthorities() {
SecUserSecRole.findAllBySecUser(this).collect { it.secRole } as Set
}
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
protected void encodePassword() {
password = springSecurityService.encodePassword(password)
// password = password
}
}
The display: false constraint is used to hide the property from the default scaffolded view. The project at https://github.com/jeffbrown/scaffolddisplay demonstrates this. You must have something in your app that is getting in the way of that. Possibly you have generated views which contain the property. Possibly you are using a plugin which is providing the view.
Installed spring-security-core 2.0-RC2 (with grails 2.3.6), ran the quick start but I'm not able to log in. Each time I try, I get the 'Sorry, we were not able to find a user with that username and password.' error.
Done some research and I'm not double encoding the password or nor am I using salt (from what I can tell). I've used earlier versions in other projects, so not sure what's going on. I've also dropped the encodePassword() from the domain class and verified in the DB that it's what I expect it to be
Here's my User domain class:
class User {
transient springSecurityService
String username
String password
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired
static transients = ['springSecurityService']
static constraints = {
username blank: false, unique: true
password blank: false
}
static mapping = {
password column: '`password`'
}
Set<Role> getAuthorities() {
UserRole.findAllByUser(this).collect { it.role } as Set
}
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
protected void encodePassword() {
password = springSecurityService.encodePassword(password)
}
}
and my Bootstrap:
def adminRole = new Role(authority: 'ROLE_ADMIN').save(flush: true)
def userRole = new Role(authority: 'ROLE_USER').save(flush: true)
def testUser = new User(username: 'me', password: 'me')
testUser.save(flush: true)
UserRole.create testUser, adminRole, true
UserRole.create testUser, userRole, true
any idea of what I'm doing wrong?
Thanks!
That looks fine, but funny things can be happening under the hood. I wrote up a couple of blog posts to help diagnose issues like this. Check out http://burtbeckwith.com/blog/?p=2003 and http://burtbeckwith.com/blog/?p=2029
I have installed the grails Spring-Security plugin:
plugins {
compile ':spring-security-core:2.0-RC2'
}
Then I used the grails s2-quickstart com.jane Person Role command to create the needed domain classes.
As I have my own User class I refactored the code to use my User class:
package com.jane
class User {
transient springSecurityService
String email
String name
String password
Boolean isAgreeTerms = false
Date agreeTermsDt
Boolean isActive = false
Boolean isBlocked = false
Date dateCreated
Integer createdBy = 0
Date lastUpdated
Integer modifiedBy = 0
static transients = [ 'springSecurityService' ]
static hasMany = [ userProductTier: UserProductTier ]
static mapping = {
id column: "userID"
dateCreated column: 'createdDt'
lastUpdated column: 'modifiedDT'
}
static constraints = {
email blank: false, email: true, unique: true, size: 5..100
name blank: false, size: 3..50
password blank: false
}
void beforeInsert() {
if ( isAgreeTerms ) {
agreeTermsDt = new Date()
}
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
protected void encodePassword() {
password = springSecurityService.encodePassword(password)
}
}
I then modified the config.groovy file to:
grails.plugin.springsecurity.userLookup.userDomainClassName = 'com.jane.User'
grails.plugin.springsecurity.userLookup.usernamePropertyName = 'email'
grails.plugin.springsecurity.userLookup.enabledPropertyName = 'isActive'
grails.plugin.springsecurity.userLookup.accountExpiredPropertyName = 'isBlocked'
grails.plugin.springsecurity.userLookup.accountLockedPropertyName = 'isBlocked'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'com.jane.UserRole'
grails.plugin.springsecurity.authority.className = 'com.jane.Role'
I can create users fine, verify they are in the database, have verified that encodePassword is called once. But every time I try to login I get the following error:
Sorry, we were not able to find a user with that username and
password.
And here is the service method to create users:
User createTeamLeader( String name, String email, String password, Boolean isAgreeTerms, Integer productTierId ) {
User user = new User( name: name, email: email, password: password, isAgreeTerms: isAgreeTerms, isActive: true)
UserProductTier userProductTier = new UserProductTier( productTierId: productTierId )
user.addToUserProductTier( userProductTier )
user.save()
UserRole.create( user, Role.findByAuthority('ROLE_USER'), true )
UserRole.create( user, Role.findByAuthority('ROLE_LEAD'), true )
user
}
Often adding debug logging helps, since Spring Security logs a lot at the debug level:
log4j = {
...
debug 'org.springframework.security'
}
In this case it didn't show the problem, so I added an event listener to see if there was information in the failure event:
grails.plugin.springsecurity.useSecurityEventListener = true
grails.plugin.springsecurity.onAbstractAuthenticationFailureEvent = { e, appCtx ->
println "\nERROR auth failed for user $e.authentication.name: $e.exception.message\n"
}
That displayed this:
ERROR auth failed for user ernie#ss.com: No such property: authorities for class: com.jane.User
When you made changes in the class, you removed the getAuthorities method that was in the original version, and is used by the UserDetailsService to determine granted roles during authentication. Adding it back got things working:
Set<Role> getAuthorities() {
UserRole.findAllByUser(this).collect { it.role } as Set
}
I want to retrieve all users which have a specific Role like "ROLE_USER".
Below are Domain Classes for User, Role and UserRole.
User.groovy
class User {
transient springSecurityService
String username
String password
String email
boolean enabled
boolean accountExpired
boolean accountLocked
boolean passwordExpired
static constraints = {
username blank: false, unique: true
password blank: false
}
static mapping = {
password column: '`password`'
}
Set<Role> getAuthorities() {
UserRole.findAllByUser(this).collect { it.role } as Set
}
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
protected void encodePassword() {
password = springSecurityService.encodePassword(password)
}
}
Role.groovy
class Role {
String authority
static mapping = {
cache true
}
static constraints = {
authority blank: false, unique: true
}
}
UserRole.groovy
class UserRole implements Serializable {
User user
Role role
boolean equals(other) {
if (!(other instanceof UserRole)) {
return false
}
other.user?.id == user?.id &&
other.role?.id == role?.id
}
int hashCode() {
def builder = new HashCodeBuilder()
if (user) builder.append(user.id)
if (role) builder.append(role.id)
builder.toHashCode()
}
static UserRole get(long userId, long roleId) {
find 'from UserRole where user.id=:userId and role.id=:roleId',
[userId: userId, roleId: roleId]
}
static UserRole create(User user, Role role, boolean flush = false) {
new UserRole(user: user, role: role).save(flush: flush, insert: true)
}
static boolean remove(User user, Role role, boolean flush = false) {
UserRole instance = UserRole.findByUserAndRole(user, role)
if (!instance) {
return false
}
instance.delete(flush: flush)
true
}
static void removeAll(User user) {
executeUpdate 'DELETE FROM UserRole WHERE user=:user', [user: user]
}
static void removeAll(Role role) {
executeUpdate 'DELETE FROM UserRole WHERE role=:role', [role: role]
}
static mapping = {
id composite: ['role', 'user']
version false
}
}
These Domain Classes are generated by Spring Security plugin.
I have added only email field for User class.
Here is my UserController.groovy
class UserController {
def index = {
}
def list = {
def role = Role.findByAuthority("ROLE_USER")
println "role id "+role.id
def users = User.findAll() //Its giving me all Users regardless of Role
println "total users "+users.size()
for(user in users)
{
println "User "+user.username+" "+user.email
}
render (view: "listUsers", model:[users:users])
}
}
In the list action I used User.findAll() but its giving me all user with all roles.
I want user list only from a certain role..
EDIT
Code to Assign Roles to newly created user
def username = params.username
def emailID = params.emailID
def password = params.password
def testUser = new User(username: username, enabled: true, password: password,email:emailID)
testUser.save(flush: true)
def userRole = new Role(authority: 'ROLE_USER').save(flush: true)
UserRole.create testUser, userRole, true
Thanks..
Replace
def users = User.findAll()
with
def users = UserRole.findAllByRole(role).user
and you should get all users with the required role.
EDIT
In your code sample you try to create a new Role for the User. Since a Role with the authority ROLE_USER already exists and authority has to be unique (see the 'constraints' part in your Role class) this new Role cannot be saved to the database. Because the Role you assign in UserRole.create doesn't exist in the database the UserRole is not saved either. You would have to assign the existing Role to the new User (e.g. with `Role.findByAuthority').
Creating the roles in Bootstrap.groovy is a good idea according to Spring Source because roles "are typically defined early in the life of the application and correspond to unchanging reference data. That makes BootStrap the ideal place to create them." (Spring Source Blog)