DynamoDBMappingException: no RANGE key value present

Viewed 3293

I am new to NoSQL and Amazon Dynamo DB. I am trying to retreive a user by username first from a DynamoDB UserMaster table.

I have a table UserMaster with 5 attributes(username, correct-hash, email, lastLogin, role), each of type String and I have a corresponding UsermasterBean mapped to the table UserMaster. UserMaster table's Partition Key(Hashkey) is username and Sort key(Range Key) is correct-hash

UsermasterBean

    @DynamoDBTable(tableName = "UserMaster")
    public class UsermasterBean {
    
    private String username;
    private String correctHash;
    private String email;
    private String lastLogin;
    private String role;
    
    @DynamoDBHashKey(attributeName = "username")
    @DynamoDBAttribute(attributeName = "username")
    public String getUsername() {
        return username;
    }
    
    @DynamoDBRangeKey(attributeName = "correct-hash")
    @DynamoDBAttribute(attributeName = "correct-hash")
    public String getCorrectHash() {
        return correctHash;
    }
    
    @DynamoDBAttribute(attributeName = "email")
    public String getEmail() {
        return email;
    }
    
    @DynamoDBAttribute(attributeName = "last-login")
    public String getLastLogin() {
        return lastLogin;
    }
    
    @DynamoDBAttribute(attributeName = "role")
    public String getRole() {
        return role;
    }
    
    public void setUsername(String username) {
        this.username = username;
    }
    ....
    ....
   }

Retrieve data from UI:

UsermasterBean usermasterBean = new UsermasterBean();
UsermasterDao usermasterDao = new UsermasterDao();

usermasterBean.setUsername(username.getValue()); // Get the username from UI form
final String inputtedPassword = password.getValue(); // Get the password from UI form

UsermasterBean retrievedUserBean = usermasterDao.findByUsernameAndPassword(usermasterBean,inputtedPassword);

Validate User:

public UsermasterBean findByUsernameAndPassword(final UsermasterBean usermasterBean, final String inputtedPassword)
            throws IOException {
        AmazonDynamoDBClientHandler amazonDynamoDBClientHandler = AmazonDynamoDBClientHandler.getNewInstance();
        UsermasterBean retrievedUser;
        try {
            AmazonDynamoDB amazonDynamoDB = amazonDynamoDBClientHandler.createNewClient();
            DynamoDBMapper dynamoDBMapper = new DynamoDBMapper(amazonDynamoDB);
            retrievedUser = dynamoDBMapper.load(usermasterBean.getClass(), usermasterBean.getUsername());
            System.out.println("RETRIEVED CORRECT-HASH FROM DATABASE: " + retrievedUser.getCorrectHash()); // Check if hash retrieved is correct for this user.

            // PasswordUtilityManager.verifyPassword(inputtedPassword,retrievedUser.getCorrectHash());
        } catch (IOException ioException) {
            throw ioException;
        } finally {
            amazonDynamoDBClientHandler.shutdownClient();
        }
        return retrievedUser;
}

Problem:

retrievedUser = dynamoDBMapper.load(usermasterBean.getClass(), usermasterBean.getUsername()); throws com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException

I am expecting retrievedUser.getCorrectHash() should display the hashed password stored in database as a String so that I can verify if the inputted password creates the same hash as retrieved from the database.

2 Answers

This exception is being throw because the DynamoDBMapper is expecting the range key to be passed in too (as your DynamoDB table contains a range key of correct-hash).

The correct function call should be as below

retrievedUser = dynamoDBMapper.load(usermasterBean.getClass(), usermasterBean.getUsername(), usermasterBean.getCorrectHash());

As this is presumably the hash for your users password, you can specify a hashed copy of the password provided by the user. If this returns no results in DynamoDB you can assume that either their username or password is incorrect.

As per your data model, there can be more than one entry in the UserMaster table for a single user (username) which is not your intention. (Why would a user have two hashed passwords?)

Do not model correctHash as a range key. If you do, DynamoDB mandates you to provide both the hash and range key when calling load (else you have to query).

See: DynamoDBMapper load vs query

Related