1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the CRUDlexUser package. |
5
|
|
|
* |
6
|
|
|
* (c) Philip Lehmann-Böhm <[email protected]> |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace CRUDlex; |
13
|
|
|
|
14
|
|
|
use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface; |
15
|
|
|
use Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder; |
16
|
|
|
use CRUDlex\AbstractData; |
17
|
|
|
use CRUDlex\Entity; |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* This class setups CRUDlex with some events so the passwords get salted and |
21
|
|
|
* hashed properly. |
22
|
|
|
*/ |
23
|
|
|
class UserSetup |
24
|
|
|
{ |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* The encoder to use. |
28
|
|
|
*/ |
29
|
|
|
protected $encoder; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* Gets a closure for possibly generating a password hash in the entity. |
33
|
|
|
* |
34
|
|
|
* @param AbstractData $data |
35
|
|
|
* the AbstractData instance managing the users |
36
|
|
|
* |
37
|
|
|
* @param string $passwordField |
38
|
|
|
* the Entity fieldname of the password hash |
39
|
|
|
* |
40
|
|
|
* @param string $saltField |
41
|
|
|
* the Entity fieldname of the password hash salt |
42
|
|
|
*/ |
43
|
|
|
protected function getPWHashFunction(AbstractData $data, $passwordField, $saltField) |
44
|
|
|
{ |
45
|
|
|
$that = $this; |
46
|
|
|
return function(Entity $entity) use ($data, $passwordField, $saltField, $that) { |
47
|
|
|
$password = $entity->get($passwordField); |
48
|
|
|
|
49
|
|
|
if (!$password) { |
50
|
|
|
return true; |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
$salt = $entity->get($saltField); |
54
|
|
|
$newSalt = $that->possibleGenSalt($salt, $entity, $saltField); |
55
|
|
|
|
56
|
|
|
$passwordHash = $this->encoder->encodePassword($password, $salt); |
57
|
|
|
|
58
|
|
|
$doGenerateHash = $that->doGenerateHash($data, $entity, $passwordField, $password, $newSalt); |
59
|
|
|
|
60
|
|
|
if ($doGenerateHash) { |
61
|
|
|
$entity->set($passwordField, $passwordHash); |
62
|
|
|
} |
63
|
|
|
return true; |
64
|
|
|
}; |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* Constructor. |
69
|
|
|
* |
70
|
|
|
* @param PasswordEncoderInterface $encoder |
71
|
|
|
* the encoder to use, defaults to BCryptPasswordEncoder if null is given |
72
|
|
|
*/ |
73
|
|
|
public function __construct(PasswordEncoderInterface $encoder = null) |
74
|
|
|
{ |
75
|
|
|
$this->encoder = $encoder; |
76
|
|
|
if ($this->encoder === null) { |
77
|
|
|
$this->encoder = new BCryptPasswordEncoder(13); |
|
|
|
|
78
|
|
|
} |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* Generates a new salt if the given salt is null. |
83
|
|
|
* |
84
|
|
|
* @param string $salt |
85
|
|
|
* the salt to override if null |
86
|
|
|
* @param Entity |
87
|
|
|
* the entity getting the new salt |
88
|
|
|
* @param string $saltField |
89
|
|
|
* the field holding the salt in the entity |
90
|
|
|
* |
91
|
|
|
* @return boolean |
92
|
|
|
* true if a new salt was generated |
93
|
|
|
*/ |
94
|
|
|
public function possibleGenSalt(&$salt, Entity $entity, $saltField) |
95
|
|
|
{ |
96
|
|
|
if (!$salt) { |
97
|
|
|
$salt = $this->getSalt(40); |
98
|
|
|
$entity->set($saltField, $salt); |
99
|
|
|
return true; |
100
|
|
|
} |
101
|
|
|
return false; |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
/** |
105
|
|
|
* Determines whether the entity needs a new hash generated. |
106
|
|
|
* |
107
|
|
|
* @param AbstractData $data |
108
|
|
|
* the CRUDlex data instance of the user entity |
109
|
|
|
* @param Entity $entity |
110
|
|
|
* the entity |
111
|
|
|
* @param string $passwordField |
112
|
|
|
* the field holding the password hash in the entity |
113
|
|
|
* @param string $password |
114
|
|
|
* the current password hash |
115
|
|
|
* @param boolean $newSalt |
116
|
|
|
* whether a new password hash salt was generated |
117
|
|
|
* |
118
|
|
|
* @return boolean |
119
|
|
|
* true if the entity needs a new hash |
120
|
|
|
*/ |
121
|
|
|
public function doGenerateHash(AbstractData $data, Entity $entity, $passwordField, $password, $newSalt) |
122
|
|
|
{ |
123
|
|
|
$doGenerateHash = true; |
124
|
|
|
$id = $entity->get('id'); |
125
|
|
|
if ($id !== null) { |
126
|
|
|
$oldEntity = $data->get($entity->get('id')); |
127
|
|
|
$doGenerateHash = $oldEntity->get($passwordField) !== $password || $newSalt; |
128
|
|
|
} |
129
|
|
|
return $doGenerateHash; |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
/** |
133
|
|
|
* Generates a random salt of the given length. |
134
|
|
|
* |
135
|
|
|
* @param int $len |
136
|
|
|
* the desired length |
137
|
|
|
* |
138
|
|
|
* @return string |
139
|
|
|
* a random salt of the given length |
140
|
|
|
*/ |
141
|
|
|
public function getSalt($len) |
142
|
|
|
{ |
143
|
|
|
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`~!@#$%^&*()-=_+'; |
144
|
|
|
$l = strlen($chars) - 1; |
145
|
|
|
$str = ''; |
146
|
|
|
for ($i = 0; $i < $len; ++$i) { |
147
|
|
|
$str .= $chars[mt_rand(0, $l)]; |
148
|
|
|
} |
149
|
|
|
return $str; |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
/** |
153
|
|
|
* Setups CRUDlex with some events so the passwords get salted and |
154
|
|
|
* hashed properly. |
155
|
|
|
* |
156
|
|
|
* @param AbstractData $data |
157
|
|
|
* the AbstractData instance managing the users |
158
|
|
|
* |
159
|
|
|
* @param string $passwordField |
160
|
|
|
* the Entity fieldname of the password hash |
161
|
|
|
* |
162
|
|
|
* @param string $saltField |
163
|
|
|
* the Entity fieldname of the password hash salt |
164
|
|
|
*/ |
165
|
|
|
public function addEvents(AbstractData $data, $passwordField = 'password', $saltField = 'salt') |
166
|
|
|
{ |
167
|
|
|
|
168
|
|
|
$that = $this; |
169
|
|
|
$saltGenFunction = function(Entity $entity) use ($saltField, $that) { |
170
|
|
|
$salt = $that->getSalt(40); |
171
|
|
|
$entity->set($saltField, $salt); |
172
|
|
|
return true; |
173
|
|
|
}; |
174
|
|
|
|
175
|
|
|
$data->getEvents()->push('before', 'create', $saltGenFunction); |
176
|
|
|
|
177
|
|
|
$pwHashFunction = $this->getPWHashFunction($data, $passwordField, $saltField); |
178
|
|
|
|
179
|
|
|
$data->getEvents()->push('before', 'create', $pwHashFunction); |
180
|
|
|
$data->getEvents()->push('before', 'update', $pwHashFunction); |
181
|
|
|
|
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
} |
185
|
|
|
|
This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.