From 5f8d03fe0b3cedacbb4987382ef6b2dbf479fe15 Mon Sep 17 00:00:00 2001 From: Wolfgang Knopki <wolfgang.knopki@hft-stuttgart.de> Date: Thu, 12 Nov 2020 13:33:51 +0100 Subject: [PATCH] added compatibility with simplesamlphp 1.19 --- lib/Auth/Source/SQL.php | 426 ++++++++++++++++++++-------------------- 1 file changed, 216 insertions(+), 210 deletions(-) diff --git a/lib/Auth/Source/SQL.php b/lib/Auth/Source/SQL.php index 5055561..3f7eadd 100644 --- a/lib/Auth/Source/SQL.php +++ b/lib/Auth/Source/SQL.php @@ -12,216 +12,222 @@ * @package simpleSAMLphp * @version $Id$ */ -class sspmod_sqlauthBcrypt_Auth_Source_SQL extends sspmod_core_Auth_UserPassBase { - - - /** - * The DSN we should connect to. - */ - private $dsn; - - - /** - * The username we should connect to the database with. - */ - private $username; - - - /** - * The password we should connect to the database with. - */ - private $password; - - - /** - * The query we should use to retrieve the attributes for the user. - * - * The username and password will be available as :username and :password. - */ - private $query; - - - /** - * The pepper used to generate the password hash. - */ - private $pepper; - - - /** - * The column holding the password hash. - */ - private $hash_column; - - /** - * Constructor for this authentication source. - * - * @param array $info Information about this authentication source. - * @param array $config Configuration. - */ - public function __construct($info, $config) { - assert('is_array($info)'); - assert('is_array($config)'); - - /* Call the parent constructor first, as required by the interface. */ - parent::__construct($info, $config); - - /* Make sure that all required parameters are present. */ - foreach (array('dsn', 'username', 'password', 'query', 'pepper') as $param) { - if (!array_key_exists($param, $config)) { - throw new Exception('Missing required attribute \'' . $param . - '\' for authentication source ' . $this->authId); - } - - if (!is_string($config[$param])) { - throw new Exception('Expected parameter \'' . $param . - '\' for authentication source ' . $this->authId . - ' to be a string. Instead it was: ' . - var_export($config[$param], TRUE)); - } - } - - $this->dsn = $config['dsn']; - $this->username = $config['username']; - $this->password = $config['password']; - $this->query = $config['query']; - $this->pepper = $config['pepper']; - $this->hash_column = $config['hash_column']; - } - - - /** - * Create a database connection. - * - * @return PDO The database connection. - */ - private function connect() { - try { - $db = new PDO($this->dsn, $this->username, $this->password); - } catch (PDOException $e) { - throw new Exception('sqlauthBcrypt:' . $this->authId . - ': - Failed to connect to \'' . $this->dsn . '\': '. $e->getMessage()); - } - - $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - - - $driver = explode(':', $this->dsn, 2); - $driver = strtolower($driver[0]); - - /* Driver specific initialization. */ - switch ($driver) { - case 'mysql': - /* Use UTF-8. */ - $db->exec("SET NAMES 'utf8'"); - break; - case 'pgsql': - /* Use UTF-8. */ - $db->exec("SET NAMES 'UTF8'"); - break; - } - - return $db; - } - - - /** - * 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($username, $password) { - assert('is_string($username)'); - assert('is_string($password)'); - - $db = $this->connect(); - - try { - $sth = $db->prepare($this->query); - } catch (PDOException $e) { - throw new Exception('sqlauthBcrypt:' . $this->authId . - ': - Failed to prepare query: ' . $e->getMessage()); - } - - try { - $res = $sth->execute(array('username' => $username)); - } catch (PDOException $e) { - throw new Exception('sqlauthBcrypt:' . $this->authId . - ': - Failed to execute query: ' . $e->getMessage()); - } - - try { - $data = $sth->fetchAll(PDO::FETCH_ASSOC); - } catch (PDOException $e) { - throw new Exception('sqlauth:' . $this->authId . - ': - Failed to fetch result set: ' . $e->getMessage()); - } - - SimpleSAML_Logger::info('sqlauthBcrypt:' . $this->authId . - ': Got ' . count($data) . ' rows from database'); - - if (count($data) === 0) { - /* No rows returned - invalid username */ - SimpleSAML_Logger::error('sqlauthBcrypt:' . $this->authId . - ': No rows in result set. Wrong username or sqlauthBcrypt is misconfigured.'); - throw new SimpleSAML_Error_Error('WRONGUSERPASS'); - } - - /* Validate stored password hash (must be in first row of resultset) */ - $password_hash = $data[0][$this->hash_column]; - - if ($password_hash !== crypt($password.$this->pepper, $password_hash)) { - /* Invalid password */ - SimpleSAML_Logger::error('sqlauthBcrypt:' . $this->authId . - ': Hash does not match. Wrong password or sqlauthBcrypt is misconfigured.'); - throw new SimpleSAML_Error_Error('WRONGUSERPASS'); - } - - /* Extract attributes. We allow the resultset to consist of multiple rows. Attributes - * which are present in more than one row will become multivalued. NULL values and - * duplicate values will be skipped. All values will be converted to strings. - */ - $attributes = array(); - foreach ($data as $row) { - foreach ($row as $name => $value) { - - if ($value === NULL) { - continue; - } - - if ($name === $this->hash_column) { - /* Don't add password hash to attributes */ - continue; - } - - $value = (string)$value; - - if (!array_key_exists($name, $attributes)) { - $attributes[$name] = array(); - } - - if (in_array($value, $attributes[$name], TRUE)) { - /* Value already exists in attribute. */ - continue; - } - - $attributes[$name][] = $value; - } - } - - SimpleSAML_Logger::info('sqlauthBcrypt:' . $this->authId . - ': Attributes: ' . implode(',', array_keys($attributes))); - - return $attributes; - } +/*class sspmod_sqlauthBcrypt_Auth_Source_SQL extends sspmod_core_Auth_UserPassBase {*/ + +namespace SimpleSAML\Module\sqlauthbcrypt\Auth\Source; + + + +class sql extends \SimpleSAML\Module\core\Auth\UserPassBase { + + /** + * The DSN we should connect to. + */ + private $dsn; + + + /** + * The username we should connect to the database with. + */ + private $username; + + + /** + * The password we should connect to the database with. + */ + private $password; + + + /** + * The query we should use to retrieve the attributes for the user. + * + * The username and password will be available as :username and :password. + */ + private $query; + + + /** + * The pepper used to generate the password hash. + */ + private $pepper; + + + /** + * The column holding the password hash. + */ + private $hash_column; + + /** + * Constructor for this authentication source. + * + * @param array $info Information about this authentication source. + * @param array $config Configuration. + */ + public function __construct($info, $config) { + assert('is_array($info)'); + assert('is_array($config)'); + + /* Call the parent constructor first, as required by the interface. */ + parent::__construct($info, $config); + + /* Make sure that all required parameters are present. */ + foreach (array('dsn', 'username', 'password', 'query', 'pepper') as $param) { + if (!array_key_exists($param, $config)) { + throw new \Exception('Missing required attribute \'' . $param . + '\' for authentication source ' . $this->authId); + } + + if (!is_string($config[$param])) { + throw new \Exception('Expected parameter \'' . $param . + '\' for authentication source ' . $this->authId . + ' to be a string. Instead it was: ' . + var_export($config[$param], TRUE)); + } + } + + $this->dsn = $config['dsn']; + $this->username = $config['username']; + $this->password = $config['password']; + $this->query = $config['query']; + $this->pepper = $config['pepper']; + $this->hash_column = $config['hash_column']; + } + + + /** + * Create a database connection. + * + * @return PDO The database connection. + */ + private function connect() { + try { + $db = new \PDO($this->dsn, $this->username, $this->password); + } catch (\PDOException $e) { + throw new \Exception('sqlauthBcrypt:' . $this->authId . + ': - Failed to connect to \'' . $this->dsn . '\': '. $e->getMessage()); + } + + $db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); + + + $driver = explode(':', $this->dsn, 2); + $driver = strtolower($driver[0]); + + /* Driver specific initialization. */ + switch ($driver) { + case 'mysql': + /* Use UTF-8. */ + $db->exec("SET NAMES 'utf8'"); + break; + case 'pgsql': + /* Use UTF-8. */ + $db->exec("SET NAMES 'UTF8'"); + break; + } + + return $db; + } + + + /** + * 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 { + assert('is_string($username)'); + assert('is_string($password)'); + + $db = $this->connect(); + + try { + $sth = $db->prepare($this->query); + } catch (\PDOException $e) { + throw new \Exception('sqlauthBcrypt:' . $this->authId . + ': - Failed to prepare query: ' . $e->getMessage()); + } + + try { + $res = $sth->execute(array('username' => $username)); + } catch ( \PDOException $e) { + throw new \Exception('sqlauthBcrypt:' . $this->authId . + ': - Failed to execute query: ' . $e->getMessage()); + } + + try { + $data = $sth->fetchAll(\PDO::FETCH_ASSOC); + } catch (\PDOException $e) { + throw new \Exception('sqlauth:' . $this->authId . + ': - Failed to fetch result set: ' . $e->getMessage()); + } + + \SimpleSAML\Logger::info('sqlauthBcrypt:' . $this->authId . + ': Got ' . count($data) . ' rows from database'); + + if (count($data) === 0) { + /* No rows returned - invalid username */ + \SimpleSAML\Logger::error('sqlauthBcrypt:' . $this->authId . + ': No rows in result set. Wrong username or sqlauthBcrypt is misconfigured.'); + throw new \SimpleSAML\Error\Error('WRONGUSERPASS'); + } + + /* Validate stored password hash (must be in first row of resultset) */ + $password_hash = $data[0][$this->hash_column]; + + if ($password_hash !== crypt($password.$this->pepper, $password_hash)) { + /* Invalid password */ + \SimpleSAML\Logger::error('sqlauthBcrypt:' . $this->authId . + ': Hash does not match. Wrong password or sqlauthBcrypt is misconfigured.'); + throw new \SimpleSAML\Error\Error('WRONGUSERPASS'); + } + + /* Extract attributes. We allow the resultset to consist of multiple rows. Attributes + * which are present in more than one row will become multivalued. NULL values and + * duplicate values will be skipped. All values will be converted to strings. + */ + $attributes = array(); + foreach ($data as $row) { + foreach ($row as $name => $value) { + + if ($value === NULL) { + continue; + } + + if ($name === $this->hash_column) { + /* Don't add password hash to attributes */ + continue; + } + + $value = (string)$value; + + if (!array_key_exists($name, $attributes)) { + $attributes[$name] = array(); + } + + if (in_array($value, $attributes[$name], TRUE)) { + /* Value already exists in attribute. */ + continue; + } + + $attributes[$name][] = $value; + } + } + + \SimpleSAML\Logger::info('sqlauthBcrypt:' . $this->authId . + ': Attributes: ' . implode(',', array_keys($attributes))); + + return $attributes; + } } -?> \ No newline at end of file +?> + -- GitLab