Skip to content
Advertisement

Trying to add a regex for password pattern matching with Spring Boot

I want to add pattern matching for a user registering a password. In my user model I have:

@Column
    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    @Pattern(regexp = "^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%%*#?&])[A-Za-z\d@$!%%*#?&]{8,}$")
    private String password;

However, when I go to register a user I am getting a 400 Bad Request.

javax.validation.ConstraintViolationException: Validation failed for classes [com.practice.models.AppUser] during persist time for groups [javax.validation.groups.Default, ]nList of constraint violations:[ntConstraintViolationImpl{interpolatedMessage='must match "^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%%*#?&])[A-Za-z\d@$!%%*#?&]{8,}$"', propertyPath=password, rootBeanClass=class com.practice.models.AppUser, messageTemplate='{javax.validation.constraints.Pattern.message}'}n]ntat 

Can it be done with the @Pattern annotation? And should it go on the model?

The endpoint for my controller looks like this:

@PostMapping("/register")
        public AppUser register(@Valid @RequestBody AppUser user) {
            return appUserService.createUser(user);
        }

This is the data I sent to register:

{
    "username": "Johnny",
    "email": "johnny@rosevideo.com",
    "password": "P@ssword123",
    "passwordConfirmation": "P@ssword123"
}

And then in my service layer, I am encrypting my password with BCrypt:

public AppUser createUser(AppUser appUser) {
        Optional<AppUser> existingUser = appUserRepo.findByUsername(appUser.getUsername());
        if (existingUser.isPresent()) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "A user with that username already exists");
        }

        if (!appUser.getPassword().equals(appUser.getPasswordConfirmation())) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Passwords don't match");
        }

        String encodedPassword = bCryptPasswordEncoder.encode(appUser.getPassword());
        appUser.setPassword(encodedPassword);


        return appUserRepo.save(appUser);
    }
    ```

 

Advertisement

Answer

This can often happen when you use password encryption at the same time as password validation. Basically, your app is currently running the pattern validation against the encrypted password.

Without extra configuration, the @Pattern annotation results in validation being run not only where you use @Valid in your controller, but also in the persistence layer when you call appUserRepo.save(appUser). This means the pattern matching is run against the hashed password, which may well not match your pattern.

If you don’t want validation to run at persistence, add this line to your application.properties file:

spring.jpa.properties.javax.persistence.validation.mode=none

User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement