0
votes

I am writing a regex to validate the password.

Below are the password policies that i want to cover :

  1. Password can only contain numbers,letters and special character .

  2. Minimum length of the password is 10 and maximum length of the password is 32.

  3. Same character should not appear consecutively 10 or more times.

  4. First character can not be special character.

  5. At least 2 character classes are required.(letters, numbers or special characters)

  6. Special characters allowed - !#+,-./:=@_

Regex that will satisfy first 4 conditions except 5th point :

^(?!.*(.)\1{7})[A-Za-z0-9][\w!#+,./:=@-]{7,23}

How i can validate all the policies together in java ?

3
Fight back against these requirements. They make for passwords that are hard for people to remember but easy for computers to guess. In particular, junk the 2 classes required and maximum length.ysth

3 Answers

1
votes

The best way to do this is not to use a regex.

A subroutine with separate conditions is much easier to read and maintain:

sub is_password_valid {
    my ($pw) = @_;
    $pw =~ m{[^a-zA-Z0-9!\#+,\-./:=\@_]}
        and return 0;
    length($pw) >= 10 && length($pw) <= 32
        or return 0;
    $pw =~ /(.)\1{9}/s
        and return 0;
    $pw =~ /^[a-zA-Z0-9]/
        or return 0;
    ($pw =~ /[a-zA-Z]/ + $pw =~ /[0-9]/ + $pw =~ /[^a-zA-Z0-9]/) >= 2
        or return 0;
    return 1;
}

Or alternatively, since this is basically just one big condition:

sub is_password_valid {
    my ($pw) = @_;
    return
        $pw !~ m{[^a-zA-Z0-9!\#+,\-./:=\@_]} &&
        length($pw) >= 10 &&
        length($pw) <= 32 &&
        $pw !~ /(.)\1{9}/s &&
        $pw =~ /^[a-zA-Z0-9]/ &&
        ($pw =~ /[a-zA-Z]/ + $pw =~ /[0-9]/ + $pw =~ /[^a-zA-Z0-9]/) >= 2
    ;
}

If this isn't a toy validator for a homework exercise, you should change your requirements. It doesn't make sense to "validate" passwords with a regex.

You should instead require a minimum length, have a much higher maximum length (maybe 255 characters or so), and not restrict the character set used.

If you want to protect against weak passwords, check against haveibeenpwned and let a password cracker (e.g. hashcat) have a go at it.

0
votes
print "Enter your password please: ";
$p=<STDIN>;chomp $p;

if ( $p =~ /(?!^[\s!#+,-./:=@_])(?=^[\w!#+,-./:=@]{10,32}$)(?=.*[A-Za-z])(?=.*[0-9])(?=.*[!#+,-./:=@_])(?!.*(.)\1{9,}).{10,32}/ ) {print "Welcome"; f=1}
0
votes

Instead of creating a sub returning true for valid password, an opposite sub can instead return zero or more error messages.

The advantage is of course that the error messages could be presented to the user to pinpoint exactly which rules are broken if any.

sub pwerr {
  local $_=pop;
  my $s='!#+,-./:=@_'; #allowed special chars
  grep $_,
  /^[a-z\d$s]+$/i        ? 0 : "Password must be just nums, letters and special chars $s",
  length()>=10           ? 0 : "Minimum length of the password is 10",
  length()<=32           ? 0 : "Maximum length of the password is 32",
  !/(.)\1{9}/            ? 0 : "Same char 10 or more in a row",
  /^[a-zA-Z0-9]/         ? 0 : "First character can not be special character",
  1</[a-z]/i+/\d/+/[$s]/ ? 0 : "At least 2 char classes of letters, numbers or special $s";
}

use strict; use warnings; use Test::More tests => 7;
sub _test_string { join("+",map{/^(\S+)/;$1}pwerr(shift()))||undef }
is(_test_string($$_[0]), $$_[1]) for map[split],grep/\w/,split/\n/,q(
1A!~                               Password+Minimum
abc                                Minimum+At
abcd12345-
abcd12345.
-abcd12345                         First
abcd4444444444                     Same
abcd12345.abcd12345.abcd12345.xyz  Maximum
);