Search code examples
javaapacheauthenticationshiro

Authentication trouble with Apache Shiro


I'm a beginner with Apache Shiro. I've been following the docs and lots of other tutorials, blogs etc. but I just can't get the authentication to work. When I attempt to login with a valid username and password, I always get an InvalidCredentialsException thrown. I'm using DynamoDB as a custom realm for storing user credentials, but I really don't think that matters. It's obviously the way that I'm storing and/or doing the credential matching that's not correct. Here's my setup:

Shiro.ini:

[main]
myRealm = com.enki.closing.users.DynamoDBRealm

credentialsMatcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher
credentialsMatcher.storedCredentialsHexEncoded = false
credentialsMatcher.hashIterations = 1024

myRealm.credentialsMatcher = $credentialsMatcher

Create user account:

String password = ...
ByteSource passwordSalt = new SecureRandomNumberGenerator().nextBytes();
String hashedPasswordBase64 = new Sha256Hash(password, passwordSalt, 1024).toBase64();

// store the hashedPassword and salt in DynamoDB...
// I've tried storing the salt with and without base64 encoding.

The password and salt are stored fine in DynamoDB, the values look alright. Here's the custom realm for authentication:

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    UsernamePasswordToken userPass = (UsernamePasswordToken) token;
    String username = userPass.getUsername();
    ...
    // pull the matching password and salt out of DynamoDB, no problems...
    ByteSource passwordSalt = ByteSource.Util.bytes( storedPasswordSalt );
    return new SimpleAuthenticationInfo(username, passwordHash, passwordSalt, getName());
}

This is all pretty much what the docs are telling me to do, but there's something not right. When I try the login, it get InvalidCredentialsException.


Solution

  • I figured out how to get it working. I had to change this (in my custom realm impl):

    ByteSource passwordSalt = ByteSource.Util.bytes( storedPasswordSalt );
    

    to this:

    ByteSource passwordSalt = ByteSource.Util.bytes( 
                                      Base64.decode( storedPasswordSalt) );