Zend_Form Validator: Konfigurierbare Vorgaben für Passwörter erzwingen

Hier ein Zend Form Validator der dazu genutzt werden kann sichere(re) Passwörter zu erzwingen. Die exakten Anforderungen können hierbei direkt in der Hauptkonfiguration “application.ini” angepasst werden. Hintergrund zur Idee war dass ich in der Entwicklungsumgebung gerne einfache Passwörter zum testen nutzen wollte, im Livebetrieb aber natürlich höhere Ansprüche an den Keyspace gestellt werden.

Einbinden kann man ihn in Zend_Form z.B. wie folgt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class App_Form_User extends Zend_Form
{
public function init()
{
//
// prepare validator
$secPasswdValidator = new Custom_Validate_SecurePassword();
 
//
// password field
$this->addElement('password', 'password', array(
'filters'      => array('StringTrim'),
'required'     => true,
'validators'   => array(
$secPasswdValidator,
array('StringLength', false, array(0,128))
),
'label'        => 'Passwort',
'size'         => 12,
'autocomplete' => 'off'
));
}
}

Damit Zend die Klasse findet, muss “Custom” in application.ini in den autoloaderNamespace eingefügt werden:

1
autoloaderNamespaces[] = "Custom"

Konfiguriert wird er in application.ini wie folgt. Die Werte können in der development Sektion überschrieben werden:

1
2
3
4
5
6
7
[production]
user.password.minLength = 8
user.password.minDigits = 2
user.password.minUpperChars = 1
user.password.minLowerChars = 1
user.password.minSpecialChars = 1
user.password.specialChars = "!-_%"

Nun noch der Validator selbst. Abgelegt würde er z.B. unter library/Custom/Validate/SecurePassword.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
< ?php
 
class Custom_Validate_SecurePassword extends Zend_Validate_Abstract
{
const LENGTH_VIOLATION = 'length';
const DIGITS_VIOLATION = 'digits';
const UPPER_VIOLATION = 'upper';
const LOWER_VIOLATION = 'lower';
const SPECIALCHAR_VIOLATION = 'specialchars';
 
/**
*
* @var array
*/
protected $_messageTemplates = null;
 
/**
* password specification
*
* @var array
*/
protected $_pwConfig = null;
 
public function  __construct()
{
// read password policy from config
try
{
$config = Zend_Registry::get('config');
$this->_pwConfig = $config->user->password;
 
$this->_messageTemplates = array(
self::LENGTH_VIOLATION => "Passwort muss min. "
.$this->_pwConfig->minLength
." Zeichen enthalten",
 
self::DIGITS_VIOLATION => "Passwort muss min. "
.$this->_pwConfig->minDigits
." Ziffern enthalten",
 
self::UPPER_VIOLATION => "Passwort muss min. "
.$this->_pwConfig->minUpperChars
." Großbuchstaben enthalten",
 
self::LOWER_VIOLATION => "Passwort muss min. "
.$this->_pwConfig->minLowerChars
." Kleinbuchstaben enthalten",
 
self::SPECIALCHAR_VIOLATION => "Passwort muss min. "
.$this->_pwConfig->minSpecialChars
." dieser Sonderzeichen enthalten: "
.$this->_pwConfig->specialChars
);
}
catch (Zend_Exception $e)
{
throw $e;
}
}
 
/**
*
* @param strong $value
* @param string|array $context
*/
public function isValid($value, $context = null)
{
// search entities
$foundDigits = 0;
$foundUpperChars = 0;
$foundLowerChars = 0;
$foundSpecialChars = 0;
 
$specialChars = preg_quote($this->_pwConfig->specialChars);
$valueLength = strlen($value);
 
for ($i = 0; $i < $valueLength; $i++)
{
if (preg_match('/^\d{1}$/', $value[$i]))
{
$foundDigits++;
}
else if (preg_match('/^[A-Z]$/', $value[$i]))
{
$foundUpperChars++;
}
else if (preg_match('/^[a-z]$/', $value[$i]))
{
$foundLowerChars++;
}
else if (preg_match('/^['.$specialChars.']$/', $value[$i]))
{
$foundSpecialChars++;
}
}
 
if ($valueLength < $this->_pwConfig->minLength)
{
$this->_error(self::LENGTH_VIOLATION);
return false;
}
else if ($foundDigits < $this->_pwConfig->minDigits)
{
$this->_error(self::DIGITS_VIOLATION);
return false;
}
else if ($foundUpperChars < $this->_pwConfig->minUpperChars)
{
$this->_error(self::UPPER_VIOLATION);
return false;
}
else if ($foundLowerChars < $this->_pwConfig->minLowerChars)
{
$this->_error(self::LOWER_VIOLATION);
return false;
}
else if ($foundLowerChars < $this->_pwConfig->minLowerChars)        {            $this->_error(self::LOWER_VIOLATION);            return false;        }
else if ($foundSpecialChars < $this->_pwConfig->minSpecialChars)
{
$this->_error(self::SPECIALCHAR_VIOLATION);
return false;
}
 
// passed all checks successful!
return true;
}
}
?>

Jegliches Feedback hierzu ist natürlich mehr als willkommen. =)