/
Default.php
331 lines (290 loc) · 9.83 KB
/
Default.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
<?php
/**
* Shopware 5
* Copyright (c) shopware AG
*
* According to our licensing model, this program can be used
* under the terms of the GNU Affero General Public License, version 3.
*
* The texts of the GNU Affero General Public License with an additional
* permission can be found at and in the LICENSE file you have received
* along with this program.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
*
* "Shopware" is a registered trademark of shopware AG.
* The licensing of the program under the AGPLv3 does not imply a
* trademark license. Therefore, any rights, title and interest in
* our trademarks remain entirely with the shopware AG.
*/
use Symfony\Component\HttpFoundation\Session\Session;
/**
* Shopware default auth adapter
*
* <code>
* $authComponent = new Shopware_Components_Auth_Adapter_Default
* $authComponent->authenticate();
* </code>
*/
class Shopware_Components_Auth_Adapter_Default extends Enlight_Components_Auth_Adapter_DbTable
{
/**
* Table to do authentication against
*
* @var string
*/
protected $_tableName = 's_core_auth';
/**
* Column that holds the username
*
* @var string
*/
protected $_identityColumn = 'username';
/**
* Column that holds the password
*
* @var string
*/
protected $_credentialColumn = 'password';
/**
* Array with conditions that have to be true in auth request
*
* @var array
*/
protected $conditions = ['active=1', '(lockeduntil <= NOW() OR lockeduntil IS NULL)'];
/**
* Column that holds the expire date
*
* @var string
*/
protected $expiryColumn = 'lastlogin';
/**
* Column that holds the session id
*
* @var string
*/
protected $sessionIdColumn = 'sessionID';
/**
* For bruce force protection - column that holds the date until the login is permitted
*
* @var string
*/
protected $lockedUntilColumn = 'lockeduntil';
/**
* How many seconds is a login is valid?
*
* @var int
*/
protected $expiry = 21600;
/**
* @var Session
*/
private $session;
/**
* Set some properties only available at runtime
*/
public function __construct(Session $session)
{
$this->session = $session;
parent::__construct();
// Add conditions to user queries
foreach ($this->conditions as $condition) {
$this->addCondition($condition);
}
$this->setSessionId($session->getId());
}
/**
* authenticate() - defined by Zend_Auth_Adapter_Interface. This method is called to
* attempt an authentication. Previous to this call, this adapter would have already
* been configured with all necessary information to successfully connect to a database
* table and attempt to find a record matching the provided identity.
*
* @throws Zend_Auth_Adapter_Exception if answering the authentication query is impossible
*
* @return Zend_Auth_Result
*/
public function authenticate()
{
$result = parent::authenticate();
$select = $this->_zendDb->select();
$select->from($this->_tableName);
$select->where($this->_zendDb->quoteIdentifier($this->_identityColumn, true) . ' = ?', $this->_identity);
$user = $this->_zendDb->fetchRow($select, [], Zend_Db::FETCH_OBJ);
if ($result->isValid()) {
// Check if user role is active
$sql = 'SELECT enabled FROM s_core_auth_roles WHERE id = ?';
if ($this->_zendDb->fetchOne($sql, [$user->roleID]) == false) {
return new Zend_Auth_Result(
Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND,
$this->_identity,
[]
);
}
$this->session->migrate(true);
$this->setSessionId($this->session->getId());
$this->updateExpiry();
$this->updateSessionId();
// Reset failed login count
$this->setFailedLogins(0);
} elseif ($user) {
// If more than 4 previous failed logins lock account for n * failedlogins seconds
if ($user->failedlogins >= 4) {
$lockedUntil = new Zend_Date();
$lockedUntil->addSecond($this->lockSeconds * $user->failedlogins);
$this->setLockedUntil($lockedUntil);
}
// Increase number of failed logins
$this->setFailedLogins($user->failedlogins + 1);
if (isset($lockedUntil)) {
return new Zend_Auth_Result(
-4,
$this->_identity,
['lockedUntil' => $lockedUntil]
);
}
}
return $result;
}
/**
* @deprecated in 5.6, will be private in 5.8
*
* @param string $plaintext
* @param string $hash
* @param string $encoderName
*
* @return void
*/
public function rehash($plaintext, $hash, $encoderName)
{
$newHash = Shopware()->PasswordEncoder()->reencodePassword($plaintext, $hash, $encoderName);
if ($newHash === $hash) {
return;
}
$this->_zendDb->update(
$this->_tableName,
[$this->_credentialColumn => $newHash],
$this->_zendDb->quoteInto(
$this->_zendDb->quoteIdentifier($this->_identityColumn, true) . ' = ?',
$this->_identity
)
);
}
/**
* Used for updating to new algorithm for the future
*
* @param string $plaintext
* @param string $defaultEncoderName
*
* @return void
*/
public function updateHash($plaintext, $defaultEncoderName)
{
$newHash = Shopware()->PasswordEncoder()->encodePassword($plaintext, $defaultEncoderName);
$this->_zendDb->update(
$this->_tableName,
['encoder' => $defaultEncoderName, $this->_credentialColumn => $newHash],
$this->_zendDb->quoteInto(
$this->_zendDb->quoteIdentifier($this->_identityColumn, true) . ' = ?',
$this->_identity
)
);
}
/**
* @return void
*/
protected function updateExpiry()
{
if ($this->expiryColumn === null) {
return;
}
$user = $this->getResultRowObject();
if (!\is_object($user)) {
return;
}
$this->_zendDb->update(
$this->_tableName,
[$this->expiryColumn => Zend_Date::now()],
$this->_zendDb->quoteInto(
$this->_zendDb->quoteIdentifier($this->_identityColumn, true) . ' = ?',
$user->username
)
);
}
/**
* Set the property failed logins to a new value
*
* @param int $number
*
* @return Shopware_Components_Auth_Adapter_Default
*/
protected function setFailedLogins($number)
{
$this->_zendDb->update(
$this->_tableName,
['failedlogins' => $number],
$this->_zendDb->quoteInto(
$this->_zendDb->quoteIdentifier($this->_identityColumn, true) . ' = ?',
$this->_identity
)
);
return $this;
}
/**
* _authenticateCreateSelect() - This method creates a Zend_Db_Select object that
* is completely configured to be queried against the database.
*
* @return Zend_Db_Select
*/
protected function _authenticateCreateSelect()
{
// get select
$dbSelect = clone $this->getDbSelect();
$dbSelect->from($this->_tableName, ['*'])
->where($this->_zendDb->quoteIdentifier($this->_identityColumn, true) . ' = ?', $this->_identity);
return $dbSelect;
}
/**
* _authenticateValidateResult() - This method attempts to validate that
* the record in the resultset is indeed a record that matched the
* identity provided to this adapter.
*
* @param array $resultIdentity
*
* @return Zend_Auth_Result
*/
protected function _authenticateValidateResult($resultIdentity)
{
if ($this->_credentialColumn == $this->expiryColumn) {
if ($this->_credential->toString('YYYY-MM-dd HH:mm:ss') >= $resultIdentity[$this->_credentialColumn]) {
$passwordValid = false;
} else {
$passwordValid = true;
}
} else {
$encoderName = $resultIdentity['encoder'];
$plaintext = $this->_credential;
$hash = $resultIdentity[$this->_credentialColumn];
$passwordValid = Shopware()->PasswordEncoder()->isPasswordValid($plaintext, $hash, $encoderName);
if ($passwordValid) {
$defaultEncoderName = Shopware()->PasswordEncoder()->getDefaultPasswordEncoderName();
if ($encoderName !== $defaultEncoderName) {
$this->updateHash($plaintext, $defaultEncoderName);
} else {
$this->rehash($plaintext, $hash, $encoderName);
}
}
}
if (!$passwordValid) {
$this->_authenticateResultInfo['code'] = Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID;
$this->_authenticateResultInfo['messages'][] = 'Supplied credential is invalid.';
return $this->_authenticateCreateAuthResult();
}
$this->_resultRow = $resultIdentity;
$this->_authenticateResultInfo['code'] = Zend_Auth_Result::SUCCESS;
$this->_authenticateResultInfo['messages'][] = 'Authentication successful.';
return $this->_authenticateCreateAuthResult();
}
}