Grails transient properties not picked up on object creation - grails

After migrating from Grails 1.3.7 to 2.0.4 I have noticed a problem with one of my domain classes where I use transient properties in order to handle passwords.
My domain class looks like this (simplified):
package test
class User {
String email
String password1
String password2
//ShiroUser shiroUser
static constraints = {
email(email:true, nullable:false, unique:true)
password1(nullable:true,size:5..30, blank: false, validator: {password, obj ->
if(password==null && !obj.properties['id']){
return ['no.password']
}
else return true
})
password2(nullable:true, blank: false, validator: {password, obj ->
def password1 = obj.properties['password1']
if(password == null && !obj.properties['id']){
return ['no.password']
}
else{
password == password1 ? true : ['invalid.matching.passwords']
}
})
}
static transients = ['password1','password2']
}
In 1.3.7 this used to work in my Bootstrap:
def user1= new User (email: "test#test.com", password1: "123456", password2: "123456")
user1.save()
However, in Grails 2.0.x this will result in error stating that password1 and password2 are both null.
The same thing happens in my controllers if I try to do:
def user2= new User (params)// params include email,password1 and password2
In order to make it work I have to do the following workaround:
def user2= new User (params)// params include email,password1 and password2
user2.password1=params.password1
user2.password2=params.password2
user2.save()
This is quite ugly - and annoying.
Can anyone say if my usage of transients has become invalid in grails 2.x, or if this could be a framework bug of some kind?

For security reasons transients are no longer auto-bound. But you can easily make it work by adding in a 'bindable' constraint (see http://grails.org/doc/latest/ref/Constraints/bindable.html). Change
password2(nullable:true, blank: false, validator: {password, obj ->
to
password2(bindable: true, nullable:true, blank: false, validator: {password, obj ->

I think as the part of data binding improvement in grails 2.x - it won't bind transient properties.

Related

How to use beforeInsert() and beforeUpdate() in GORM

I'm working on an inventory management system in Grails, the application will keep track of assets information such as Users, Brand, Type etc. I have 3 domain classes (other class are not important for this discussion) namely, User, Movement and Inventory.
Each assets is owned by a particular User. When the asset is transferred from the current owner to a new owner in the Movement class, the change should be reflected in the User class and Inventory class. These are my classes:
User:
class User {
String userID
String fullName
String position
Department department
String toString(){
fullName
}
static hasMany = [inventories: Inventory, movementsByOldUser: Movement, movementsByNewUser: Movement]
static mappedBy = [movementsByOldUser: 'oldUser', movementsByNewUser: 'newUser']
static constraints = {
userID blank: false, unique: true
fullName blank: false
position()
department()
}
}
Movement:
class Movement {
User oldUser
User newUser
Inventory inventoryID
Date movementDate
User userResponsible
static constraints = {
inventoryID blank: false
oldUser blank: false
newUser blank: false
movementDate()
userResponsible blank: false
}
}
Inventory:
class Inventory {
String inventoryID
String code
String description
String serial_num
Date purchase_date
Date record_date
Type type
Brand brand
User user
static hasMany = [movements: Movement]
String toString(){
"$inventoryID, $type"
}
static constraints = {
inventoryID blank: false, unique: true
code blank: false
description nullable: true, maxSize: 1000
serial_num blank: false
purchase_date()
image nullable: true, maxSize: 1000000
record_date()
remarks nullable: true, maxSize: 1000
type()
brand()
user()
}
}
I have heard of the GORM method called beforeInsert() and beforeUpdate() that they can do the job, but I'm completely new to Grails, Groovy and of course GORM as this is the first application I develop, I have no idea how to use them in my codes. I did host of research but none match my scenario so I cannot get a clear picture of how to use it.
Question edited from here:
I have made some changes to the class User by using beforeUpdate() and beforeUpdate() but it gets an error shown below.
User class (edited version):
class User {
String userID
String fullName
String position
Department department
String toString(){
fullName
}
static hasMany = [inventories: Inventory, movementsByOldUser: Movement, movementsByNewUser: Movement]
static mappedBy = [movementsByOldUser: 'oldUser', movementsByNewUser: 'newUser']
def beforeInsert(){
this.fullName = 'oldUser'
}
def beforeUpdate(){
this.fullName = 'newUser'
}
static constraints = {
userID blank: false, unique: true
fullName blank: false
position()
department()
}
}
Error:
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00000000543e4bc2, pid=7488, tid=6520
#
# JRE version: Java(TM) SE Runtime Environment (8.0_05-b13) (build 1.8.0_05-b13)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.5-b02 mixed mode windows-amd64compressed oops)
# Problematic frame:
# V [jvm.dll+0x424bc2]
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# C:\Users\Kanaan\MFEDinventory\hs_err_pid7488.log
#
# Compiler replay data is saved as:
# C:\Users\Kanaan\MFEDinventory\replay_pid7488.log
#
# If you would like to submit a bug report, please visit:
# http://bugreport.sun.com/bugreport/crash.jsp
#
| Error Forked Grails VM exited with error

springSecurityService how to NOT store passwords in cleartext?

This tutorial:
http://spring.io/blog/2010/08/11/simplified-spring-security-with-grails/
Says you should create users like this:
def adminUser = SecUser.findByUsername('admin') ?: new SecUser(
username: 'admin',
password: springSecurityService.encodePassword('admin'),
enabled: true).save(failOnError: true)
However, this does not work. It only works if you do this:
password: 'admin'
Which I am assuming (but could be wrong) that stores the password in the internal DB in plain text (not hashed).
Is there a way to tell spring to encrypt or hash passwords? Its not in any of the tutorials, and can't find it in the manual
Grails 2.3.6, security core 2.0-RC2 & UI, default install.
I have seen it said that grails by default does hash with bcrypt, but I dont know how to verify this. I guess I need to install mysql, tell grails to use this, then I can query the values.
Take a deep breath. By default the spring security plugin for Grails (recent versions) isn't going to store you passwords in clear text.
Take a look at your SecUser domain class and you will see that it's handling the encryption of the password for you. You can also see an example of this in the documentation.
This is directly from the documentation.
package com.mycompany.myapp
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)
}
}
If you haven't already read through the documentation I suggest you do. It's well written and will likely answer a lot of other questions you have about the plugin.

spring security core grails not logging in

Installed Spring Security Core as plugin then did quickstart
Here is my User domain class
package auth
class User {
def springSecurityService
String username
String password
boolean enabled
boolean accountExpired
boolean accountLocked
boolean passwordExpired
static mapping = {
// password is a keyword in some sql dialects, so quote with backticks
// password is stored as 44-char base64 hashed value
password column: '`password`', length: 64
}
static constraints = {
username blank: false, size: 1..50, unique: true
password blank: false, size: 8..100
}
Set getAuthorities() {
UserRole.findAllByUser(this).collect { it.role } as Set
}
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
protected encodePassword() {
password = springSecurityService.encodePassword(password, username)
}
}
And my boostrap.groovy is
class BootStrap {
def init = { servletContext ->
auth.User james = new auth.User(username: 'test', enabled: true, password: 'password')
james.save()
if (james.hasErrors())
{
println("he has errors")
}
println("we made it! ")
}
def destroy = {
}
}
But when I go to login, it keeps saying "Sorry, we were not able to find a user with that username and password." Any thoughts?
This is because you are using the salt while encoding the password.
password = springSecurityService.encodePassword(password, username)
I have no idea of salting and hence can not guide you to much.
But if you encode your password without salting then your code works, just remove username when encoding the password, try this
password = springSecurityService.encodePassword(password)
Hope this helps.
If you create the user in BootStrap.groovy, try changing this:
def adminUser = User.findByUsername('admin') ?: new User(
username: 'admin',
password: springSecurityService.encodePassword('admin'),
enabled: true).save(failOnError: true)
to this:
def adminUser = User.findByUsername('admin') ?: new User(
username: 'admin',
password: 'admin',
enabled: true).save(failOnError: true)
The problem is that you are using the encoding password twice, once in the Domain and once in the constructor's parameters.
Can you validate that the user is actually bootstrapped into the database?
If so, I ran into a similar issue with Tomcat caching some data incorrectly.
Here is what I did:
Stopped Tomcat
Deleted all the files in Tomcat's Temp directory
Restarted Tomcat
After that, it worked fine.
Let me know if this helps.
Also, its been a while since I've built a Grails site from scratch, but I think I remember there being an issue with some online instructions. SpringSecurity might be encoding the password for you, so when you do it, it is getting double encoded.
Try removing the lines that encode the password.

Grails domain class constraint modification causing exception

Am using grails 2.0.3 with default h2 database and have the following user domain class:
class User {
transient springSecurityService
String username
String password
boolean enabled
boolean accountExpired
boolean accountLocked
boolean passwordExpired
Preferences preferences
Company company
Personal personal
static constraints = {
username email: true, blank: false, unique: true
password blank: false
preferences unique: true
company unique: true
personal unique: true
}
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)
}
}
In the controller, I save the user using the following code:
userInstance.save(flush: true)
Now, this afternoon, I realized that the password field should have a size constraint and hence modified the domain class so that it became as follows (only change is in the constraints):
class User {
transient springSecurityService
String username
String password
boolean enabled
boolean accountExpired
boolean accountLocked
boolean passwordExpired
Preferences preferences
Company company
Personal personal
static constraints = {
username email: true, blank: false, unique: true
password blank: false, size: 6..15
preferences unique: true
company unique: true
personal unique: true
}
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)
}
}
Subsequently I generated the views and controllers again. Now when I am trying to save the user object from the controller, using:
userInstance.save(flush: true)
I am getting the following exception:
Class: org.hibernate.AssertionFailure
Message: null id in login.User entry (don't flush the Session after an exception occurs)
Any help will be appreciated.
Info: If I remove the size constraint from the new/modified class the
saving happens fine.
I ran into the same problem using Grails 3.1.12. This is what I found out and how I solved it.
Problem:
You are trying to put a size constraint to a field that is going to be enconded. This means that a password like "admin5" will turn at the end of the domain life cycle as an encoded pwd. For example the db will stored the pwd as: "$2a$10$dn7MyN.nsU8l05fMkL/rfek/d1odko9H4QUpiNp8USGhqx9g0R6om".
The validation process will apply the size constraint to the unencoded pwd (validation step on the domain life cycle), wich will pass because the pwd typed by the user is in that range. but on the save() method (persistance step on the domain life cycle) the pwd will be encoded before an insert or update. The enconding method will create a pwd with a size bigger than your constraint and Hibernate will fail the assert() for the pwd size.
Solution:
Use the minSize constraint if you don't need to worry about the maxSize
static constraints = {
password blank: false, minSize:6
}
If you need to validate the maxSize, then I recommend you do the validation on your Service or Controller layer before creating the domain instance.

Grails conditional nullable validation or custom validator with nullable option

I have a form to create a place. Depending of the country, the province (state, region) field is required or not.
When is not required, I want to be null, not empty string. I have code that makes all empty form fields, null:
def newparams = [:]
place = new Place()
params.each() { k, v ->
if (v instanceof String && place.hasProperty(k)) {
if (!v.trim().length()) {
newparams[k] = null
} else {
newparams[k] = v
}
}
}
place = new Place(newparams)
place.validate()
Now, in the place domain, I have a validator on the province:
province validator: {val, obj -> if (obj.country in obj.requiresRegionCountries() && !obj.province) return [province.required]}
With this rule, I always get "province can't be null" even if it is required or not.
I think this is because the nullable validator that is set default to false.
If I am adding nullable: true, then even if province is required, the custom validator is skipped and it is possible to save with empty province (I think that is because it gets instantiated with null)
Now, I need somehow my custom validator and also ability to specify the nullable in my validator, something like this:
province validator: {val, obj ->
if (obj.country in obj.requiresRegionCountries() && !obj.province) {
nullable: false
return [province.required] }
else {
nullable: true
}
}
How can I achieve this in Grails 2.0.3?
After lots of research and feedback I found out 2 solutions that are working. One is in controller. Do not add any validation in model and add them dynamically from controller:
class PlacesController {
def create() {
def place = new Place(params.address)
if (place.country in placesThatRequiresProvinceArray) {
place.constrains.province.nullable = false
} else {
place.constrains.province.nullable = true
}
}
The other solution is the one proposed by Tri in this thread, but put the custom validator before the nullable constraint (else the custom validator will not be called for null values):
static constraints = {
province (validator: {val, obj ->
if (obj.country == 'Canada' && !val)
return ['province.required']
}, nullable: true)
}
I can't tell with the code you've pasted but if your problem is that the default validation doesn't allow province to be null, have you tried explicitly allowing province to be null? You are allowed multiple validators for each field. So back in your original code, just specify the nullable validator as well:
province nullable: true, validator: {val, obj ->
if (obj != null && obj.country in obj.requiresRegionCountries() && !obj.province)
return [province.required]
}
EDIT:
In the custom validator, might also want to guard against the obj being null in the if condition.
EDIT2: Demo project showing the above validation working on grails 2.0.4
class Place {
String country
Province province
static constraints = {
province (nullable: true, validator: {val, obj ->
if (obj.country == 'Canada' && !val) return ['province.required']
})
}
}
Controller...
class MainController {
def index() {
def place = new Place(country: 'Canada')
if (!place.validate()) {
render "need province<br/>" + place.errors
} else {
render "cool"
}
So the idea is that I have a dummy controller where I can invoke the index action which is hardcoded to create a Place domain instance similar to your example. Notice I only defined the country string so I can key my logic on that for the custom validation. I didn't define the province when creating the Place instance so it should be null. Under that scenario, the response page will print the following...
Output snippet ...
need province
grails.validation.ValidationErrors: 1 .... does not pass custom validation]
If I remove the nullable: true constraint from Place, then the error is the null value as expected...
Output snippet ...
need province
grails.validation.ValidationErrors: 1 .... cannot be null]

Resources