* $pwdVal = new PasswordValidator(); * $pwdValidator->minLength(7); * $pwdValidator->checkHistoricalPasswords(6); * $pwdValidator->characterStrength(3, array("lowercase", "uppercase", "digits", "punctuation")); * * Member::set_password_validator($pwdValidator); * * * @package framework * @subpackage security */ class PasswordValidator extends Object { private static $character_strength_tests = array( 'lowercase' => '/[a-z]/', 'uppercase' => '/[A-Z]/', 'digits' => '/[0-9]/', 'punctuation' => '/[^A-Za-z0-9]/', ); protected $minLength, $minScore, $testNames, $historicalPasswordCount; /** * Minimum password length */ public function minLength($minLength) { $this->minLength = $minLength; return $this; } /** * Check the character strength of the password. * * Eg: $this->characterStrength(3, array("lowercase", "uppercase", "digits", "punctuation")) * * @param $minScore The minimum number of character tests that must pass * @param $testNames The names of the tests to perform */ public function characterStrength($minScore, $testNames) { $this->minScore = $minScore; $this->testNames = $testNames; return $this; } /** * Check a number of previous passwords that the user has used, and don't let them change to that. */ public function checkHistoricalPasswords($count) { $this->historicalPasswordCount = $count; return $this; } /** * @param String $password * @param Member $member * @return ValidationResult */ public function validate($password, $member) { $valid = ValidationResult::create(); if($this->minLength) { if(strlen($password) < $this->minLength) { $valid->error( sprintf( _t( 'PasswordValidator.TOOSHORT', 'Password is too short, it must be %s or more characters long' ), $this->minLength ), 'TOO_SHORT' ); } } if($this->minScore) { $score = 0; $missedTests = array(); foreach($this->testNames as $name) { if(preg_match(self::config()->character_strength_tests[$name], $password)) { $score++; } else { $missedTests[] = _t( 'PasswordValidator.STRENGTHTEST' . strtoupper($name), $name, 'The user needs to add this to their password for more complexity' ); } } if($score < $this->minScore) { $valid->error( sprintf( _t( 'PasswordValidator.LOWCHARSTRENGTH', 'Please increase password strength by adding some of the following characters: %s' ), implode(', ', $missedTests) ), 'LOW_CHARACTER_STRENGTH' ); } } if($this->historicalPasswordCount) { $previousPasswords = MemberPassword::get() ->where(array('"MemberPassword"."MemberID"' => $member->ID)) ->sort('"Created" DESC, "ID" DESC') ->limit($this->historicalPasswordCount); if($previousPasswords) foreach($previousPasswords as $previousPasswords) { if($previousPasswords->checkPassword($password)) { $valid->error( _t( 'PasswordValidator.PREVPASSWORD', 'You\'ve already used that password in the past, please choose a new password' ), 'PREVIOUS_PASSWORD' ); break; } } } return $valid; } }