In a previous post I explained why bCrypt is a good choice for hashing your passwords. In this post I will show were you can hash and check your passwords: in your handlers, in a service layer or in some entity model. When using cbsecurity I will show you why it fits best in your service layer or entity model.

But let’s start with some hashing and checking in a handler. Make sure bcrypt is installed by using commandbox and execute the command:

box install bcrypt

Let’s say you want to store your password in a db table. Bcrypt has two important methods for hashing and checking called hashPassword() and checkPassword() but you have to call them on a bcrypt instance, so you can inject bcrypt in a handler:

property name="bCrypt" inject="BCrypt@BCrypt";

or getting your instance directly by calling getInstance("BCrypt@BCrypt"). But you don’t have to do this, by installing the module some mixin helpers are created so you can just call bCryptHash() or bCryptCheck(). These handy functions will be available in all handlers, views, layouts or even interceptors. So let’s say we want to save a user in some handler it will look like this:

function saveUser( event, rc, prc ) {
  // do some password and user validations first
  // .....
  var params = { 
    userName: rc.userName,
    password: bCryptHash(rc.password)
  }
  queryExecute(
    sql = "Insert into users( userName, password ) 
      values( :userName, :passWord )",
    params = params
  )
  //relocate to user list
  relocate("users.index");
}

Checking for a valid login is slightly more complicated than in a table with simple hashes. Because the hash of a string is never the same you can’t retrieve a user with valid password in ONE statement. You have to retrieve the user first, including the hashed password, based on username and compare the stored password hash with the entered password candidate:

function login( event, rc, prc ) {
  var params = { 
    userName: rc.userName,
  }
  var q = queryExecute(
    sql = "select id,userName,password as hashedPassword from users
      where userName = :userName",
    params = params
  )
  // first check for existing user
  if ( !q.recordCount ) {
    // go somewhere else with an error message
  }
  // now check for correct password
  if ( bCryptCheck( rc.password, q.hashedPassword ) ) {
    relocate("someSecured.action")
  } else {
    //go somewhere else with an error message
  }
}

By using bCrypt in this way, you have to remember you always use bCryptHash() and bCryptCheck() when storing and retrieving users. It is a matter of style, but it might make more sense to move the hashing and checking to some model.

So what should we do when using cbsecurity? In a previous post I explained you only had to implement some interfaces on some UserService and UserObject. Just to remind you: A user object needs the following methods:

  • getId()
  • hasPermission()
  • isLoggedIn

The UserService has the following required methods:

  • isValidCredentials
  • retrieveUserByUserName
  • retrieveUserById

I don’t have to change a lot to make use of bcrypt. The isValidCredentials() method probably needs some work, and we need to store a hashed password. We have two possibilities for this: we can make the UserService a little bit smarter by injecting bcrypt there OR leave all intelligence is the User object itself. I opt for the latter, so we need a method to hash the password on the user object and a method to check if a password candidate matches the stored password.

We start with the UserService, where we only need to modify isValidCredentials(). The retrieveUserByUsername () method is already part of the interface requirements, so we can use it unmodified.

// UserService method
function isValidCredentials( required username, required password ){
  var oUser = retrieveUserByUsername(arguments.UserName);
  if (!IsNull( oUser )){
    return oUser.checkPassword( passwordCandidate=arguments.password );
  } else {
    return false;
  }
}

I need a new checkPassword method now on my user object. I also want to make sure each password I set on my user object will be hashed so I am going to create a password setter method.

// User model
component {
  property name = "id";
  property name = "userName";
  property name = "password";
  // DI
  property name = "bCrypt" inject = "BCrypt@BCrypt";

  this.constraints = {
    "password": { size : "8..50" }
  };
  
  function checkPassword( required string passwordCandidate ){
    return bcrypt.checkPassword( 
      arguments.passwordCandidate, 
      variables.Password 
    );
  }
  function setPassword( ){
    if ( arguments.value.len() <=50 ) {
      variables.password = bcrypt.hashPassword( arguments.value );
    } else {
      variables.password = value
    }
  }
}

My user object gets a bcrypt instance which will be injected by wirebox. I want to make sure my password property is always hashed. So if I set a new password it will automatically be hashed when using user.setPassword(someValue). But there is a small issue with this. When I retrieve my userInfo from the database and populate my user object I am probably also calling the password setter. Without additional precautions this would hash my already hashed db password value again, and its obvious we don’t want that! So if the password has been hashed already we don’t want to do it again. A hashed value is easy to recognize because the format looks like this:
$2a$12$8RQwfyiSHf.Ef.COeOFQKOdMLTqj/ARBuOJpb9Yc3T3ITJlRrOn32
The first 7 characters are quite predictable, so I could create some regex expression to detect this. On the other hand: end users could also create such a string, so I can’t trust such detection. But there is a solution which is a lot simpler: does it make sense to create a password which is 60 characters long? Our hash is exactly 60 characters, so as long as I restrict user input to something smaller I can easily distinguish between real hashes and passwords provided by user input. That’s what happens in our setter now. It only hashed the new password if the length is <50, and I put a maximum value in this.constraints which is always called when populating my object from user input. If I wanted to make it a bit more sophisticated I could check for length AND a regex.

Checking for a valid password in my user object is quite simple: we have a property password which is actually a hashed version of the password. We just compare the password candidate with this hashed value and return the result to my isValidCredentials method in the User service.

So using bCrypt is not that hard. But what if we want to update the password hashes for all users without asking them all to reset their passwords? This will be to topic for a future post, so stay tuned.