Ad

Matching Encoded Password Field Spring Boot

- 1 answer

I´m currently learning Spring-Boot framework and trying to create a custom field matching Validator following the guide at the page baledung.

My code is actually the same like on the page above, the only thing that's different is that I've encoded the password using BCryptPasswordEncoder.

Here is my user class.

    @FieldsValueMatch.List({
        @FieldsValueMatch(
                field = "password",
                fieldMatch = "verifyPassword",
                message = "Passwords do not match!"
        )
})
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity(name = "User")
public class User implements UserDetails {
    @Id
    @GeneratedValue (strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    @NotEmpty(message = "{firstname.notempty}")
    private String firstname;

    @Column(nullable = false)
    @NotEmpty(message = "{lastname.notempty}")
    private String lastname;

    @Column(nullable = false,unique = true)
    @NotEmpty(message = "{email.notempty}")
    @Email(message = "{email.notwellformed}")
    private String email;

    @Column(nullable = false)
    @NotEmpty(message = "{password.notempty}")
    @ValidPassword
    private String password;

    @NotEmpty(message = "{verifyPassword.notempty}")
    @Transient
    private String verifyPassword;

Controller:

    @PostMapping("/sign-up")
String signUp(@Valid User user, BindingResult bindingResult) {
    if (userService.userExists(user.getEmail())){
        bindingResult.rejectValue("email", "email.alreadyexists");
    }
    if(bindingResult.hasErrors()){
        return "sign-up";
    }
    user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
    userService.signUpUser(user);
    return "redirect:/sign-in";
}

signUpUser Method:

    public void signUpUser(User user) {
    user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
    userRepository.save(user);
    final ConfirmationToken confirmationToken = new ConfirmationToken(user);
    confirmationTokenService.saveConfirmationToken(confirmationToken);
    sendConfirmationMail(user.getEmail(), confirmationToken.getConfirmationToken());
}

And I recieve the following error:

    javax.validation.ConstraintViolationException: Validation failed for classes [com.project.project.entity.User] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
    ConstraintViolationImpl{interpolatedMessage='Passwords do not match!', propertyPath=verifyPassword, rootBeanClass=class com.project.project.entity.User, messageTemplate='Passwords do not match!'}
    ConstraintViolationImpl{interpolatedMessage='Password must be no more than 30 characters in length.', propertyPath=password, rootBeanClass=class com.project.project.entity.User, messageTemplate='Password must be no more than 30 characters in length.'}
]
    at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:140) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
    at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreInsert(BeanValidationEventListener.java:80) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
    at org.hibernate.action.internal.EntityIdentityInsertAction.preInsert(EntityIdentityInsertAction.java:188) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
    at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:78) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
    at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:645) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
    at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:282) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
    at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:263) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
    at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:317) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
    at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:330) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:287) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:193) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:123) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:185) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:128) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:55) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
    at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:107) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:760) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:746) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]

I think that encoded password is being compared with the verifyPassword which isn't encoded. That's why I'm receieving this error or? How can I fix it? If I also encode the verifyPassword, I still get the error.

Thanks in Advance.

Ad

Answer

The length of 30 characters normally represents that a user of the system should type a password no more than 30 characters long. The typed password however when encoded by the system will be of a different length.

The error occurs because the User that you use to map your database entity has a validation constraint of password not exceeding 30 characters. The process to encode your password can modify the original length of the password. Therefore the error occurs.

You should create another class UserDto which would be accessible from the controller and will represent the information that is exchanged between the controller class and the actual user of the system which types the password. This new UserDto can then have this constraint of 30 characters and the database representation with User class can be without such constraint, since in database the password will be stored with a different length.

So you will use UserDto class to validate the input of the user, to the system, and you will use User class to map your database records inside a java object following the structure of the relative table.

Ad
source: stackoverflow.com
Ad