Skip to content
Snippets Groups Projects
Commit 119c50b2 authored by Olav Morken's avatar Olav Morken
Browse files

SQL authentication source

git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@887 44740490-163a-0410-bde0-09ae8108e29a
parent 1701293d
No related branches found
No related tags found
No related merge requests found
......@@ -2,6 +2,14 @@
$config = array(
'example-sql' => array(
'sqlauth:SQL',
'dsn' => 'pgsql:host=sql.example.org;port=5432;dbname=simplesaml',
'username' => 'simplesaml',
'password' => 'secretpassword',
'query' => 'SELECT "username", "name", "email" FROM "users" WHERE "username" = :username AND "password" = :password',
),
'example-static' => array(
'exampleauth:Static',
'uid' => 'testuser',
......
This file indicates that the default state of this module
is enabled. To disable, create a file named disable in the
same directory as this file.
<?php
/**
* Simple SQL authentication source
*
* This class is an example authentication source which authenticates an user
* against a SQL database.
*
* The following options are required:
* It has the following options:
* - dsn: The DSN which should be used to connect to the database server. Check the various
* database drivers in http://php.net/manual/en/pdo.drivers.php for a description of
* the various DSN formats.
* - username: The username which should be used when connecting to the database server.
* - password: The password which should be used when connecting to the database server.
* - query: The SQL query which should be used to retrieve the user. The parameters :username
* and :password are available. If the username/password is incorrect, the query should
* return no rows. The name of the columns in resultset will be used as attribute names.
* If the query returns multiple rows, they will be merged into the attributes. Duplicate
* values and NULL values will be removed.
*
* Database layout used in examples:
* CREATE TABLE users (
* username VARCHAR(30) NOT NULL PRIMARY KEY,
* password TEXT NOT NULL,
* name TEXT NOT NULL,
* email TEXT NOT NULL
* );
* CREATE TABLE usergroups (
* username TEXT REFERENCES users (username) ON DELETE CASCADE ON UPDATE CASCADE,
* groupname TEXT,
* UNIQUE(username, groupname)
* );
*
* Example - simple setup, PostgreSQL server:
* 'sql-exampleorg' => array(
* 'sqlauth:SQL',
* 'dsn' => 'pgsql:host=sql.example.org;port=5432;dbname=simplesaml',
* 'username' => 'userdb',
* 'password' => 'secretpassword',
* 'query' => 'SELECT username, name, email FROM users WHERE username = :username AND password = :password',
* ),
*
* Example - multiple groups, MySQL server:
* 'sql-exampleorg-groups' => array(
* 'sqlauth:SQL',
* 'dsn' => 'mysql:host=sql.example.org;dbname=simplesaml',
* 'username' => 'userdb',
* 'password' => 'secretpassword',
* 'query' => 'SELECT users.username, name, email, groupname AS groups FROM users LEFT JOIN usergroups ON users.username=usergroups.username WHERE users.username = :username AND password = :password',
* ),
*
* Example query - MD5 of salt + password, stored as salt + md5(salt + password) in password-field, MySQL server:
* SELECT username, name, email
* FROM users
* WHERE username = :username AND SUBSTRING(password, -32) = MD5(CONCAT(SUBSTRING(password, 1, LENGTH(password) - 32), :password))
*
* Example query - MD5 of salt + password, stored as salt + md5(salt + password) in password-field, PostgreSQL server:
* SELECT username, name, email
* FROM users
* WHERE username = :username AND SUBSTRING(password FROM LENGTH(password) - 31) = MD5(SUBSTRING(password FROM 1 FOR LENGTH(password) - 32) || :password)
*
* @package simpleSAMLphp
* @version $Id$
*/
class sspmod_sqlauth_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;
/**
* 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') 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'];
}
/**
* 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)');
try {
$db = new PDO($this->dsn, $this->username, $this->password);
} catch (PDOException $e) {
throw new Exception('sqlauth:' . $this->authId . ': - Failed to connect to \'' .
$this->dsn . '\': '. $e->getMessage());
}
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
$sth = $db->prepare($this->query);
} catch (PDOException $e) {
throw new Exception('sqlauth:' . $this->authId .
': - Failed to prepare query: ' . $e->getMessage());
}
try {
$res = $sth->execute(array('username' => $username, 'password' => $password));
} catch (PDOException $e) {
throw new Exception('sqlauth:' . $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('sqlauth:' . $this->authId . ': Got ' . count($data) .
' rows from database');
if (count($data) === 0) {
/* No rows returned - invalid username/password. */
SimpleSAML_Logger::error('sqlauth:' . $this->authId .
': No rows in result set. Probably wrong username/password.');
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;
}
$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('sqlauth:' . $this->authId . ': Attributes: ' .
implode(',', array_keys($attributes)));
return $attributes;
}
}
?>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment