1

Given a password, I am trying to validate if it passes all validation rules such as

  1. Be at least 6 characters long
  2. Contain at least one letter (a-z or A-Z)
  3. Contain at least one number (0-9)
  4. Contain at least one special character (@, $, %, etc)

So I am creating a common validation class which can be used for in any of my applications. Below are the following scenarios the validation class needs to handle :

  • Passing password, confirm password as input and perform all validations.
  • Passing current password, new password, confirm password as input and perform all validations.
  • Passing username, password, confirm password as input but skip special character validation

So here is my initial idea. I created static methods for each scenario and return a Result object which will say if the validation has passed or failed. If it failed, it will contain error codes added to errors list object which the calling application will handle as needed.

/* CASE1: Passing password, confirm password as input and perform all validation */ 
public static ValidationResult validate(final String newPassword, final String newConfirmedPassword) {
    ValidationResult result = checkPassword(null, newPassword, newConfirmedPassword, false, true);
    // check for any errors in result object
    return result;
}

/* CASE 2 : Passing current password, new password, confirm password as input and perform all validation */
public static ValidationResult validate(final String oldPassword, final String newPassword, final String newConfirmedPassword) {
    ValidationResult result = checkPassword(oldPassword, newPassword, newConfirmedPassword, true, true);
    // check for any errors in result object
    return result;
}

/* CASE3: Passing username, password, confirm password as input but skip special character validation  */
public static ValidationResult validate(final String userName, final String newPassword, final String newConfirmedPassword) {
    ValidationResult result = checkPassword(oldPassword, newPassword, newConfirmedPassword, true, false);
    // check for any errors in result object
    return result;
}

private static ValidationResult checkPassword(final String currentPass, final String newPass,
        final String confirmedPass, final boolean resetFlag, boolean allowSplChar) {
    ValidationResult result = new ValidationResult(true);
    if(resetFlag) {
        //check if current password app has entered is correct
        //check new password is different from current password
    }
    // check password length is between 8-14 characters 
    if (doesNotContainUpperCaseAlpha(newPass)){
        // set error code to result 
        result.getErrors().add("ERROR_NO_UPPERCASE");
    }
    if (doesNotContainLowerCaseAlpha(newPass)){
        // set error code to result 
        result.getErrors().add("ERROR_NO_LOWERCASE");
    }
    ...
    ..
    if(allowSplChar && doesNotContainSplCharacter(newPass)){
        // set error code to result 
        result.getErrors().add("ERROR_NO_SPECIAL_CHARAACTER");
    }
}

The above flow might work for the required scenarios but is there a better way this can be implemented?

4

1 Answer 1

2

Observations:

  • Method signatures are too long (5 parms!)
  • All method are statics, possible indication of a God Class
  • No flexibility considering that you want ...a common validation class which can be used for in any of my applications"
  • Validation options and user credentials are mixed (too many concerns)

My suggestion is:

  • A PasswordValidator class or interface which is responsible of validation options and performing validation
  • A credentials class or interface that holds username, new password, etc.
  • Usage: you instantiate the validator, set the validation settings (maybe a Factory method would do it for you, you can even read the validation settings from a conf file) then call validate(userCredentials);

One PNG is worth 1024 words:

enter image description here

Stubs and code:

==> PasswordValidator.java <== You might one to implement slightly different validators. If you find it too much having an interface just use the class down bellow.

public interface PasswordValidator {    
    public void setReset(boolean reset);
    public void setMinimalLength(int length);
    public void setAllowPasswordEqualsName(boolean allow);
    public void setAllowSpecialCharacters(boolean allow);

    public boolean getReset();
    public int getMinimalLength();
    public boolean getAllowPasswordEqualsName();
    public boolean getAllowSpecialCharacters();     
    public ValidationResult validate(Credentials cred);
}

==> Credentials.java <== This one I could be a class, I used an interface to save time and space

public interface Credentials {
    public void setUserName(String userName);
    public void setOldPasssword(String oldPassword);
    public void setNewPassword(String newPassword);
    public void setConfirmedNewPassword(String confirmedNewPassword);
    public String getUserName();
    public String getOldPasssword();
    public String getNewPassword();
    public String getConfirmedNewPassword();
}

==> ValidationResult.java <== This implementation you already have

public class ValidationResult {
}

==> NicePasswordValidator.java <== A sample implementor of PasswordValidator

public class NicePasswordValidator implements PasswordValidator {

    private boolean allowSpecialCharacters;
    private boolean allowPasswordEqualsName;
    private int minimalLength;
    private boolean reset;  

    private static boolean containSpecialCharacters(String newPassword) {
        // TODO Auto-generated method stub
        return false;
    }

    private static boolean containsLowerCase(String newPassword) {
        // TODO Auto-generated method stub
        return false;
    }

    private static boolean containsUpperCase(String newPassword) {
        // TODO Auto-generated method stub
        return false;
    }

    private static boolean doesNotContainUpperCaseAlpha(String newPassword) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public void setReset(boolean reset) {
        this.reset=reset;
    }

    @Override
    public void setMinimalLength(int length) {
        this.minimalLength=length;
    }

    @Override
    public void setAllowPasswordEqualsName(boolean allow) {
        this.allowPasswordEqualsName=allow;
    }

    @Override
    public void setAllowSpecialCharacters(boolean allow) {
        this.allowSpecialCharacters=allow;      
    }   

    @Override
    public boolean getReset() {
        return this.reset;
    }

    @Override
    public int getMinimalLength() {
        return this.minimalLength;
    }

    @Override
    public boolean getAllowPasswordEqualsName() {
        return this.allowPasswordEqualsName;
    }

    @Override
    public boolean getAllowSpecialCharacters() {
        return this.allowSpecialCharacters;
    }

    @Override
    public ValidationResult validate(Credentials cred) {

        ValidationResult result = new ValidationResult();

        if (!this.allowPasswordEqualsName && cred.getNewPassword().endsWith(cred.getUserName())){
            // add to result
        }

        if (!cred.getNewPassword().equals(cred.getConfirmedNewPassword())){
            // add to result
        }

        if (!this.containsUpperCase(cred.getNewPassword())){
            // add to result
        }

        if (!this.containsLowerCase(cred.getNewPassword())){
            // add to result
        }

        if (!this.getAllowSpecialCharacters() && this.containSpecialCharacters(cred.getNewPassword())){
            // add to result
        }

        return result;
    }
}

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.