Page 1 of 1

Password Hashing in Broadleaf 4.0 (SHA-256)

Posted: Mon Jul 13, 2015 5:05 am
by rudy
Hi,

I was struggling with setting up Salted SHA-256 passwords for customers. With salt as emails.
I found out some stuff to make it work. Thought of sharing so it might help others.

1. CHANGES IN applicationContext-security.xml

a. Setup salt-source: i.e. which property should be used as salt. I wanted it to be username [which is same as email by default]. You are free to use your own customer property.
NOTE: If you want your own salt [same for all users, you can skip this step]

Code: Select all

<bean id="blSaltSource" class="org.springframework.security.authentication.dao.ReflectionSaltSource">
        <property name="userPropertyToUse" value="username" />
</bean>


b. Define a bean for your password encoder: I used SHA-256 algorithm.

Code: Select all

<bean id="mdPasswordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
       <constructor-arg value="256"/>
</bean>


c. Configure Authentication Manager to use your encoder and salt: Third line in the below code refers to the bean defined in step (b). Fourth line in the below code refers to the bean being used for salting.

Code: Select all

<sec:authentication-manager alias="blAuthenticationManager">
        <sec:authentication-provider user-service-ref="blUserDetailsService">
           <sec:password-encoder hash="sha-256" ref="mdPasswordEncoder">
                 <sec:salt-source ref="blSaltSource" />
           </sec:password-encoder>
        </sec:authentication-provider>
</sec:authentication-manager>


If you want a common salt for all users, you can use the below code:-

Code: Select all

<sec:authentication-manager alias="blAuthenticationManager">
        <sec:authentication-provider user-service-ref="blUserDetailsService">
           <sec:password-encoder hash="sha-256" ref="mdPasswordEncoder">
                 <sec:salt-source system-wide="--your-salt-string--" />
           </sec:password-encoder>
        </sec:authentication-provider>
</sec:authentication-manager>


2. CREATE A UTILITY CLASS FOR PROVIDING ShaPasswordEncoder Object: This will be used for hashing the password entered by the user on front-end for validation.

Code: Select all

public class CommonUtils {
         private static final ShaPasswordEncoder encoder = new ShaPasswordEncoder(256);

         public static ShaPasswordEncoder getCustomerPasswordEncoder() {
            return encoder;
         }
}


3. OVERRIDE CustomerServiceImpl.registerCustomer() in CORE MODULE: This class uses the above utility class and encodes the password before registration.

Code: Select all

public class MDCustomerServiceImpl extends CustomerServiceImpl {
      @Override
      public Customer registerCustomer(Customer customer, String password, String passwordConfirm) {
         ShaPasswordEncoder encoder = CommonUtils.getCustomerPasswordEncoder();
         password = encoder.encodePassword(password, customer.getUsername());
         passwordConfirm = encoder.encodePassword(passwordConfirm, customer.getUsername());
         return super.registerCustomer(customer, password, passwordConfirm);
      }
   }


In applicationContext.xml, register this new class with the original bean id [which belonged to CustomerServiceImpl]

Code: Select all

<bean id="blCustomerService" class="<path_to_above_class>.MDCustomerServiceImpl" />


4. RegisterController CUSTOMIZATION: This is required because of a tricky bug in broadleaf 4.0
The bug is, when a user registers, the password is set as the hashed one. [WHICH IS OK]
NEXT, the login service is called. During the login, the password is picked up from the database [which is already hashed].
As a part of authentication, this is hashed again and there is a password mismatch.
Ideally, under normal scenario, during login the user will enter a plain password and will be hashed once to validate. In this case, the hashed password is picked from database and is re-hashed, which fails the authentication.

I copied the code from BroadleafRegisterController's processRegister method into RegisterController's processRegister method.

a. At the first line of processRegister method add the below code

Code: Select all

String unencodedPassword = registerCustomerForm.getPassword(); //store non-hashed password in a variable


b. Replace the following code

Code: Select all

loginService.loginCustomer(registerCustomerForm.getCustomer());


BY

Code: Select all

//#### Store hashed password in a variable
String codedPassword = registerCustomerForm.getCustomer().getPassword();

//#### SET UNENCODED PASSWORD AS PLAIN ONE FROM ABOVE
newCustomer.setUnencodedPassword(unencodedPassword);

//#### REPLACE WITH "newCustomer" for loginService.
loginService.loginCustomer(newCustomer);

//AFTER LOGIN RE-SET THE HASHED PASSWORD - Because loginService resets it to unencodedPassword.
newCustomer.setUnencodedPassword(codedPassword);
newCustomer.setPassword(codedPassword);
customerService.saveCustomer(newCustomer);


Now, for all the operations, the password will be hashed.
NOTE: This is the process for hashing passwords by SHA-256 algorithm, which is salted by the user's email-id on user-facing website and NOT admin panel.
____________________________________________________________________________

HOW TO RESET PASSWORD IF FORGOTTEN: In case you lose your password and you need to quickly reset it from database, you can use the following process to do so.

1. Choose a password in clear text: For example, you want to set your password as Magic2015
2. Next, choose a salt: It can be a user-property or a simple text value. For e.g. we want to use the salt as abc@def.com
3. Now, place your string in the format: <password_in_clear_text>{<your_salt>}. In our case, the string will be Magic2015{abc@def.com}
4. Use any online utility to hash this string using SHA-256 algorithm. The hashed string of above string will be 9f9c9b9682bd06a01cc47fed8929d70a4751bd011ccb36df82ecac68b65bd4a3
5. Insert this into database.

Code: Select all

insert into BLC_CUSTOMER
set password = '9f9c9b9682bd06a01cc47fed8929d70a4751bd011ccb36df82ecac68b65bd4a3'
where email = 'abc@def.com';

6. Now, you can login using credentials abc@def.com as username and Magic2015 as password

Re: Password Hashing in Broadleaf 4.0 (SHA-256)

Posted: Mon Jul 27, 2015 4:40 am
by phillipuniverse
Thanks for the post!

Just a quick note, we now officially recommend using BCrypt which uses a randomly generated salt every time the password is generated. This is the most secure mode of password encryption generation.

Re: Password Hashing in Broadleaf 4.0 (SHA-256)

Posted: Fri Jul 31, 2015 11:43 am
by rudy
Thanks Phillip.
Will definitely try that.