Password validation in Java I just wrote this password validation code function that checks to see if a password will be accepted in AD or not. I'm not sure this is the best way to do it, but for now it works fine. I would love some suggestions on how to make it better.

public String validateNewPass(String pass1, String pass2){
        StringBuilder retVal = new StringBuilder();

        if(pass1.length() &lt; 1 || pass2.length() &lt; 1 )retVal.append("Empty fields &lt;br&gt;");

        if (pass1 != null &amp;&amp; pass2 != null) {

            if (pass1.equals(pass2)) {
                logger.info(pass1 + " = " + pass2);

                pass1 = pass2;
                boolean hasUppercase = !pass1.equals(pass1.toLowerCase());
                boolean hasLowercase = !pass1.equals(pass1.toUpperCase());
                boolean hasNumber = pass1.matches(".*\\d.*");
                boolean noSpecialChar = pass1.matches("[a-zA-Z0-9 ]*");

                if (pass1.length() &lt; 11) {
                    logger.info(pass1 + " is length &lt; 11");
                    retVal.append("Password is too short. Needs to have 11 characters &lt;br&gt;");
                }

                if (!hasUppercase) {
                    logger.info(pass1 + " &lt;-- needs uppercase");
                    retVal.append("Password needs an upper case &lt;br&gt;");
                }

                if (!hasLowercase) {
                    logger.info(pass1 + " &lt;-- needs lowercase");
                    retVal.append("Password needs a lowercase &lt;br&gt;");
                }

                if (!hasNumber) {
                    logger.info(pass1 + "&lt;-- needs a number");
                    retVal.append("Password needs a number &lt;br&gt;");
                }

                if(noSpecialChar){
                    logger.info(pass1 + "&lt;-- needs a specail character");
                    retVal.append("Password needs a special character i.e. !,@,#, etc.  &lt;br&gt;");
                }
            }else{
                logger.info(pass1 + " != " + pass2);
                retVal.append("Passwords don't match&lt;br&gt;");
            }
        }else{
            logger.info("Passwords = null");
            retVal.append("Passwords Null &lt;br&gt;");
        }
        if(retVal.length() == 0){
            logger.info("Password validates");
            retVal.append("Success");
        }

        return retVal.toString();

    }


**Note: These lines are to ensure a different case to handle a null vs empty string

if(pass1.length() &lt; 1 || pass2.length() &lt; 1 )retVal.append("Empty fields &lt;br&gt;");

        if (pass1 != null &amp;&amp; pass2 != null) {
Buggy behavior

First you're checking the length of the passwords, and then if they are null:


if(pass1.length() &lt; 1 || pass2.length() &lt; 1 )retVal.append("Empty fields &lt;br&gt;");

if (pass1 != null &amp;&amp; pass2 != null) {



This is not going to work well: if any of the passwords were null, you would get a NullPointerException when you check length.

Also, a better way to check if a string is empty is using pass1.isEmpty().

Also, this is pointless and potentially confusing:


pass1 = pass2;



Simplify the validation logic

It would be better and more efficient to create private final Pattern members that are compiled regular expressions, and reusable multiple times:

private final Pattern hasUppercase = Pattern.compile("[A-Z]");
private final Pattern hasLowercase = Pattern.compile("[a-z]");
private final Pattern hasNumber = Pattern.compile("\\d");
private final Pattern hasSpecialChar = Pattern.compile("[^a-zA-Z0-9 ]");


For example, this returns true if pass1 contains an uppercase character:

hasUppercase.matcher(pass1).find()


Notice the patter for hasSpecialChar: match non-alphabetic, non-digit, non-space.

Suggested implementation

Based on the above tips, you can simplify your implementation like this:

private final Pattern hasUppercase = Pattern.compile("[A-Z]");
private final Pattern hasLowercase = Pattern.compile("[a-z]");
private final Pattern hasNumber = Pattern.compile("\\d");
private final Pattern hasSpecialChar = Pattern.compile("[^a-zA-Z0-9 ]");

public String validateNewPass(String pass1, String pass2) {
    if (pass1 == null || pass2 == null) {
        logger.info("Passwords = null");
        return "One or both passwords are null";
    }

    StringBuilder retVal = new StringBuilder();

    if (pass1.isEmpty() || pass2.isEmpty()) {
        retVal.append("Empty fields &lt;br&gt;");
    }

    if (pass1.equals(pass2)) {
        logger.info(pass1 + " = " + pass2);

        if (pass1.length() &lt; 11) {
            logger.info(pass1 + " is length &lt; 11");
            retVal.append("Password is too short. Needs to have 11 characters &lt;br&gt;");
        }

        if (!hasUppercase.matcher(pass1).find()) {
            logger.info(pass1 + " &lt;-- needs uppercase");
            retVal.append("Password needs an upper case &lt;br&gt;");
        }

        if (!hasLowercase.matcher(pass1).find()) {
            logger.info(pass1 + " &lt;-- needs lowercase");
            retVal.append("Password needs a lowercase &lt;br&gt;");
        }

        if (!hasNumber.matcher(pass1).find()) {
            logger.info(pass1 + "&lt;-- needs a number");
            retVal.append("Password needs a number &lt;br&gt;");
        }

        if (!hasSpecialChar.matcher(pass1).find()) {
            logger.info(pass1 + "&lt;-- needs a specail character");
            retVal.append("Password needs a special character i.e. !,@,#, etc.  &lt;br&gt;");
        }
    } else {
        logger.info(pass1 + " != " + pass2);
        retVal.append("Passwords don't match&lt;br&gt;");
    }
    if (retVal.length() == 0) {
        logger.info("Password validates");
        retVal.append("Success");
    }

    return retVal.toString();
}


Support for unicode

If you want to allow unicode characters in the password, define the patterns using the special java character classes, as documented in the javadoc:

private final Pattern hasUppercase = Pattern.compile("\\p{javaUpperCase}");
private final Pattern hasLowercase = Pattern.compile("\\p{javaLowerCase}");
private final Pattern hasNumber = Pattern.compile("\\p{javaDigit}");
private final Pattern hasSpecialChar = Pattern.compile("[^\\p{javaLetterOrDigit} ]");