springSecurityService how to NOT store passwords in cleartext? - grails

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.

Related

grails 3 spring security User domain id field synthetic

I am using grails 3.2.9 with spring-security-core plugin 3.1.2.
I've run the s2-quickstart script to create User, Role, and UserRole domain classes. I've found that the id field in the User and Role domains is being considered synthetic. For instance, if I run the following bit of code the id field is not shown:
def u = User.class.declaredFields.findAll {!it.synthetic}
u.each {
println it
}
Here is my User class:
#GrailsCompileStatic
#EqualsAndHashCode(includes='username')
#ToString(includes='username', includeNames=true, includePackage=false)
class User extends BaseDomain implements Serializable {
private static final long serialVersionUID = 1
String username
String password
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired
Date lastLogin
Set<Role> getAuthorities() {
(UserRole.findAllByUser(this) as List<UserRole>)*.role as Set<Role>
}
static constraints = {
password blank: false, password: true
username blank: false, unique: true
}
static mapping = {
id generator: 'identity', column: 'user_id', sqlType: 'bigint(20) unsigned'
password column: '`password`'
lastLogin sqlType: 'timestamp'
}
}
This is not happening with my other domain classes, and the first problem I see this causing is with the exa-datatables plugin (2.0.1). The plugin uses similar code to find the fields of a domain, so when requesting the id field to be displayed by the plugin it fails with an unknown column error.
I found this was being caused because I was extending a class (BaseDomain in the example), and I did not mark the BaseDomain as abstract. As soon as I qualified BaseDomain as abstract, everything started working as expected.
abstract class BaseDomain {...

Grails 3 Spring Security UI Forgotten Password blank URL & user

I have customised grails.plugin.springsecurity.userLookup.usernamePropertyName = "email" but the default rendering behaviour for the email body will fail with:
No such property: username for class
Therefore I customised emailBody in my application.groovy:
grails.plugin.springsecurity.ui.forgotPassword.emailBody = "Dear ${user.email} , Please follow <a href='${url}'>this link</a> to reset your password. This link will expire shortly."
because according to the docs:
The emailBody property should be a GString and will have the User domain class instance in scope in the user variable, and the generated url to click to reset the password in the url variable.
However, the params map that contains the properties in my MailStrategy is empty for the user.email and url values:
[to:blah#blah.com,
from:no-reply#blah.com, subject:Reset your password for your account,
html:Dear [:], Please follow <a href='[:']>this link</a> to reset your password. This link will expire shortly.]
Notice the [:] and [:] for the user.email and url values.
The spring-security plugin is configured with these values in application.groovy:
grails.plugin.springsecurity.userLookup.userDomainClassName = 'blah.Account'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'blah.AccountRole'
grails.plugin.springsecurity.authority.className = 'blah.Role'
grails.plugin.springsecurity.requestMap.className = 'blah.Requestmap'
grails.plugin.springsecurity.securityConfigType = 'Annotation'
The Account class is defined as:
String email
String password
Date emailVerified = null
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired
Set<Role> getAuthorities() {
AccountRole.findAllByAccount(this)*.role
}
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
protected void encodePassword() {
password = springSecurityService?.passwordEncoder ? springSecurityService.encodePassword(password) : password
}
static transients = ['springSecurityService']
static constraints = {
password blank: false, password: true
email blank: false, unique: true
emailVerified nullable: true
}
static mapping = {
password column: '`password`'
}
How can I have the username and more importantly the URL rendered for me so I can send the forgotten password email?
GString should start from " not from '
so instead of grails.plugin.springsecurity.ui.forgotPassword.emailBody = '...'
you should use: grails.plugin.springsecurity.ui.forgotPassword.emailBody = "..."

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 transient properties not picked up on object creation

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.

Resources