0

This is the second time I'm using apache shiro in a project but the first time am salting the password.this time around i use apache shiro 1.2.0 . I'm using shiro in a web application using jsp, spring, JPA(spring-data-jpa) and using SHA256 for encryption then base64 before saving to database. I have a SaltedJPARealm, a Sha256CredentialMatcher which implements a HashedCredentialMatcher. this is how i do

creating a user in my controller

RandomNumberGenerator rng = new SecureRandomNumberGenerator();
ByteSource salt = rng.nextBytes(10);              
        String hashedPasswordBase64 = new Sha256Hash(signupForm.getPassword(),salt).toBase64();

userService.createUser(signupForm.getFullName(), signupForm.getEmail(), hashedPasswordBase64, salt.toBase64());

so supposed my password is password1234 and the generated salt is /ZFfGOcSxYhy+g== so in my database i have password: whb+0AihIGJ4n8QwULj1tR6qSwCrA+1BUvnoe4q4Cy4= the salt in the salt field in the database is the same.

In my configuration in spring is:

<!--....-->
 <bean id="saltedJPARealm" class="bla.bla.webapp.security.SaltedJPARealm">
    <constructor-arg  ref="credMatcher"/>
</bean>

    <bean id="credMatcher" class="bla.bla.webapp.security.Sha256CredentialMatcher">
        <property name="storedCredentialsHexEncoded" value="false" />
        <property name="hashAlgorithmName" value="SHA-256" />
        <!--<property name="hashIterations" value="1024" />-->
    </bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" depends-on="userRepository">
    <property name="realm" ref="saltedJPARealm" />
</bean>
<!--....-->

login user

 Subject currentUser = SecurityUtils.getSubject();
 if (!currentUser.isAuthenticated()) {
            UsernamePasswordToken token = new UsernamePasswordToken(loginForm.getEmail(), loginForm.getPassword(), loginForm.isRememberMe());
  SecurityUtils.getSubject().login(token);
        }

The SaltedJPARealm's doGetAuthenticationInfo(AuthenticationToken at) returns SaltedAuthenticationInfo after getting the user from the database :

ByteSource salt = ByteSource.Util.bytes(user.getSalt());           
return new SimpleAuthenticationInfo(user, user.getPassword().toCharArray(),salt,this.getName());

the doCredentialsMatch of Sha256CredentialMatcher looks like :

    Object tokenfromSubmition = hashProvidedCredentials(token.getCredentials(),((SaltedAuthenticationInfo)info).getCredentialsSalt(),0);
    Object passwordFromStorage =this.getCredentials(info);

    Boolean match = equals(tokenfromSubmition, passwordFromStorage);
    return match;

full code is available here on pastie the authentication fails with this. but when i change the code not to salt the password(when creating account) and return AuthenticationInfo as opposed to SaltedAuthenticationInfo. it works with the same class. am wondering what exactly am doing wrong?

black sensei
  • 6,528
  • 22
  • 109
  • 188
  • Is there a reason you're not using the PasswordMatcher and PasswordService? These automatically use securely randomly generated salts and perform password comparison directly. – Les Hazlewood Oct 16 '12 at 18:26
  • the `passwordService` use per default `sha-256` encryption and 50,000 iteration (i think so) and i haven't found any way of changing these default values.when tried it seems to be slow during debugging when generating the password. so i fall back to custom implementation. thanks – black sensei Oct 17 '12 at 06:45
  • I answered your question about `passwordService` usage below. I know it doesn't address your originally posted question, but I think you'll find it much easier/nicer to use. – Les Hazlewood Oct 17 '12 at 18:31

1 Answers1

1

The PasswordService is a POJO (with nested properties) and its nested properties can be configured just as well with Spring:

<bean id="passwordService" class="org.apache.shiro.authc.credential.DefaultPasswordService">
  <property name="hashService.hashAlgorithmName" value="SHA-512"/>
  <property name="hashService.hashIterations" value="500000"/>
</bean>

<bean id="myRealm" class="...">
  <property name="credentialsMatcher">
    <bean class="org.apache.shiro.authc.credential.PasswordMatcher">
      <property name="passwordService" ref="passwordService"/>
    </bean>
  </property>
</bean>

This allows the myRealm instance to use the PasswordService for credentials checking during a login attempt.

To use the PasswordService to encrypt passwords when the end user sets their password (i.e. during account registration or password reset), you can inject the PasswordService bean and then use it:

String encryptedPassword = passwordService.encryptPassword(signupForm.getPassword());

userService.createUser(signupForm.getFullName(), signupForm.getEmail(), encryptedPassword);

I think you'll find the Spring config and code usage much nicer/cleaner to use than the lower-level random number generators and HashService + Hash APIs.

HTH!

Les Hazlewood
  • 18,480
  • 13
  • 68
  • 76
  • Thanks for your response. with your suggestion is the Realm the same? : `protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken at) //..... return new SimpleAuthenticationInfo(user, user.getPassword().toCharArray(),this.getName()); }` – black sensei Oct 18 '12 at 00:14
  • @blacksensei P.S. This approach assumes you use the PasswordService to set the password in your data store first (as shown above in the 2nd code block). Then the stored value can be used to do a comparison during login. – Les Hazlewood Oct 18 '12 at 00:36
  • How do you get the PasswordService to begin with? Is that owned by the SecurityManager somehow? – Jess Bowers Mar 15 '14 at 13:09
  • 1
    @JessBowers as shown in the code example above, it is just instantiated manually (` – Les Hazlewood Mar 15 '14 at 20:44