Bcrypt generates different hashes for the same input? - grails

I just added a registration functionality to my new grails project. For testing it, I registered by giving an email and a password. I am using bcrypt algorithm for hashing the password before saving it to the database.
However when I try to login with the same email and password that I gave while registering, login fails. I debugged the application and found out that the hash that is generated for the same password is different when I try to compare with the already hashed one from database and hence the login is failing (Registration.findByEmailAndPassword(params.email,hashPassd) in LoginController.groovy returns null).
Here's my domain class Registration.groovy:
class Registration {
transient springSecurityService
String fullName
String password
String email
static constraints = {
fullName(blank:false)
password(blank:false, password:true)
email(blank:false, email:true, unique:true)
}
def beforeInsert = {
encodePassword()
}
protected void encodePassword() {
password = springSecurityService.encodePassword(password)
}
}
Here's my LoginController.groovy:
class LoginController {
/**
* Dependency injection for the springSecurityService.
*/
def springSecurityService
def index = {
if (springSecurityService.isLoggedIn()) {
render(view: "../homepage")
}
else {
render(view: "../index")
}
}
/**
* Show the login page.
*/
def handleLogin = {
if (springSecurityService.isLoggedIn()) {
render(view: "../homepage")
return
}
def hashPassd = springSecurityService.encodePassword(params.password)
// Find the username
def user = Registration.findByEmailAndPassword(params.email,hashPassd)
if (!user) {
flash.message = "User not found for email: ${params.email}"
render(view: "../index")
return
} else {
session.user = user
render(view: "../homepage")
}
}
}
Here's a snippet from my Config.groovy telling grails to use bcrypt algorithm to hash passwords and the number of rounds of keying:
grails.plugins.springsecurity.password.algorithm = 'bcrypt'
grails.plugins.springsecurity.password.bcrypt.logrounds = 16

Jan is correct - bcrypt by design doesn't generate the same hash for each input string. But there's a way to check that a hashed password is valid, and it's incorporated into the associated password encoder. So add a dependency injection for the passwordEncoder bean in your controller (def passwordEncoder) and change the lookup to
def handleLogin = {
if (springSecurityService.isLoggedIn()) {
render(view: "../homepage")
return
}
def user = Registration.findByEmail(params.email)
if (user && !passwordEncoder.isPasswordValid(user.password, params.password, null)) {
user = null
}
if (!user) {
flash.message = "User not found for email: ${params.email}"
render(view: "../index")
return
}
session.user = user
render(view: "../homepage")
}
Note that you don't encode the password for the isPasswordValid call - pass in the cleartext submitted password.
Also - completely unrelated - it's a bad idea to store the user in the session. The auth principal is readily available and stores the user id to make it easy to reload the user as needed (e.g. User.get(springSecurityService.principal.id). Storing disconnected potentially large Hibernate objects works great in dev mode when you're the only user of your server, but can be a significant waste of memory and forces you to work around the objects being disconnected (e.g. having to use merge, etc.).

A BCrypt hash includes salt and as a result this algorithm returns different hashes for the same input. Allow me to demonstrate it in Ruby.
> require 'bcrypt'
> p = BCrypt::Password.create "foobar"
=> "$2a$10$DopJPvHidYqWVKq.Sdcy5eTF82MvG1btPO.81NUtb/4XjiZa7ctQS"
> r = BCrypt::Password.create "foobar"
=> "$2a$10$FTHN0Dechb/IiQuyeEwxaOCSdBss1KcC5fBKDKsj85adOYTLOPQf6"
> p == "foobar"
=> true
> r == "foobar"
=> true
Consequently, BCrypt cannot be used for finding users in the way presented in your example. An alternative unambiguous field should be used instead, e.g. user's name or e-mail address.

Related

Redirection based on user role upon login

I am trying to redirect user to page based on their role. Below is the login code in a controller:
[HttpPost]
public ActionResult Login(User model)
{
// Lets first check if the Model is valid or not
if (ModelState.IsValid)
{
using (AuthenticationAppEntities1 entities = new AuthenticationAppEntities1())
{
string username = model.Username;
string password = model.Password;
// Now if our password was enctypted or hashed we would have done the
// same operation on the user entered password here, But for now
// since the password is in plain text lets just authenticate directly
bool userValid = entities.Users.Any(user => user.Username == username && user.Password == password);
// User found in the databases
if (userValid)
{
FormsAuthentication.SetAuthCookie(username, false);
if (Roles.IsUserInRole(model.Roles, "admin"))
{
return RedirectToAction("Home", "Authentication");
}
else
{
return RedirectToAction("HomeAdmin", "Authentication");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
As you can see in the code, I redirect users based on their roles, using a if. However, model.Roles contain a null value as the controller is getting only the username and password from the login page. Any simple idea how I get the role of the authenticated user? I thought of searching it through the username, but am not sure if this is the best solution.
You can get the User's roles and then compare it with 'admin' and then redirect accordingly.
Honestly, I'm not even sure how you're getting that to run in the first place. The method signature for Roles.IsUserInRole is:
Roles.IsUserInRole(string username, string role);
Passing model.Roles is neither a string, nor a username, if it was a string.

Grails, Spring Security core, change user authority

I generated Role, User and UserRole class using the Spring Security Core Plugin. I want to set the users role directly in the user-creation-process. I added a "Role" field in User but don't know how and where I should set the entry in UserRole.
Is there anything else to implement like reauthentication to update a users role afterwards?
You should delete link to Role from User and use next code, after creating User and Role:
UserRole.create(user,role,true)
Where user your created user, role your created role, and true is indicated that userRole should create with flush:true
Good luck!
Yes its works!!! thanks, this is my code in a Service:
public String updateUser(long userId, String username, String password, long roleId){
Object[] args = [messageSource.getMessage('spring.security.ui.login.username',null, null),username];
def user = User.get(userId);
def userTemp = User.findAllByUsername(username);
if(userTemp.isEmpty() || userTemp.get(0).id == userId){
def role = Role.get(roleId);
user.username = username;
user.roleId = roleId;
if (password != ''){
user.password = password;
}
user.save(flush:true);
UserRole.create(user,role,true);
return "<span class='successMessage'><strong>" + messageSource.getMessage("message.common.record.saved.successfully", args, null) + "</strong></span>";
} else {
return "<span class='warnMessage'><strong>" + messageSource.getMessage("message.common.register.exist", args,null) + "</strong></span>";
}
}

Grails - controller access variables from gsp

I have the following grails controller
class UserController {
def userService
def roleService
def index() {
def roles = roleService.listRoles()
[roles: roles]
}
def userDetails() {
[user: userService.getUser(params.id), role:params.role]
}
def updateUser() {
def user = userService.getUser(params.id)
if (!(params.username)) {
flash.message = "You have to enter a username!"
redirect(action: "userDetails")
}
else {
user.username = params.username
user.person.title = params.title
user.person.given = params.given
user.person.middle = params.middle
user.person.family = params.family
userService.updateUser(user)
redirect(action: "index")
}
}
}
Starting with index() the user gets a list of all roles and users currently available. The user may then select one particular user being linked to the userDetails()-action. There I retrieve the information about the id of the user with params.id and the user's role name with params.role.
In userDetails.gsp the user is able to update some of the user's properties. However, if he doesn't enter a username, he should be redirected back to the userDetails.gsp. (I know that I could check this with the required-attribute within the gsp - it's just to understand the functionality)
And here is where I get stuck - when using the userDetails()-action, two parameters are passed to the gsp. But now when committing the redirect I don't know how to access this information. As a result, rendering the userDetails.gsp results in an error as the required information concerning the user and the role are not available.
Any help would be highly appreciated!
You should change the form (presumably) that submits to the updateUser action, so that it also sends in the role. Then if the data submitted is invalid, you simply include these parameters when redirecting back to the userDetails action.
def updateUser() {
def user = userService.getUser(params.id)
// I'm not sure if this the right way to get a Role from the role parameter
// but presumably you can figure that out yourself
def role = roleService.getRole(params.role)
if (!(params.username)) {
flash.message = "You have to enter a username!"
redirect action: "userDetails", params: [id: params.id, role: params.role]
}
}
As an aside, the way you're manually binding each parameter to the user object is unnecessarily verbose. Grails' databinding can do this automatically.

Grails 2.1.1 and Spring Security Core plugin

I've been noticing that a lot of the tutorials I'm following use this:
def springSecurityService
and since I want to get records only by current logged in user I use:
def user = params.id ? User.findByUserId(params.id) : User.get(springSecurityService.principal.id)
and also in my Bootstrap I want to create a username and password, so for instance
def user = new User(
username: username,
password: springSecurityService.encodePassword("tops3kr17"),
enabled: true)
However I noticed that the password is not being created, and Spring Source Tools does not find the method .principal.id or .encodePassword (they stay underlined in STS) and wants to use SpringSecurityService with a capital S when hitting CTL+SPACE (and doesn't complete .principal.id or .encodePassword).
So i'm a little lost because it seems that the tutorials are out of date
So how can I do what I described with what the current supported methods are? Or am I missing something really simple? : )
class BootStrap {
def springSecurityService
def init = { servletContext ->
def demo = [
'jack' : [ fullName: 'Jack Demo Salesman'],
'jill' : [ fullName: 'Jill Demo Saleswoman']]
def now = new Date()
def random = new Random()
def userRole = SecRole.findByAuthority("ROLE_SALES") ?: new SecRole(authority: "ROLE_SALES").save()
def adminRole = SecRole.findByAuthority("ROLE_ADMIN") ?: new SecRole(authority: "ROLE_ADMIN").save()
def users = User.list() ?: []
if (!users) {
demo.each { username, password, userAttrs ->
def user = new User(
username: username,
password: springSecurityService.encodePassword('secret'),
enabled: true)
if (user.validate()) {
println "DEBUG: Creating user ${username}..."
println "DEBUG: and their password is ${password}"
user.save(flush:true)
SecUserSecRole.create user, userRole
users << user
}
else {
println("\n\n\nError in account bootstrap for ${username}!\n\n\n")
user.errors.each {err ->
println err
}
}
Using the injected instance of SpringSecurityService is the right approach.
def springSecurityService
def foo() {
springSecurityService.principal
springSecurityService.encodePassword('fdsfads')
....
}
If the IDE isn't recognizing it, there is an issue with your IDE.

Grails spring-security - Can I intercept before success action to check required password change?

Upon creating new users in my system, I am sending them a temporary password via email and setting an property of changePasswordNextLogin=true. When they come to log in for the first time, I would like to intercept the flow upon a successful login, check for this this value, and if it is true, redirect them to a change password action. Once the password change has been completed, ideally I would like to send them to their intended destination.
I have been pouring through the default settings and am not seeing - or more likely not interpreting properly - any way to make that happen. It seems that almost every time that I try to cobble some solution together in Grails, I find that someone has already made a much more elegant approach to do the same thing. Is there any functionality built in that would allow this?
If not, I would really appreciate any suggestions on the best approach to make it so.
There is some support for this directly with Spring Security and the grails plugin, but you also have to do some work yourself :)
The domain class that was created when you installed grails-spring-security plugin (and ran the S2Quickstart script) has a property on it named 'passwordExpired'. Set this to true when you create your new user domain instance.
Once that user logs in for the first time, the Spring Security core libs will throw an exception which you can catch in your login controller's authfail closure, re-directing them to the change password form (that you need to supply yourself).
Here's an example from one of my apps, a skeleton version of this closure should already be included in your login controller:
/**
* Callback after a failed login.
*/
def authfail = {
def msg = ''
def username =
session[UsernamePasswordAuthenticationFilter.SPRING_SECURITY_LAST_USERNAME_KEY]
def exception = session[WebAttributes.AUTHENTICATION_EXCEPTION]
if (exception) {
if (exception instanceof CredentialsExpiredException) {
msg = g.message(code: "springSecurity.errors.login.passwordExpired")
if (!springSecurityService.isAjax(request))
redirect (action:'changePassword') // <-- see below
}
// other failure checks omitted
}
if (springSecurityService.isAjax(request)) {
render([error: msg] as JSON)
}
else {
flash.message = msg
redirect controller: 'login', action:'auth', params: params
}
}
/**
* render the change pwd form
*/
def changePassword = {
[username: session[UsernamePasswordAuthenticationFilter.SPRING_SECURITY_LAST_USERNAME_KEY] ?: springSecurityService.authentication.name]
}
From your 'changePasssword' view, submit the form back to another controller closure (I call mine 'updatePassword' that checks whatever constraints you want for passwords and either saves the updated password on the domain object or not..
def updatePassword = {
String username = session[UsernamePasswordAuthenticationFilter.SPRING_SECURITY_LAST_USERNAME_KEY] ?: springSecurityService.authentication.name
if (!username) {
flash.message = 'Sorry, an error has occurred'
redirect controller: 'login', action:'auth'
return
}
String password = params.password
String newPassword = params.password_new
String newPassword2 = params.password_new_2
if (!password || !newPassword || !newPassword2 || newPassword != newPassword2) {
flash.message = 'Please enter your current password and a new password'
render view: 'changePassword', model: [username: username]
return
}
SecUser user = SecUser.findByUsername(username)
if (!passwordEncoder.isPasswordValid(user.password, password, null /*salt*/)) {
flash.message = 'Current password is incorrect'
render view: 'changePassword', model: [username: username]
return
}
if (passwordEncoder.isPasswordValid(user.password, newPassword, null /*salt*/)) {
flash.message = 'Please choose a different password from your current one'
render view: 'changePassword', model: [username: username]
return
}
if (!newPassword.matches(PASSWORD_REGEX)) {
flash.message = 'Password does not meet minimum requirements'
render view: 'changePassword', model: [username: username]
return
}
// success if we reach here!
user.password = springSecurityService.encodePassword(newPassword)
user.passwordExpired = false
user.save()
flash.message = 'Password changed successfully' + (springSecurityService.loggedIn ? '' : ', you can now login')
redirect uri: '/'
}
If you are using Spring Secuirty 3.0 and later, You can refer to the spring security plugin documentation 11.3 Account Locking and Forcing Password Change.
Remember that you should set
grails.plugin.springsecurity.apf.storeLastUsername=true in Config.groovy.

Resources