Grails 3 Spring Security UI Forgotten Password blank URL & user - grails

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 = "..."

Related

Grails BootStrap: No signature of method: *.addTo* applicable

I have two domain classes: User
class User {
String username
String password
String email
Date dateCreated
Date lastUpdated
// static belongsTo = [profile: Profile]
static constraints = {
username size: 3..20, unique: true, nullable: false, validator: { _username ->
_username.toLowerCase() == _username
}
password size: 6..100, nullable: false, validator: { _password, user ->
_password != user.username
}
email email: true, blank: false
// profile nullable: true
}
}
and Profile:
class Profile {
String firstName
String middleName
String lastName
byte[] photo
Date dateCreated
Date lastUpdated
static belongsTo = [User]
static constraints = {
firstName blank: false
middleName nullable: true
lastName blank: false
photo nullable: true, maxSize: 2 * 1024**2
}
}
A profile can belong to only one user and a user can have (or belong to?) only one profile. When I try to create the objects in BootStrap.groovy in the current setup I get an error saying that the addTo() method does not exist. I don't really know what I am doing wrong. This is how I am creating them in BootStrap.groovy:
User arun = new User(username: 'arun', password: 'password', email: 'arun#email.com').save(failOnError: true)
Profile arunProfile = new Profile(firstName: 'Arun', lastName: 'Allamsetty').addToUser(arun).save(failOnError: true)
Can someone please point out the mistake(s). I am sure it's silly.
A strict bi-directional one-one relationship is required as you have requested for:
A profile can belong to only one user and a user can have (or belong to?) only one profile
Three modifications are mainly required in domain classes:
//User.groovy
static hasOne = [profile: Profile]
static constraints = {
profile unique: true
}
//Profile.groovy
User user
Above is a bi-directianl one-one relationship. You do not need addTo* anymore while creating each of them.
Profile arunProfile = new Profile(firstName: 'Arun', lastName: 'Allamsetty')
User arun = new User(username: 'arun', password: 'password',
email: 'arun#email.com',
profile: arunProfile).save()

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.

Email field in user class and spring security ui plugin

I've got a problem with spring security ui plugin. I'm trying to add an email field to my SecUser class (which stores information about users). However there is no field "email" in Spring Security Management Console generated with s2ui-override. On the other hand, due to documentation this is avaible(link):
By default only the standard fields (username, enabled, accountExpired, accountLocked, and passwordExpired) are available but this is customizable with the grails s2ui-override script - see the section on configuration.
I try to use s2ui overide scripts but with no effect.
I think this is somethink simple but after hours I can't find solution myself. So if anyone know how to do this - please tell me ;)
At the and my user class:
class SecUser {
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
email blank: false, email:true
}
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)
}
#Override
public String toString(){
return "User - "+username;
}
}
You can watch the source code from user/edit view:
<table>
<tbody>
<s2ui:textFieldRow name='username' labelCode='user.username.label' bean="${user}"
labelCodeDefault='Username' value="${user?.username}"/>
<s2ui:passwordFieldRow name='password' labelCode='user.password.label' bean="${user}"
labelCodeDefault='Password' value="${user?.password}"/>
<s2ui:checkboxRow name='enabled' labelCode='user.enabled.label' bean="${user}"
labelCodeDefault='Enabled' value="${user?.enabled}"/>
<s2ui:checkboxRow name='accountExpired' labelCode='user.accountExpired.label' bean="${user}"
labelCodeDefault='Account Expired' value="${user?.accountExpired}"/>
<s2ui:checkboxRow name='accountLocked' labelCode='user.accountLocked.label' bean="${user}"
labelCodeDefault='Account Locked' value="${user?.accountLocked}"/>
<s2ui:checkboxRow name='passwordExpired' labelCode='user.passwordExpired.label' bean="${user}"
labelCodeDefault='Password Expired' value="${user?.passwordExpired}"/>
</tbody>
</table>
There are not email field. You should to copy the edit.gsp and create.gsp files from source to grails-app/views/user/ and edit it pasting this code after username field:
<s2ui:textFieldRow name='email' labelCode='user.email.label' bean="${user}"
labelCodeDefault='email' value="${user?.email}"/>
You must to create a spring-security-core-local.properties in grails-app/i18n/ path and to write the new property
user.email.label=Email
And of course, you should to create the property email in the correct domain class.

Resources