2017-09-08 1 views
0

J'ai une obligation d'écrire un service de validation de mot de passe, ce qui est de accepct certaines règles: je l'ai écrit ci-dessous le code:Mot de passe service de validation

@Service 
public class PasswordValidatonServiceImpl implements PasswordValidationService { 

    public static final String EMPTY_OR_NULL_PASSWORD = "Password Should not be empty"; 
    public static final String ERROR_PASSWORD_LENGTH = "Password must be betwee 5 and 12 characters long."; 
    public static final String ERROR_PASSWORD_CASE = "Password must only contain lowercase letters."; 
    public static final String ERROR_LETTER_AND_DIGIT = "Password must contain both a letter and a digit."; 
    public static final String ERROR_PASSWORD_SEQUENCE_REPEATED = "Password must not contain any sequence of characters immediately followed by the same sequence."; 


    private Pattern checkCasePattern = Pattern.compile("[A-Z]"); 
    private Pattern checkLetterAndDigit = Pattern 
      .compile("(?=.*[a-z])(?=.*[0-9])"); 
    private Pattern checkSequenceRepetition = Pattern.compile("(\\w{2,})\\1"); 

    /** 
    * @param password 
    * @return List<String> This method calls 4 more methods which validates 
    *   password and return list of errors if any. 
    */ 
    public List<String> validatePassword(String password) { 
     List<String> failures = new ArrayList<String>(); 
     if (StringUtils.isEmpty(password)) { 
      failures.add(EMPTY_OR_NULL_PASSWORD); 
      return failures; 
     } else { 
      checkLength(password, failures); 
      checkCase(password, failures); 
      checkLetterAndDigit(password, failures); 
      checkSequenceRepetition(password, failures); 
      return failures; 
     } 
    } 

    /** 
    * @param password 
    * @param failures 
    *   This method will validate if there are any repeated character 
    *   sequence, if found it will add error message to failures list. 
    */ 
    private void checkSequenceRepetition(String password, List<String> failures) { 
     Matcher matcher = checkSequenceRepetition.matcher(password); 
     if (matcher.find()) { 
      failures.add(ERROR_PASSWORD_SEQUENCE_REPEATED); 
     } 
    } 

    /** 
    * @param password 
    * @param failures 
    *   This method will validate both letters and characters in 
    *   password, if not found add a error message to the failures 
    *   list. 
    */ 
    private void checkLetterAndDigit(String password, List<String> failures) { 
     Matcher matcher = checkLetterAndDigit.matcher(password); 
     if (!matcher.find()) { 
      failures.add(ERROR_LETTER_AND_DIGIT); 
     } 
    } 

    /** 
    * @param password 
    * @param failures 
    *   This Method checks upper case and lower case letters in the 
    *   password if there are any Upper case letters it will add error 
    *   message to failures list. 
    */ 
    private void checkCase(String password, List<String> failures) { 
     Matcher matcher = checkCasePattern.matcher(password); 
     if (matcher.find()) { 
      failures.add(ERROR_PASSWORD_CASE); 
     } 
    } 

    /** 
    * @param string 
    * @param failures 
    *   This Method will checks the length of the string, if string is 
    *   less than 5 or more than 12 characters then it will add error 
    *   message into failures list 
    */ 
    private void checkLength(String string, List<String> failures) { 
     if (string.length() < 5 || string.length() > 12) { 
      failures.add(ERROR_PASSWORD_LENGTH); 
     } 
    } 
} 

Maintenant, mon exigence est de faire de cette classe est extensible, donc, en avenir, si je veux ajouter plus de règles/prendre quelques règles, les changements de code devraient être minimes. Comment puis-je atteindre cet objectif? Toutes les suggestions sont appréciées.

+0

Vous semblez vérifier toutes les règles, même si l'une des règles a été enfreinte. Ne serait-il pas plus facile de vérifier un mot de passe valide et de retourner false dès que l'une des règles est violée? – hamena314

+0

n'a pas vous pouvez vous s'il vous plaît élaborer – user8579908

+0

La plupart ne contiennent que des lettres minuscules? Entre 5 et 12 caractères de long? Plutôt effrayant! Considérez ceci: https://nakedsecurity.sophos.com/2016/08/18/nists-new-password-rules-what-you-need-to-know/ – TheGreatContini

Répondre

1

Vous pouvez définir PasswordValidationService comme une sorte de liste ou d'ensemble d'une nouvelle classe, PasswordRule. De cette façon, le PasswordValidationService retournera "password is valid" si et seulement si chaque PasswordRule est satisfaite.

Si vous deviez ajouter de nouvelles règles, il vous suffira de les définir en tant que nouvelles règles de mot de passe et de les ajouter à votre instance de PasswordValidationService.

EDIT: ajout exemple de code

La classe abstraite chaque nouvelle règle devrait mettre en œuvre:

public abstract class PasswordRule{ 
    private String errorString; 

    abstract public boolean check(String password){ 
     //implement the rule 
    } 

    public String getError(){ 
     return errorString; 
    } 
} 

La classe qui étend la classe abstraite PasswordRule, ce mot de passe ne pas être vide:

public class PasswordNotEmpty extends PasswordRule{ 
    private String errorString; 

    public PasswordNotEmpty(){ 
     errorString = "Password Should not be empty"; 
    } 

    public boolean check(String password){ 
     return StringUtils.isEmpty(password); 
    } 
} 

Et enfin le PasswordValidationService:

public class PasswordValidator implements PasswordValidationService{ 
    private Set<PasswordRule> rules = new HashSet<PasswordRules>(); 

    public PasswordValidator(PasswordRule... args){ 
     for(PasswordRule r : args) 
      rules.add(r); 
    } 

    public List<String> validate(String password){ 
     List<String> failures = new ArrayList<String>(); 
     for(PasswordRule r : rules) 
      if(!r.check(password)) 
       failures.add(r.getError()); 
     return failures; 
    } 
} 

Son utilisation va ressembler à ceci:

PasswordRule rule1 = new PasswordNotEmpty(); 
PasswordValidationService v = new PasswordValidator(rule1); 
List<String> errors = v.validate("somePassword"); 
+0

Exemple de code serait apprécié merci .. – user8579908

+0

Je vais modifier mon poste avec du code. Je vous suggère quelques documents à lire: [Interfaces] (https://docs.oracle.com/javase/tutorial/java/concepts/interface.html) et [Abstract Classes] (https://docs.oracle.com /javase/tutorial/java/IandI/abstract.html) en Java –

+0

Bien sûr, ça va m'aider .. – user8579908

1

Tout d'abord, ne pas conserver le mot de passe dans String mais comme un tableau de caractères char[]. C'est pour des raisons de sécurité. Lire la suite chez f.e. ici: Why is char[] preferred over String for passwords?

Deuxièmement, le service et sa méthode isValid(char[] password) est supposé renvoyer booléen descirbing la validité du mot de passe lui-même. Il serait:

public boolean isValid(char[] password) { ... } 

Personnellement, je voudrais créer une liste de champ ou l'ensemble tenant la politique actuelle de validation (comme String, Enum ..). Ces règles de critères doivent être ajoutées à l'instance du service validant un mot de passe.

private Set<PasswordValidationPolicy> passwordValidationPolicy; 

public void addPolicy(PasswordValidationPolicy policy) { 
    this.passwordValidationPolicy.add(policy); 
} 

La validation se serait entraîné selon les éléments de la liste ou un ensemble dans la méthode isValid(...).

if (passwordValidationPolicy.contains(..)) { /* validate ... */} 

Ceci est juste l'une des nombreuses implémentations possibles. Finalement c'est à vous de choisir celui qui correspond à votre projet et il doit respecter les pratiques courantes sur les mots de passe mentionnés ci-dessus.

+0

Pouvez-vous s'il vous plaît ajouter un peu plus extrait de code pour Set ou liste de règles de mot de passe, je ne comprends pas comment pouvons-nous atteindre cela .. merci pour l'aide .. – user8579908

0

Je vous suggère de lister toutes ces méthodes que vous souhaitez utiliser dans interface (ou peut-être l'interface générique, si vous avez besoin de plus de méthodes generic par exemple). Ensuite, implémentez cette interface dans votre classe, vous devez donc les importer. Toujours remplacer vos méthodes et ce sera vraiment agréable. Abstract class est aussi un bon exemple, comme l'a écrit Emanuele Giona. Les méthodes abstraites doivent être surchargées.

+0

vous voulez dire toutes ces méthodes: checkLength (mot de passe, échecs); \t \t \t checkCase (mot de passe, échecs); \t \t \t checkLetterAndDigit (mot de passe, échecs); \t \t \t checkSequenceRepetition (mot de passe, échecs); dans l'interface? – user8579908

+0

Oui.Vous les listez tous dans l'interface ou sous forme de méthodes abstraites dans la classe que vous allez hériter. Vous devrez donc implémenter des méthodes non implémentées. Lisez à propos des classes abstraites et des interfaces. J'ai mis un lien hypertexte dans ma réponse, aussi Emanuele a fait –