I have a spring data rest custom user repository in which password need to be encrypted using BCCrypt. From the UI I am sending the plain password, I want to know where to convert the plain password into BCCrypt hash before hibernate creates user in DB. Should I use before save interceptor and hash the password? Or is there any way I can tell spring to use password encoder?
Asked
Active
Viewed 4,823 times
6

Jens Schauder
- 77,657
- 34
- 181
- 348

Vijay Muvva
- 1,063
- 1
- 17
- 31
-
Does this answer your question? [Password encoding with Spring Data REST](https://stackoverflow.com/questions/30260582/password-encoding-with-spring-data-rest) – lcnicolau Jun 26 '22 at 17:02
2 Answers
13
The way to intercept inserts in Spring Data Rest is using an event handler.
NOTE: This code won't work with PATCH operations that don't include the password field.
@Component
@RepositoryEventHandler(User.class)
public class UserEventHandler {
@Autowired
private BCryptPasswordEncoder passwordEncoder;
@Autowired
private UserRepository userRepository;
@HandleBeforeCreate
public void handleUserCreate(User user) {
user.setPassword(passwordEncoder.encode(user.getPassword()));
}
@HandleBeforeSave
public void handleUserUpdate(User user) {
if (user.getPassword() == null || user.getPassword().equals("")) {
//keeps the last password
User storedUser = userRepository.getOne(user.getId());
user.setPassword(storedUser.getPassword());
}
else {
//password change request
user.setPassword(passwordEncoder.encode(user.getPassword()));
}
}
}

Javier Alvarez
- 1,409
- 2
- 15
- 33
-
-
@DavidRiccitelli Then you should implement a similar method annotated with "@HandleBeforeSave" – Javier Alvarez Jun 13 '16 at 14:26
-
It's not feasible, because if I send a PATCH request w/o the password, the User instance will contain the encrypted password (loaded from the database) and you would encrypt it twice. – David Riccitelli Jun 13 '16 at 14:54
-
3HandleBeforeSave is called only with updates (PATCH and PUT) and not with inserts (POST), so you can do a different implementations. I updated my response with an implementation of that method. – Javier Alvarez Jun 15 '16 at 14:36
-
The implementation is not right, because Spring Data REST on PATCH operations (w/o the password set) will pass a User instance with the password property populated from the database. Therefore you'll end up encrypting an already encrypted password. – David Riccitelli Jun 15 '16 at 14:51
-
1That's true. I ended using always PUT, because Spring Data Rest PATCH is not very RESTful standard and I had other issues with it. By the way, you can send an empty password in PATCH operations always (except password change requests), so it won't be populated from database. – Javier Alvarez Jun 16 '16 at 08:51
-
1I am sorry but I don't think this can be called a solution. You're basically inhibiting anyone else from using your APIs. The problem is *not* Spring Data REST but the solution you're proposing. You should use a custom JsonDeserializer on the password field and encrypt the incoming password when the JSON is deserialized, see http://stackoverflow.com/questions/30260582/password-encoding-with-spring-data-rest/30723658 – David Riccitelli Jun 16 '16 at 10:51
-
Ok, I admit that solution it's ok for the general case. In my case, I removed PATCH verb from my users endpoint (and other endpoints) because the implementation of it in Spring data rest gives is not standard and problematic (recommeded read: http://williamdurand.fr/2014/02/14/please-do-not-patch-like-an-idiot/). So I shouldn't call it "inhibiting anyone from using my APIs". – Javier Alvarez Jun 16 '16 at 11:23
-
It's good that you added a notice on top of the answer. Have a good one! – David Riccitelli Jun 16 '16 at 11:35
2
You need to do it in your Registration-Service
, like the following:
@Autowired
private BCryptPasswordEncoder passwordEncoder;
...
public void registerUser(final User user)
{
final String encodedPassword = passwordEncoder.encode(user.getPassword());
user.setPassword(encodedPassword);
userRepo.save(user);
}
The password-encoder i refer you, is the org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
this encoder automatically generate a salt for you.

Manu Zi
- 2,300
- 6
- 33
- 67
-
6If you use Spring-Data-Rest you won't hit any service layer? How would you be able to insert this Service before the Repository when using the implicit Spring-Data-Rest controllers? – Kevin Wittek Jan 19 '16 at 21:39
-
@ManuZi have you been able to resolve this? I'm aware that I can implement a service layer that encodes and delegates the persistence job to the repository, but I'm looking for a more elegant and lightweight solution that uses only implicit JPA repositories. Can we somehow configure JPA to do that? – KareemJ Jan 05 '21 at 10:09
-