Updated config structure for auth backends, and added config backend

This commit is contained in:
Lukas Metzger 2018-04-03 13:43:56 +02:00
parent ee1b081447
commit 0e6a90fa8f
7 changed files with 89 additions and 20 deletions

View file

@ -18,8 +18,9 @@ $defaultConfig = [
'config' => null 'config' => null
], ],
'authentication' => [ 'authentication' => [
'default' => [ 'native' => [
'plugin' => 'native', 'plugin' => 'native',
'prefix' => 'default',
'config' => null 'config' => null
] ]
], ],

View file

@ -43,18 +43,19 @@ class UserAuth
public function authenticate(string $username, string $password) : int public function authenticate(string $username, string $password) : int
{ {
if (strpos($username, '/') === false) { // no explicit backend specification if (strpos($username, '/') === false) { // no explicit backend specification
$backend = 'default'; $prefix = 'default';
$name = $username; $name = $username;
} else { } else {
$parts = preg_split('/\//', $username, 2); $parts = preg_split('/\//', $username, 2);
$backend = $parts[0]; $prefix = $parts[0];
$name = $parts[1]; $name = $parts[1];
} }
$this->logger->debug('Trying to authenticate with info', ['backend' => $backend, 'name' => $name]); $this->logger->debug('Trying to authenticate with info', ['prefix' => $prefix, 'name' => $name]);
try { try {
if ($this->authenticateBackend($backend, $name, $password)) { $backend = '';
if ($this->authenticateBackend($prefix, $name, $password, $backend)) {
return $this->localUser($backend, $name, $password); return $this->localUser($backend, $name, $password);
} else { } else {
return -1; return -1;
@ -71,23 +72,32 @@ class UserAuth
* @param $backend The name of the backend to use * @param $backend The name of the backend to use
* @param $username The username to use * @param $username The username to use
* @param $password The password to use * @param $password The password to use
* @param $backendId Output to return the backend id used
* *
* @return bool true if authentication successfull false otherwise * @return bool true if authentication successfull false otherwise
* *
* @throws \Exceptions\PluginNotFoundExecption if no matching backend can be found * @throws \Exceptions\PluginNotFoundExecption if no matching backend can be found
*/ */
private function authenticateBackend(string $backend, string $username, string $password) : bool private function authenticateBackend(string $backend, string $username, string $password, string &$backendId) : bool
{ {
$config = $this->c['config']['authentication']; $config = $this->c['config']['authentication'];
if (!array_key_exists($backend, $config)) { // Check if backend is configured for prefix $configForPrefix = array_filter($config, function ($v, $k) use ($backend) {
return $backend === $v['prefix'];
}, ARRAY_FILTER_USE_BOTH);
if (count($configForPrefix) === 0) { // Check if backend is configured for prefix
$this->logger->warning('No authentication backend configured for prefix', ['prefix' => $backend]); $this->logger->warning('No authentication backend configured for prefix', ['prefix' => $backend]);
throw new PluginNotFoundException('No authentication backend configured for this user.'); throw new PluginNotFoundException('No authentication backend configured for this user.');
} elseif (count($configForPrefix) > 1) {
$this->logger->error('Two authentication backends configured for prefix.', ['prefix' => $backend]);
} }
$plugin = $config[$backend]['plugin']; $backendId = array_keys($configForPrefix)[0];
$plugin = $config[$backendId]['plugin'];
$pluginClass = '\\Plugins\\UserAuth\\' . $plugin; $pluginClass = '\\Plugins\\UserAuth\\' . $plugin;
$pluginConfig = $config[$backend]['config']; $pluginConfig = $config[$backendId]['config'];
if (!class_exists($pluginClass)) { // Check if given backend class exists if (!class_exists($pluginClass)) { // Check if given backend class exists
$this->logger->error('The configured UserAuth plugin does not exist', ['prefix' => $backend, 'plugin' => $plugin]); $this->logger->error('The configured UserAuth plugin does not exist', ['prefix' => $backend, 'plugin' => $plugin]);
@ -102,7 +112,7 @@ class UserAuth
throw new PluginNotFoundException('The authentication request can not be processed.'); throw new PluginNotFoundException('The authentication request can not be processed.');
} }
$this->logger->debug("UserAuth plugin was loaded", ['plugin' => $plugin, 'prefix' => $backend]); $this->logger->debug("UserAuth plugin was loaded", ['plugin' => $plugin, 'prefix' => $backend, 'backend' => $backendId]);
return $backendObj->authenticate($username, $password); return $backendObj->authenticate($username, $password);
} }

View file

@ -22,8 +22,8 @@ interface InterfaceUserAuth
/** /**
* Authenticate user. * Authenticate user.
* *
* @param $username The key for the entry * @param $username The username for authentication
* @param $password The value for the entry * @param $password The password for authentication
* *
* @return true if valid false otherwise * @return true if valid false otherwise
*/ */

View file

@ -0,0 +1,54 @@
<?php
namespace Plugins\UserAuth;
require '../vendor/autoload.php';
/**
* This provides a simple user auth mechanism where users can be
* stored in the config file. The config property therefore should
* be a array mapping usernames to results of password_hash()
*/
class Config implements InterfaceUserAuth
{
/** @var \Monolog\Logger */
private $logger;
/** @var \PDO */
private $db;
/** @var array */
private $userList;
/**
* Construct the object
*
* @param $logger Monolog logger instance for error handling
* @param $db Database connection
* @param $config The configuration for the Plugin if any was provided
*/
public function __construct(\Monolog\Logger $logger, \PDO $db, array $config = null)
{
$this->logger = $logger;
$this->db = $db;
$this->userList = $config ? $config : [];
}
/**
* Authenticate user.
*
* @param $username The username for authentication
* @param $password The password for authentication
*
* @return true if valid false otherwise
*/
public function authenticate(string $username, string $password) : bool
{
if (!array_key_exists($username, $this->userList)) {
return false;
}
return password_verify($password, $this->userList[$username]);
}
}

View file

@ -5,8 +5,8 @@ namespace Plugins\UserAuth;
require '../vendor/autoload.php'; require '../vendor/autoload.php';
/** /**
* This interface provides the neccessary functions for * This provides the native authentication done in the
* a user authentication backend. * PDNSManager database.
*/ */
class Native implements InterfaceUserAuth class Native implements InterfaceUserAuth
{ {
@ -32,8 +32,8 @@ class Native implements InterfaceUserAuth
/** /**
* Authenticate user. * Authenticate user.
* *
* @param $username The key for the entry * @param $username The username for authentication
* @param $password The value for the entry * @param $password The password for authentication
* *
* @return true if valid false otherwise * @return true if valid false otherwise
*/ */

View file

@ -18,13 +18,17 @@ return [
'path' => '../../test/logfile.log' 'path' => '../../test/logfile.log'
], ],
'authentication' => [ 'authentication' => [
'default' => [ 'native' => [
'plugin' => 'native', 'plugin' => 'native',
'prefix' => 'default',
'config' => null 'config' => null
], ],
'foo' => [ 'foo' => [
'plugin' => 'native', 'plugin' => 'config',
'config' => null 'prefix' => 'foo',
'config' => [
'admin' => '\$2y\$10\$u9ji0cGRpd/doYEF/AztkOP3qmaaDYOGXzs0PmnGbMF7sJYzODDbO'
]
] ]
] ]
]; ];

View file

@ -49,7 +49,7 @@ test.run(async function () {
assert.equal(res.status, 422, 'Status not valid'); assert.equal(res.status, 422, 'Status not valid');
//Try to login with invalid username and password //Try to login with prefix
var res = await req({ var res = await req({
url: '/sessions', url: '/sessions',
method: 'post', method: 'post',