0

i have a problem with hashing a password.

The following Code tries to login on a server via a jsf-Page, but when the Method login is called the hash of the password is changed on the underlying database. I'm using a postgresql database in version 9.2 I cant figure out why. Anyone could help?

The jsf-Page:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"`   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:c="http://java.sun.com/jsp/jstl/core">

<h:head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF8" />
</h:head>
<body>
    <h1>Login</h1>
    <div id="container">
        <h:form id="create">
            <h:commandButton id="create" value="create"
                action="#{login.create()}">
            </h:commandButton>
        </h:form>
        <h:form id="loginForm">
            <h:panelGrid columns="2">
                <h:outputLabel>Username:</h:outputLabel>
                <h:inputText value="#{username}" />
            </h:panelGrid>
            <h:panelGrid columns="2">
                <h:outputLabel>Password:</h:outputLabel>
                <h:inputText value="#{password}" />
            </h:panelGrid>
            <h:commandButton id="login" value="Login"
                action="#{loginController.login(username, password)}">
            </h:commandButton>
        </h:form>
        <h:form id="response">
            <h:panelGrid columns="2">
                <h:outputLabel>Response:</h:outputLabel>
                <h:outputLabel value="#{login.username}" />
            </h:panelGrid>
        </h:form>

    </div>
</body>
</html>

The LoginController:

import java.io.Serializable;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.annotation.ManagedBean;
import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;

import de.lps.entities.User;
import de.lps.server.interfaces.ILPSServerUser;
import de.lps.server.server.LPSServer;

@Named("loginController")
@SessionScoped
public class LoginController implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    @EJB(beanInterface=ILPSServerUser.class)
    private ILPSServerUser server;

    private Logger logger;

    String username;

    public void login(String username, String password) {
        this.logger = Logger.getLogger("LoginController");

        this.logger.log(Level.INFO, server.toString());

        if (username != "" && password != "") {
            User user = server.login(username, password);
            if (user == null) {
                this.logger.log(Level.INFO, "user == null");
                this.username = "User N.A";
            } else {
                this.logger.log(Level.INFO, "got user");
                this.username = user.getUserName();
            }

        } else {
            this.logger.log(Level.INFO, "No credentials were given");
            this.username = "No credentials were given";
        }

    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getUsername() {
        return this.username;
    }

}

The called EJB:

package de.lps.server.server;

import java.util.logging.Level;
import java.util.logging.Logger;

import javax.ejb.Stateful;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import de.lps.entities.User;
import de.lps.server.interfaces.ILPSServerUser;
import de.lps.utils.security.PasswordHash;

/**
 * Session Bean implementation class LPSServer
 */
@Stateful
public class LPSServer implements ILPSServerUser {
    private User loggedUser;
    @PersistenceContext
    EntityManager em;

    Logger logger = Logger.getLogger(LPSServer.class.getPackage().getName());

    /**
     * Default constructor.
     */
    public LPSServer() {
        // TODO Auto-generated constructor stub
    }

    @Override
    public User login(String username, String password) {
        if (loggedUser == null) {
            User user = em.find(User.class, username);

            if (user != null) {
                if (PasswordHash.comparePasswordWithHash(password,
                        user.getPassword())) {
                    loggedUser = user;
                    logger.log(Level.INFO, "Loggedin successfull | username="
                            + username);
                    return loggedUser;
                }

                logger.log(Level.WARNING, "GIVEN_PASSWORD_HASH[ "
                        + PasswordHash.hash(password)
                        + " ] SAVED_PASSWORD_HASH[ " + user.getPassword()
                        + " ]");
                logger.log(
                        Level.INFO,
                        "Not logged in due wrong password| username="
                                + user.getUserName());

            } else {
                logger.log(Level.INFO,
                        "Not logged in due wrong username| username="
                                + username);
            }

        }
        else{
            return loggedUser;
        }
        return null;
    }

    @Override
    public void logout() {
        // TODO Auto-generated method stub
        logger.log(Level.INFO, loggedUser.getUserName() + " logged out");
        this.loggedUser = null;

    }

    @Override
    public void createUser(String username, String password) {
        // TODO Auto-generated method stub
        User user = new User();
        user.setUserName(username);
        user.setPassword(password);
        em.persist(user);
        logger.log(Level.INFO, "User created");

    }

}

The method for hashing the password:

package de.lps.utils.security;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.xml.bind.DatatypeConverter;

public class PasswordHash {
    /**
     * 
     * @param password
     * @return returns the md5-hash of the password if the password == null  returns null
     */
    public static String hash(String password){
        if(null == password){
            return null;
        }
        MessageDigest sha256;
        try {
            sha256 = MessageDigest.getInstance("SHA-256");
            byte[] passBytes = password.getBytes("UTF-8");
            byte[] passHash = sha256.digest(passBytes);
            return DatatypeConverter.printHexBinary(passHash);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }        

    }

    /**
     * Compares a specified password with a specified hash
     * @param password
     * @param hash
     * @return return true when hash and password are equals
     */
    public static boolean comparePasswordWithHash(String password, String hash){
        if(hash(password).equals(hash)){
            return true;
        }
        return false;
    }
}   

And the entity User:

package de.lps.entities;

import java.io.Serializable;
import java.lang.String;

import javax.persistence.*;

import de.lps.utils.security.PasswordHash;

/**
 * Entity implementation class for Entity: User
 * 
 */
@Entity
@Table(name = "lps_user")
public class User implements Serializable {

    private String userName;
    private String password;

    private static final long serialVersionUID = 1L;

    public User() {
        super();
    }

    @Id
    @Column(name = "username")
    public String getUserName() {
        return this.userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    @Column(name = "password", length=1000)
    public String getPassword() {
        return this.password;
    }

    public void setPassword(String password) {
        this.password = PasswordHash.hash(password);        
    }

}

Thanks for your help and sorry for my poor english skills

ZeusNet
  • 710
  • 9
  • 25
  • Hey, first of all -- welcome to StackOverflow! A couple of questions for you: What steps did you take to try to get it to work? What error messages do you receive? – Translunar Jul 24 '13 at 21:27
  • That was the problem, there were no error messages. In my log files it only says that the given hash isnt equals to the stored one. But Sotirios gave me the right hint :) – ZeusNet Jul 24 '13 at 21:41
  • Good. Those are the most frustrating errors. Glad you were able to find a solution. – Translunar Jul 24 '13 at 21:43
  • You should get the database to hash the password and also to compare it with what the user entered. There's no need to reimplement all this stuff. – user207421 Jul 24 '13 at 22:26
  • Why should i do so? What are the advantages? – ZeusNet Jul 25 '13 at 04:57

1 Answers1

3

This happens because when you try to load the User instance from the database, your EntityManager will use the User#setPassword(String) setter to set the value of the password it gets from your table. This will recalculate the password hash so you won't the original hash, but a hash of the hash.

You should hash the password outside of your setter method.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • Hey @SotiriosDelimanolis, i have a additional question to this solution. I don't understand why the password was changed on the database when i call the `EntityManager`, because i thougt that this would only happen as i call the `persit` method of the `EntityManager`-class – ZeusNet Jul 25 '13 at 05:00
  • @Holger The `EntityManager` is also used to query for Entities from the database. When that happens it uses reflection to instantiate your entity and to find your setters. It uses those to set the various instance fields. `password` is one of them. – Sotirios Delimanolis Jul 25 '13 at 12:29
  • I know but i thougt the method `find` of the `EntityManager` do this. And i only use this method to get the dataset from the database. But the dataset is changed on the database when i do so. In my mind it shouldn't happen because i have to call the method `perist(Object o)` to persits the changes on the database. – ZeusNet Jul 25 '13 at 12:39
  • When you do `em.find`, that gets the row from the database using reflection to find and use your setters. With JPA, when you change your entity (ex. edit the username), you don't need to recall `persist`. The `EntityManager` will be able to see that you changed it and will itself modify it in the database. This is a called a `managed entity`. See the answer to [this question](http://stackoverflow.com/questions/1784981/jpa-saving-changes-without-persist-invoked). – Sotirios Delimanolis Jul 25 '13 at 13:14