DEV Community

Cover image for Not a Regular Password Regex
Joseph Olugbohunmi
Joseph Olugbohunmi

Posted on

Not a Regular Password Regex

The password must contain at least 3 of these: a lower-case letter, an upper-case letter, a number, a special character (such as @$!%*#?&) and cannot be less than 8 characters in length.

That is the goal…

There are several regular expression patterns used for password validation based on different requirements but what if you have a password policy that is a little bit lenient and at the same time does not compromise on the security and strength of the password. There is a particular regex pattern that can achieve this (NB: I am not in any way saying this is the best password policy).

Let us have a look at the regex;

String regex = "^(((?=.*[a-z])(?=.*[A-Z])(?=.*\\d))|((?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*#?&]))|((?=.*[a-z])(?=.*[A-Z])(?=.*[@$!%*#?&]))|((?=.*[a-z])(?=.*\\d)(?=.*[@$!%*#?&])))(?=\\S+$).{8,}$";
Enter fullscreen mode Exit fullscreen mode

Now let us see this regex in use;

public class PasswordValidationTest {

    private Pattern pattern;

    @Before
    public void setUp() {
        String regex = "^(((?=.*[a-z])(?=.*[A-Z])(?=.*\\d))|((?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*#?&]))|((?=.*[a-z])(?=.*[A-Z])(?=.*[@$!%*#?&]))|((?=.*[a-z])(?=.*\\d)(?=.*[@$!%*#?&])))(?=\\S+$).{8,}$";
        pattern = Pattern.compile(regex);
    }

    @Test
    public void test_first_valid_password_example() {
        //Number, upper case, lower case in no particular order
        String password = "13Edlpouhgfdcfvgbqb";
        Assert.assertTrue(matchPassword(password));
    }

    @Test
    public void test_second_valid_password_example() {
        //Lower case, number, special character in no particular order
        String password = "dfgjrwerdvfbghjhgfdxc90@";
        Assert.assertTrue(matchPassword(password));
    }

    @Test
    public void test_third_valid_password_example() {
        //Upper case, number, lower case in no particular order
        String password = "POIIUHGFBGNHUYF2df";
        Assert.assertTrue(matchPassword(password));
    }

    @Test
    public void test_fourth_valid_password_example() {
        //Upper case, lower case, number, special character in no particular order
        String password = "KJSrtyhgh!58E543561#";
        Assert.assertTrue(matchPassword(password));
    }

    @Test
    public void test_invalid_password_example() {
        String password = "TGsayhtgfdcsxrbfdvc";
        Assert.assertFalse(matchPassword(password));
    }

    //Utility function
    private boolean matchPassword(String password) {
        Matcher matcher = pattern.matcher(password);
        return matcher.matches();
    }
}
Enter fullscreen mode Exit fullscreen mode

As seen in the code snippet above, this regex does not make any of the conditions mandatory but the user cannot submit a password that does not satisfy at least three of these conditions, and of course, the password cannot be less than 8 characters long. The fourth test case shows that the regex can allow a password that has all four combinations, while the last test case is that of an invalid password.

Now let us see the result of the tests above;

Image description

All tests passed, now some explanation;
^ Assert position at the start of the line
(?=.*[a-z]) Ensure a lower case letter must occur at least once
(?=.*[A-Z]) Ensure an upper case letter must occur at least once
(?=.*\\d) Ensure a digit must occur at least once
(?=.*[@$!%*#?&]) Ensure a special character must occur at least once
(?=\S+$) Ensure no white space is allowed in the entire string
.{8,} Ensure at least eight characters
$ Assert position at the end of the line
Also, notice that there are 4 groups of combination in the regex separated by the Alternative sign (|), equivalent to OR condition. That does the conditional enforcement. I hope this is helpful to someone out there.

Thanks for reading! If you have any observation, kindly share your thoughts in the comment section. You can also reach out to me via Twitter or LinkedIn.

Top comments (0)