3

I need to validate passwords that needs to fulfill the following rules:

  • Minimum length is 8 characters
  • All characters need to be unique
  • At least one of the characters is capitalized
  • At least one character is a non-alphabetic character, a digit or a hyphen
  • Non-alphabetic characters should not be placed as the first two or last two characters

I can't figure out how to validate this using regular expressions. Can anybody help me?

mmjmanders
  • 1,533
  • 2
  • 13
  • 32
  • 3
    Sometimes writing a few lines of validation code is better than writing an undecipherable regular expression. Also, assertions like "all characters need to be unique" can be quite unwieldy when it comes to regular expressions. – Ates Goral Dec 11 '14 at 14:56
  • 9
    *All characters need to be unique* is a horrible idea. That **reduces** security significantly. – Elliott Frisch Dec 11 '14 at 14:58
  • 2
    Most of thease problems are solved in [this blog post](http://howtodoinjava.com/2012/12/14/how-to-build-regex-based-password-validator-in-java/). I'd suggest not using one super long 'oneliner' regex, because it's hard to maintain. – Marcin Szymczak Dec 11 '14 at 15:00
  • I would use a library that verifies the password entropy and then tries to "find it" using the usual tricks of the trade. Regexes for passwords fields just cause Mr. Rage to drop by. – David Tonhofer Dec 11 '14 at 15:02
  • 1
    Is there a reason not to have a `Rule` interface, implementations for each of these rules, and require that the input pass at least `N` rules? Then you can just keep a collection of rules around, rather than an unmaintainable regex. – ssube Dec 11 '14 at 15:11

2 Answers2

5
^(?=.*[A-Z])(?=.*(?:\d|-))(?!.*(.).*\1)[a-zA-Z]{2}.{4,}[a-zA-Z]{2}$

Try this.See demo.

https://regex101.com/r/eZ0yP4/12

As you can see step by step all conditions are met with the help of lookahead.

(?=.*[A-Z])===at least one Capital

(?=.*(?:\d|-))===at least one digit or -

(?!.*(.).*\1)=== no duplicates

[a-zA-Z]{2}.{4,}[a-zA-Z]{2}===alphabetic characters as first two and last two.

vks
  • 67,027
  • 10
  • 91
  • 124
3

You could use vt password library. Code is quite long, but it is easy to modify it and it is quite maintainable.

// password must be between 8 and 16 chars long
LengthRule lengthRule = new LengthRule(8, 16);

// don't allow whitespace
WhitespaceRule whitespaceRule = new WhitespaceRule();

// control allowed characters
CharacterCharacteristicsRule charRule = new CharacterCharacteristicsRule();
// require at least 1 digit in passwords
charRule.getRules().add(new DigitCharacterRule(1));
// require at least 1 non-alphanumeric char
charRule.getRules().add(new NonAlphanumericCharacterRule(1));
// require at least 1 upper case char
charRule.getRules().add(new UppercaseCharacterRule(1));
// require at least 1 lower case char
charRule.getRules().add(new LowercaseCharacterRule(1));
// require at least 3 of the previous rules be met
charRule.setNumberOfCharacteristics(3);
// don't allow alphabetical sequences
AlphabeticalSequenceRule alphaSeqRule = new AlphabeticalSequenceRule();

// don't allow numerical sequences of length 3
NumericalSequenceRule numSeqRule = new NumericalSequenceRule(3);

// don't allow qwerty sequences
QwertySequenceRule qwertySeqRule = new QwertySequenceRule();

// don't allow 4 repeat characters
RepeatCharacterRegexRule repeatRule = new RepeatCharacterRegexRule(4);

// group all rules together in a List
List<Rule> ruleList = new ArrayList<Rule>();
ruleList.add(lengthRule);
ruleList.add(whitespaceRule);
ruleList.add(charRule);
ruleList.add(alphaSeqRule);
ruleList.add(numSeqRule);
ruleList.add(qwertySeqRule);
ruleList.add(repeatRule);

PasswordValidator validator = new PasswordValidator(ruleList);
PasswordData passwordData = new PasswordData(new Password("testpassword"));

RuleResult result = validator.validate(passwordData);
if (result.isValid()) {
  System.out.println("Valid password");
} else {
  System.out.println("Invalid password:");
  for (String msg : validator.getMessages(result)) {
    System.out.println(msg);
  }
}
Marcin Szymczak
  • 11,199
  • 5
  • 55
  • 63