Maciej Szlosarczyk
Maciej Szlosarczyk

Reputation: 809

Storing computed data (passwordHash) in Hibernate with Spring

I have an Object with the following constructor:

public User(String name, String email, String password) {
    this.name = name;
    this.email = email;
    this.creationDate = new Date();
    this.passwordHash = hashPassword(password, getCreationDate());
}

The hashPassword is a method that creates the passwordHash taking the password string and date as salt. Obviously, I only want it to be stored in the hashed format. The question is that given the following Controller and request, the returned value is null:

@RequestMapping(method = RequestMethod.POST) @ResponseStatus(HttpStatus.CREATED) public
@ResponseBody User createUser(@RequestBody User user) {
    return repository.save(user);}

JSON:

{
"name": "My new user",
"email": "My email",
"password": "my password"
}

Response:

{
"id": 1,
"name": "My new user",
"email": "My email",
"passwordHash": null,
"creationDate": null
}

User.java:

@Entity public class User {
@Column private Long id;

@Column(nullable = false) private String name;

@Column(nullable = false, unique = true) private String email;

@Column(nullable = false) private String passwordHash;

@CreationTimestamp private Date creationDate;

// Constructors

public User() {
}

public User(String name, String email, String password) {
    this.name = name;
    this.email = email;
    this.passwordHash = hashPassword(password, getCreationDate());
}

// Additional methods

public String hashPassword(String password, Date date) {
    MessageDigest sha512 = null;
    try {
        sha512 = getInstance("SHA-512");
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    String passwordProposal = password + date
        .toString();
    byte[] passwordDigest = new byte[0];
    try {
        passwordDigest = sha512.digest(passwordProposal.getBytes("UTF-8"));
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    return Hex.encodeHexString(passwordDigest);
}

public boolean comparePasswords(String password, String passwordHash) {
    if (hashPassword(password, getCreationDate()).equals(passwordHash)) {
        return true;
    } else
        return false;
}

// Getters and setters

@Id @GeneratedValue(strategy = GenerationType.IDENTITY) public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public String getEmail() {
    return email;
}

public void setEmail(String email) {
    this.email = email;
}

public String getPasswordHash() {
    return passwordHash;
}

public void setPasswordHash(String password) {
    this.passwordHash = password;
}

@Generated(value = GenerationTime.INSERT) public Date getCreationDate() {
    return creationDate;
}

public void setCreationDate(Date creationDate) {
    this.creationDate = creationDate;
}

// toString

@Override public String toString() {
    final StringBuilder sb = new StringBuilder("User{");
    sb.append("id=").append(id);
    sb.append(", name='").append(name).append('\'');
    sb.append(", email='").append(email).append('\'');
    sb.append(", passwordHash='").append(passwordHash).append('\'');
    sb.append(", creationDate=").append(creationDate);
    sb.append('}');
    return sb.toString();
}
}

Upvotes: 0

Views: 66

Answers (1)

inigo skimmer
inigo skimmer

Reputation: 918

The problem is that by default request to entity converter (I suppose you use Jackson for JSON) uses no argument constructor, so computed fields are not populated.

@JsonCreator
public User(@JsonProperty("name") String name,
            @JsonProperty("email") String email,
            @JsonProperty("password") String password) {
    this.name = name;
    this.email = email;
    this.creationDate = new Date();
    this.passwordHash = hashPassword(password, getCreationDate());
}

The above code should work I think.

Upvotes: 1

Related Questions