Unit Testing Password Utility in Java

In this guide, we will see how to create a Password utility to validate the password using certain rules and then write Unit test cases to unit test the Password utility in Java.

Password security rules are crucial to protect users and systems from unauthorized access. While the specific rules may vary based on the application's nature and security requirements, certain standard rules are widely accepted across the industry. 

Standard Password Security Rules 

Minimum Length: Passwords should have a minimum length, typically at least 8 characters. This makes brute-force attacks more difficult. 

Character Types: 

  • Uppercase: At least one uppercase letter.
  • Lowercase: At least one lowercase letter. 

Numeric: At least one number. 

Symbols: At least one symbol (e.g., @, #, $, %, ^, &, *). 

No Common Passwords: Passwords such as "password123", "12345678", or "letmein" should be explicitly disallowed. 

No User-related Info: Passwords should not contain easily obtainable information about the user, like their username, real name, company name, or birthdate. 

No Repetitive or Sequential Characters: Passwords like "aaaaaa", "123456", or "abcdef" should be avoided. 

Password Expiry: Depending on the security requirements, passwords might need to be changed every 60 to 90 days. 

Limit Password Attempts: Implement an account lockout or delay after a certain number of incorrect password attempts to thwart brute-force attacks. 

Two-Factor Authentication (2FA): Whenever possible, enable 2FA. This adds an additional layer of security beyond just the password. 

Check Against Breaches: Some systems check passwords against databases of known breached passwords, ensuring users don't use passwords previously exposed in hacks. 

No Dictionary Words: Passwords should not be easily guessable dictionary words or combinations of two dictionary words. 

Regular Audits: Regularly audit and test password policies, including using penetration testing to find vulnerabilities. 

Educate Users: Users should be informed about the importance of unique passwords across platforms and the risks of reusing passwords.

Password Utility Class

Here is the Password Utility class that covers the most common rules:
import java.util.regex.Pattern;

public class PasswordUtil {

    private static final Pattern UPPERCASE_PATTERN = Pattern.compile(".*[A-Z].*");
    private static final Pattern LOWERCASE_PATTERN = Pattern.compile(".*[a-z].*");
    private static final Pattern DIGIT_PATTERN = Pattern.compile(".*\\d.*");
    private static final Pattern SYMBOL_PATTERN = Pattern.compile(".*[@#$%^&*].*");
    private static final Pattern REPETITIVE_PATTERN = Pattern.compile("(.)\\1{2,}"); // more than two repetitions
    private static final Pattern SEQUENTIAL_PATTERN = Pattern.compile("123|234|345|456|567|678|789|987|876|765|654|543|432|321"); // 3 consecutive digits

    public static boolean isValidPassword(String password) {
        if (password == null) {
            return false;
        }

        if (password.length() < 8 || password.length() > 12) {
            return false;
        }

        if (!UPPERCASE_PATTERN.matcher(password).matches() ||
            !LOWERCASE_PATTERN.matcher(password).matches() ||
            !DIGIT_PATTERN.matcher(password).matches() ||
            !SYMBOL_PATTERN.matcher(password).matches()) {
            return false;
        }

        if (REPETITIVE_PATTERN.matcher(password).find() || SEQUENTIAL_PATTERN.matcher(password).find()) {
            return false;
        }

        // TODO: Further checks like checking against a list of common passwords can be added.

        return true;
    }
}

JUnit Test Cases - Unit Testing Password Utility in Java

import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;

public class PasswordUtilTest {

    @Test
    public void testIsValidPassword() {
        assertFalse(PasswordUtil.isValidPassword(null));  // Null password
        assertFalse(PasswordUtil.isValidPassword("short"));  // Too short
        assertFalse(PasswordUtil.isValidPassword("nouppercase1@"));  // Missing uppercase
        assertFalse(PasswordUtil.isValidPassword("NOLOWERCASE1@"));  // Missing lowercase
        assertFalse(PasswordUtil.isValidPassword("NoNumbersOrSymbols"));  // Missing number and symbol
        assertTrue(PasswordUtil.isValidPassword("Valid1@Pass"));  // Valid password
        
        // Add more test cases as per other rules.
    }
}

You can run these tests using your favorite IDE with JUnit support or via a build tool like Maven or Gradle.

Comments