Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions docs/sql.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,11 @@ The authentication can be done in one of two ways:
- Most commonly, as a part of the SQL query itself (ie. using SQL functions to hash a parameterized password and compare that to a value stored in the database).
- Less commonly, just store the hash in the database, retrieve that then compare that hash using PHP's `password_verify()` function to authenticate. This is useful in cases where there is minimal support in the database or to allow the same code to work against many databases without modification. The differences in how this is configured are in a section towards the bottom of this file.

There are two different configuration formats supported ("version 1" and "version 2"). Version 1 is simpler, but is more limited in functionality. Version 2 is more powerful and configurable, but a little more verbose. If you wish to authenticate or gather attributes from more than one SQL database, or need more than one SQL query for authentication then you definitely need Version 2.
There are two different configuration formats ("Version 1" and "Version 2"). We highly recommend using the more powerful and configurable Version 2 configuration. Version 1 is now considered deprecated and support for this legacy configuration format will be removed in a future release.

The Version 1 configuration support comes in two flavours (but identical configurations):
If you are starting out you should use the Version 2 (`sqlauth:SQL2`) configuration format.

- `sqlauth:SQL` uses the legacy Version 1 configuration format and code. Eventually the old code will be phased out, and `sqlauth:SQL` will become a synonym for `sqlauth:SQL1Compat`.
- `sqlauth:SQL1Compat` uses the legacy Version 1 configuration, but applies it to the Version 2 code.

If you are starting out we recommend the Version 2 (`sqlauth:SQL2`) configuration format.
If you have existing Version 1 (`sqlauth:SQL` or `sqlauth:SQL1Compat`) configuration, you should migrate to the new Version 2 (`sqlauth:SQL2`) configuration format.

You enable the module in `config/config.php`.

Expand Down
138 changes: 1 addition & 137 deletions src/Auth/Source/PasswordVerify.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,6 @@

namespace SimpleSAML\Module\sqlauth\Auth\Source;

use SimpleSAML\Assert\Assert;
use SimpleSAML\Error;
use SimpleSAML\Logger;
use SimpleSAML\Module\sqlauth\Auth\Source\SQL;

use function array_key_exists;
use function array_keys;
use function count;
use function implode;
use function is_null;
use function password_verify;
use function sprintf;

/**
* Simple SQL authentication source
*
Expand Down Expand Up @@ -44,129 +31,6 @@
* @package SimpleSAMLphp
*/

class PasswordVerify extends SQL
class PasswordVerify extends PasswordVerify1Compat
{
/**
* The column in the result set containing the passwordhash.
*/
protected string $passwordhashcolumn = 'passwordhash';


/**
* Constructor for this authentication source.
*
* @param array $info Information about this authentication source.
* @param array $config Configuration.
*/
public function __construct(array $info, array $config)
{
// Call the parent constructor first, as required by the interface
parent::__construct($info, $config);

if (array_key_exists('passwordhashcolumn', $config)) {
$this->passwordhashcolumn = $config['passwordhashcolumn'];
}
}


/**
* Attempt to log in using the given username and password.
*
* On a successful login, this function should return the users attributes. On failure,
* it should throw an exception. If the error was caused by the user entering the wrong
* username or password, a \SimpleSAML\Error\Error('WRONGUSERPASS') should be thrown.
*
* Note that both the username and the password are UTF-8 encoded.
*
* @param string $username The username the user wrote.
* @param string $password The password the user wrote.
* @return array Associative array with the users attributes.
*/
protected function login(string $username, string $password): array
{
$this->verifyUserNameWithRegex($username);

$db = $this->connect();
$params = ['username' => $username];
$attributes = [];

$numQueries = count($this->query);
for ($x = 0; $x < $numQueries; $x++) {
$data = $this->executeQuery($db, $this->query[$x], $params);

Logger::info('sqlauth:' . $this->authId . ': Got ' . count($data) .
' rows from database');

/**
* Sanity check, passwordhash must be in each resulting tuple and must have
* the same value in every tuple.
*
* Note that $pwhash will contain the passwordhash value after this loop.
*/
$pwhash = null;
if ($x === 0) {
if (count($data) === 0) {
// No rows returned - invalid username/password
Logger::error(sprintf(
'sqlauth:%s: No rows in result set. Probably wrong username/password.',
$this->authId,
));
throw new Error\Error('WRONGUSERPASS');
}

foreach ($data as $row) {
if (
!array_key_exists($this->passwordhashcolumn, $row)
|| is_null($row[$this->passwordhashcolumn])
) {
Logger::error(sprintf(
'sqlauth:%s: column `%s` must be in every result tuple.',
$this->authId,
$this->passwordhashcolumn,
));
throw new Error\Error('WRONGUSERPASS');
}
if ($pwhash) {
if ($pwhash != $row[$this->passwordhashcolumn]) {
Logger::error(sprintf(
'sqlauth:%s: column %s must be THE SAME in every result tuple.',
$this->authId,
$this->passwordhashcolumn,
));
throw new Error\Error('WRONGUSERPASS');
}
}
$pwhash = $row[$this->passwordhashcolumn];
}

/**
* This should never happen as the count(data) test above would have already thrown.
* But checking twice doesn't hurt.
*/
Assert::notNull($pwhash);

/**
* VERIFICATION!
* Now to check if the password the user supplied is actually valid
*/
if (!password_verify($password, $pwhash)) {
Logger::error(sprintf(
'sqlauth:%s: password is incorrect.',
$this->authId,
));
throw new Error\Error('WRONGUSERPASS');
}
}

$this->extractAttributes($attributes, $data, [$this->passwordhashcolumn]);
}

Logger::info(sprintf(
'sqlauth:%s: Attributes: %s',
$this->authId,
implode(',', array_keys($attributes)),
));

return $attributes;
}
}
11 changes: 10 additions & 1 deletion src/Auth/Source/PasswordVerify1Compat.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@

namespace SimpleSAML\Module\sqlauth\Auth\Source;

use SimpleSAML\Logger;

/**
* @deprecated Use the SQL2 class and the new SQL2 configuration format instead.
*
* @package SimpleSAMLphp
*/

Expand All @@ -18,7 +22,12 @@ class PasswordVerify1Compat extends SQL2
*/
public function __construct(array $info, array $config)
{
/* Transform PasswordVerify (version 1) config to SQL2 config
Logger::warning(
'The sqlauth:PasswordVerify and sqlauth:PasswordVerify1Compat authentication sources are deprecated. ' .
'Please migrate to sqlauth:SQL2 with the new configuration format.',
);

/* Transform PasswordVerify (version 1) config to SQL2 config
* Version 1 supported only one database, but multiple queries. The first query was defined
* to be the "authentication query", all subsequent queries were "attribute queries".
*/
Expand Down
Loading