Home > Software engineering >  Trying to add a regex for password pattern matching with Spring Boot
Trying to add a regex for password pattern matching with Spring Boot

Time:11-11

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:[\n\tConstraintViolationImpl{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]\n\tat 

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": "[email protected]",
    "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);
    }
    ```

 

CodePudding user response:

The regex is a little bit off, you should use \\d and not \\\\d:

^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$

CodePudding user response:

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

CodePudding user response:

Use the following Regex to satisfy the below conditions:

Conditions:

  • Min 1 uppercase letter.
  • Min 1 lowercase letter.
  • Min 1 special character.
  • Min 1 number.
  • Min 8 characters.

Regex:

^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[#$@!%&*?])[A-Za-z\d#$@!%&*?]{8,}$

CodePudding user response:

Testing your regex, and it does seem to not work. I was able quickly find the following regex example for a password.

^(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[^\w\d\s:])([^\s]){8,16}$

This regex matches only when all the following are true:

  • password must contain 1 number (0-9)
  • password must contain 1 uppercase letters
  • password must contain 1 lowercase letters
  • password must contain 1 non-alpha numeric number
  • password is 8-16 characters with no space

https://regex101.com/library/0bH043

Here is another great site for building regex from a string: https://regex-generator.olafneumann.org/

  • Related