Version: current

     1 <?php
     2
     3 /**
     4  * This class represents a validator for member passwords.
     5  *
     6  * <code>
     7  * $pwdVal = new PasswordValidator();
     8  * $pwdValidator->minLength(7);
     9  * $pwdValidator->checkHistoricalPasswords(6);
    10  * $pwdValidator->characterStrength('lowercase','uppercase','digits','punctuation');
    11  *
    12  * Member::set_password_validator($pwdValidator);
    13  * </code>
    14  *
    15  * @package sapphire
    16  * @subpackage security
    17  */
    18 class PasswordValidator extends Object {
    19     static $character_strength_tests = array(
    20         'lowercase' => '/[a-z]/',
    21         'uppercase' => '/[A-Z]/',
    22         'digits' => '/[0-9]/',
    23         'punctuation' => '/[^A-Za-z0-9]/',
    24     );
    25
    26     protected $minLength, $minScore, $testNames, $historicalPasswordCount;
    27
    28     /**
    29      * Minimum password length
    30      */
    31     function minLength($minLength) {
    32         $this->minLength = $minLength;
    33     }
    34
    35     /**
    36      * Check the character strength of the password.
    37      *
    38      * Eg: $this->characterStrength(3, array("lowercase", "uppercase", "digits", "punctuation"))
    39      *
    40      * @param $minScore The minimum number of character tests that must pass
    41      * @param $testNames The names of the tests to perform
    42      */
    43     function characterStrength($minScore, $testNames) {
    44         $this->minScore = $minScore;
    45         $this->testNames = $testNames;
    46     }
    47
    48     /**
    49      * Check a number of previous passwords that the user has used, and don't let them change to that.
    50      */
    51     function checkHistoricalPasswords($count) {
    52         $this->historicalPasswordCount = $count;
    53     }
    54
    55     function validate($password, $member) {
    56         $valid = new ValidationResult();
    57
    58         if($this->minLength) {
    59             if(strlen($password) < $this->minLength) $valid->error("Password is too short, it must be 7 or more characters long.", "TOO_SHORT");
    60         }
    61
    62         if($this->minScore) {
    63             $score = 0;
    64             $missedTests = array();
    65             foreach($this->testNames as $name) {
    66                 if(preg_match(self::$character_strength_tests[$name], $password)) $score++;
    67                 else $missedTests[] = $name;
    68             }
    69
    70             if($score < $this->minScore) {
    71                 $valid->error("You need to increase the strength of your passwords by adding some of the following characters: " . implode(", ", $missedTests), "LOW_CHARACTER_STRENGTH");
    72             }
    73         }
    74
    75         if($this->historicalPasswordCount) {
    76             $previousPasswords = DataObject::get("MemberPassword", "\"MemberID\" = $member->ID", "\"Created\" DESC, \"ID\" Desc", "", $this->historicalPasswordCount);
    77             if($previousPasswords) foreach($previousPasswords as $previousPasswords) {
    78                 if($previousPasswords->checkPassword($password)) {
    79                     $valid->error("You've already used that password in the past, please choose a new password", "PREVIOUS_PASSWORD");
    80                     break;
    81                 }
    82             }
    83         }
    84
    85         return $valid;
    86     }
    87
    88 }

[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -