Skip to content

Commit 4b38aa5

Browse files
Move password_verify_hash_column handling from login into a member function
1 parent 1230b28 commit 4b38aa5

File tree

1 file changed

+88
-54
lines changed

1 file changed

+88
-54
lines changed

src/Auth/Source/SQL2.php

Lines changed: 88 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,89 @@ protected function executeQuery(PDO $db, string $query, array $params): array
396396
}
397397

398398

399+
/**
400+
* Authenticate using the optional password_verify() support against a hash retrieved from the database.
401+
*
402+
* @param string $queryname Name of the auth query being processed
403+
* @param array $queryConfig Configuration from authsources.php for this auth query
404+
* @param array $data Result data from the database query
405+
* @param string $password Password to verify with password_verify()
406+
* @return bool True if password_verify() password verification succeeded, false otherwise
407+
*/
408+
protected function authenticatePasswordVerifyHash(
409+
string $queryname,
410+
array $queryConfig,
411+
array $data,
412+
string $password,
413+
): bool {
414+
// If password_verify_hash_column is not set, we are not using password_verify()
415+
if (!array_key_exists('password_verify_hash_column', $queryConfig)) {
416+
Logger::error(sprintf(
417+
'sqlauth:%s: authenticatePasswordVerifyHash() called but configuration for ' .
418+
'"password_verify_hash_column" not found in query config for query %s.',
419+
$this->authId,
420+
$queryname,
421+
));
422+
throw new Error\Error('WRONGUSERPASS');
423+
} elseif (count($data) < 1) {
424+
// No rows returned, password_verify() cannot succeed
425+
return false;
426+
}
427+
428+
/* This is where we need to run password_verify() if we are using password_verify() to
429+
* authenticate hashed passwords that are only stored in the database. */
430+
$hashColumn = $queryConfig['password_verify_hash_column'];
431+
if (!array_key_exists($hashColumn, $data[0])) {
432+
Logger::error('sqlauth:' . $this->authId . ': Auth query ' . $queryname .
433+
' did not return expected hash column \'' . $hashColumn . '\'');
434+
throw new Error\Error('WRONGUSERPASS');
435+
}
436+
437+
$validPasswordHashFound = false;
438+
$passwordHash = null;
439+
foreach ($data as $row) {
440+
if ((!array_key_exists($hashColumn, $row)) || is_null($row[$hashColumn])) {
441+
Logger::error(sprintf(
442+
'sqlauth:%s: column `%s` must be in every result tuple.',
443+
$this->authId,
444+
$hashColumn,
445+
));
446+
throw new Error\Error('WRONGUSERPASS');
447+
}
448+
if (($passwordHash === null) && (strlen($row[$hashColumn]) > 0)) {
449+
$passwordHash = $row[$hashColumn];
450+
$validPasswordHashFound = true;
451+
} elseif ($passwordHash != $row[$hashColumn]) {
452+
Logger::error(sprintf(
453+
'sqlauth:%s: column %s must be THE SAME in every result tuple.',
454+
$this->authId,
455+
$hashColumn,
456+
));
457+
throw new Error\Error('WRONGUSERPASS');
458+
} elseif (strlen($row[$hashColumn]) === 0) {
459+
Logger::error(sprintf(
460+
'sqlauth:%s: column `%s` must contain a valid password hash.',
461+
$this->authId,
462+
$hashColumn,
463+
));
464+
throw new Error\Error('WRONGUSERPASS');
465+
}
466+
}
467+
468+
if ((!$validPasswordHashFound) || (!password_verify($password, $passwordHash))) {
469+
Logger::error('sqlauth:' . $this->authId . ': Auth query ' . $queryname .
470+
' password verification failed');
471+
/* Authentication with verify_password() failed, however that only means that
472+
* this auth query did not succeed. We should try the next auth query if any. */
473+
return false;
474+
}
475+
476+
Logger::debug('sqlauth:' . $this->authId . ': Auth query ' . $queryname .
477+
' password verification using password_verify() succeeded');
478+
return true;
479+
}
480+
481+
399482
/**
400483
* Attempt to log in using the given username and password.
401484
*
@@ -449,60 +532,11 @@ protected function login(
449532
}
450533

451534
// If we got any rows, the authentication succeeded. If not, try the next query.
452-
if (count($data) > 0) {
453-
/* This is where we need to run password_verify() if we are using password_verify() to
454-
* authenticate hashed passwords that are only stored in the database. */
455-
if (array_key_exists('password_verify_hash_column', $queryConfig)) {
456-
$hashColumn = $queryConfig['password_verify_hash_column'];
457-
if (!array_key_exists($hashColumn, $data[0])) {
458-
Logger::error('sqlauth:' . $this->authId . ': Auth query ' . $queryname .
459-
' did not return expected hash column \'' . $hashColumn . '\'');
460-
throw new Error\Error('WRONGUSERPASS');
461-
}
462-
463-
$validPasswordHashFound = false;
464-
$passwordHash = null;
465-
foreach ($data as $row) {
466-
if ((!array_key_exists($hashColumn, $row)) || is_null($row[$hashColumn])) {
467-
Logger::error(sprintf(
468-
'sqlauth:%s: column `%s` must be in every result tuple.',
469-
$this->authId,
470-
$hashColumn,
471-
));
472-
throw new Error\Error('WRONGUSERPASS');
473-
}
474-
if (($passwordHash === null) && (strlen($row[$hashColumn]) > 0)) {
475-
$passwordHash = $row[$hashColumn];
476-
$validPasswordHashFound = true;
477-
} elseif ($passwordHash != $row[$hashColumn]) {
478-
Logger::error(sprintf(
479-
'sqlauth:%s: column %s must be THE SAME in every result tuple.',
480-
$this->authId,
481-
$hashColumn,
482-
));
483-
throw new Error\Error('WRONGUSERPASS');
484-
} elseif (strlen($row[$hashColumn]) === 0) {
485-
Logger::error(sprintf(
486-
'sqlauth:%s: column `%s` must contain a valid password hash.',
487-
$this->authId,
488-
$hashColumn,
489-
));
490-
throw new Error\Error('WRONGUSERPASS');
491-
}
492-
}
493-
494-
if ((!$validPasswordHashFound) || (!password_verify($password, $passwordHash))) {
495-
Logger::error('sqlauth:' . $this->authId . ': Auth query ' . $queryname .
496-
' password verification failed');
497-
/* Authentication with verify_password() failed, however that only means that
498-
* this auth query did not succeed. We should try the next auth query if any. */
499-
continue;
500-
}
501-
502-
Logger::debug('sqlauth:' . $this->authId . ': Auth query ' . $queryname .
503-
' password verification using password_verify() succeeded');
504-
}
505-
535+
if (
536+
(count($data) > 0) &&
537+
((array_key_exists('password_verify_hash_column', $queryConfig) === false) ||
538+
$this->authenticatePasswordVerifyHash($queryname, $queryConfig, $data, $password))
539+
) {
506540
Logger::debug('sqlauth:' . $this->authId . ': Auth query ' . $queryname .
507541
' succeeded with ' . count($data) . ' rows');
508542
$queryConfig['_winning_auth_query'] = true;

0 commit comments

Comments
 (0)