mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
Prevent credentials from being leaked in backtrace in some instances (#9817)
* Prevent credentials from being leak in backtrace in some instances Particularly before the user is authenticated * fix test
This commit is contained in:
@@ -52,9 +52,9 @@ class ADAuthorizationAuthorizer extends MysqlAuthorizer
|
||||
}
|
||||
}
|
||||
|
||||
public function authenticate($username, $password)
|
||||
public function authenticate($credentials)
|
||||
{
|
||||
if ($this->userExists($username)) {
|
||||
if (isset($credentials['username']) && $this->userExists($credentials['username'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -18,19 +18,19 @@ class ActiveDirectoryAuthorizer extends AuthorizerBase
|
||||
protected $ldap_connection;
|
||||
protected $is_bound = false; // this variable tracks if bind has been called so we don't call it multiple times
|
||||
|
||||
public function authenticate($username, $password)
|
||||
public function authenticate($credentials)
|
||||
{
|
||||
$this->connect();
|
||||
|
||||
if ($this->ldap_connection) {
|
||||
// bind with sAMAccountName instead of full LDAP DN
|
||||
if ($username && $password && ldap_bind($this->ldap_connection, $username . '@' . Config::get('auth_ad_domain'), $password)) {
|
||||
if (!empty($credentials['username']) && !empty($credentials['password']) && ldap_bind($this->ldap_connection, $credentials['username'] . '@' . Config::get('auth_ad_domain'), $credentials['password'])) {
|
||||
$this->is_bound = true;
|
||||
// group membership in one of the configured groups is required
|
||||
if (Config::get('auth_ad_require_groupmembership', true)) {
|
||||
// cycle through defined groups, test for memberOf-ship
|
||||
foreach (Config::get('auth_ad_groups', array()) as $group => $level) {
|
||||
if ($this->userInGroup($username, $group)) {
|
||||
if ($this->userInGroup($credentials['username'], $group)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ class ActiveDirectoryAuthorizer extends AuthorizerBase
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($password) || $password == '') {
|
||||
if (empty($credentials['password'])) {
|
||||
throw new AuthenticationException('A password is required');
|
||||
} elseif (Config::get('auth_ad_debug', false)) {
|
||||
ldap_get_option($this->ldap_connection, LDAP_OPT_DIAGNOSTIC_MESSAGE, $extended_error);
|
||||
@@ -209,12 +209,15 @@ class ActiveDirectoryAuthorizer extends AuthorizerBase
|
||||
ldap_set_option($this->ldap_connection, LDAP_OPT_PROTOCOL_VERSION, 3);
|
||||
}
|
||||
|
||||
public function bind($username = null, $password = null)
|
||||
public function bind($credentials)
|
||||
{
|
||||
if (!$this->ldap_connection) {
|
||||
$this->connect();
|
||||
}
|
||||
|
||||
$username = $credentials['username'] ?? null;
|
||||
$password = $credentials['password'] ?? null;
|
||||
|
||||
if (Config::has('auth_ad_binduser') && Config::has('auth_ad_bindpassword')) {
|
||||
$username = Config::get('auth_ad_binduser');
|
||||
$password = Config::get('auth_ad_bindpassword');
|
||||
|
@@ -12,9 +12,9 @@ class HttpAuthAuthorizer extends MysqlAuthorizer
|
||||
protected static $CAN_UPDATE_PASSWORDS = 0;
|
||||
protected static $AUTH_IS_EXTERNAL = 1;
|
||||
|
||||
public function authenticate($username, $password)
|
||||
public function authenticate($credentials)
|
||||
{
|
||||
if ($this->userExists($username)) {
|
||||
if (isset($credentials['username']) && $this->userExists($credentials['username'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -76,9 +76,9 @@ class LdapAuthorizationAuthorizer extends AuthorizerBase
|
||||
}
|
||||
}
|
||||
|
||||
public function authenticate($username, $password)
|
||||
public function authenticate($credentials)
|
||||
{
|
||||
if ($this->userExists($username)) {
|
||||
if (isset($credentials['username']) && $this->userExists($credentials['username'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -10,12 +10,13 @@ class LdapAuthorizer extends AuthorizerBase
|
||||
{
|
||||
protected $ldap_connection;
|
||||
|
||||
public function authenticate($username, $password)
|
||||
public function authenticate($credentials)
|
||||
{
|
||||
$connection = $this->getLdapConnection(true);
|
||||
|
||||
if ($username) {
|
||||
if ($password && ldap_bind($connection, $this->getFullDn($username), $password)) {
|
||||
if (!empty($credentials['username'])) {
|
||||
$username = $credentials['username'];
|
||||
if (!empty($credentials['password']) && ldap_bind($connection, $this->getFullDn($username), $credentials['password'])) {
|
||||
$ldap_groups = $this->getGroupList();
|
||||
if (empty($ldap_groups)) {
|
||||
// no groups, don't check membership
|
||||
@@ -44,7 +45,7 @@ class LdapAuthorizer extends AuthorizerBase
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($password) || $password == '') {
|
||||
if (empty($credentials['password'])) {
|
||||
throw new AuthenticationException('A password is required');
|
||||
}
|
||||
|
||||
@@ -321,7 +322,7 @@ class LdapAuthorizer extends AuthorizerBase
|
||||
}
|
||||
}
|
||||
|
||||
public function bind($username = null, $password = null)
|
||||
public function bind($credentials)
|
||||
{
|
||||
if (Config::get('auth_ldap_debug')) {
|
||||
ldap_set_option(null, LDAP_OPT_DEBUG_LEVEL, 7);
|
||||
@@ -329,11 +330,14 @@ class LdapAuthorizer extends AuthorizerBase
|
||||
|
||||
$this->connect();
|
||||
|
||||
$username = $credentials['username'] ?? null;
|
||||
$password = $credentials['password'] ?? null;
|
||||
|
||||
if ((Config::has('auth_ldap_binduser') || Config::has('auth_ldap_binddn')) && Config::has('auth_ldap_bindpassword')) {
|
||||
$username = Config::get('auth_ldap_binddn', $this->getFullDn(Config::get('auth_ldap_binduser')));
|
||||
$password = Config::get('auth_ldap_bindpassword');
|
||||
} elseif ($username) {
|
||||
$username = $this->getFullDn($username);
|
||||
} elseif (!empty($credentials['username'])) {
|
||||
$username = $this->getFullDn($credentials['username']);
|
||||
}
|
||||
|
||||
// With specified bind user
|
||||
|
@@ -15,9 +15,12 @@ class MysqlAuthorizer extends AuthorizerBase
|
||||
protected static $CAN_UPDATE_USER = 1;
|
||||
protected static $CAN_UPDATE_PASSWORDS = 1;
|
||||
|
||||
public function authenticate($username, $password)
|
||||
public function authenticate($credentials)
|
||||
{
|
||||
$hash = User::thisAuth()->where('username', $username)->value('password');
|
||||
$username = $credentials['username'] ?? null;
|
||||
$password = $credentials['password'] ?? null;
|
||||
|
||||
$hash = User::thisAuth()->where(['username' => $username])->value('password');
|
||||
|
||||
// check for old passwords
|
||||
if (strlen($hash) == 32) {
|
||||
|
@@ -20,11 +20,11 @@ class RadiusAuthorizer extends MysqlAuthorizer
|
||||
$this->radius = new Radius(Config::get('radius.hostname'), Config::get('radius.secret'), Config::get('radius.suffix'), Config::get('radius.timeout'), Config::get('radius.port'));
|
||||
}
|
||||
|
||||
public function authenticate($username, $password)
|
||||
public function authenticate($credentials)
|
||||
{
|
||||
global $debug;
|
||||
|
||||
if (empty($username)) {
|
||||
if (empty($credentials['username'])) {
|
||||
throw new AuthenticationException('Username is required');
|
||||
}
|
||||
|
||||
@@ -32,8 +32,9 @@ class RadiusAuthorizer extends MysqlAuthorizer
|
||||
$this->radius->setDebug(true);
|
||||
}
|
||||
|
||||
if ($this->radius->accessRequest($username, $password) === true) {
|
||||
$this->addUser($username, $password, Config::get('radius.default_level', 1));
|
||||
$password = $credentials['password'] ?? null;
|
||||
if ($this->radius->accessRequest($credentials['username'], $password) === true) {
|
||||
$this->addUser($credentials['username'], $password, Config::get('radius.default_level', 1));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -42,9 +42,9 @@ class SSOAuthorizer extends MysqlAuthorizer
|
||||
protected static $CAN_UPDATE_PASSWORDS = 0;
|
||||
protected static $AUTH_IS_EXTERNAL = 1;
|
||||
|
||||
public function authenticate($username, $password)
|
||||
public function authenticate($credentials)
|
||||
{
|
||||
if (empty($username)) {
|
||||
if (empty($credentials['username'])) {
|
||||
throw new AuthenticationException('$config[\'sso\'][\'user_attr\'] was not found or was empty');
|
||||
}
|
||||
|
||||
@@ -57,10 +57,10 @@ class SSOAuthorizer extends MysqlAuthorizer
|
||||
$level = $this->authSSOCalculateLevel();
|
||||
|
||||
// User has already been approved by the authenicator so if automatic user create/update is enabled, do it
|
||||
if (Config::get('sso.create_users') && !$this->userExists($username)) {
|
||||
$this->addUser($username, null, $level, $email, $realname, $can_modify_passwd, $description ? $description : 'SSO User');
|
||||
} elseif (Config::get('sso.update_users') && $this->userExists($username)) {
|
||||
$this->updateUser($this->getUserid($username), $realname, $level, $can_modify_passwd, $email);
|
||||
if (Config::get('sso.create_users') && !$this->userExists($credentials['username'])) {
|
||||
$this->addUser($credentials['username'], null, $level, $email, $realname, $can_modify_passwd, $description ? $description : 'SSO User');
|
||||
} elseif (Config::get('sso.update_users') && $this->userExists($credentials['username'])) {
|
||||
$this->updateUser($this->getUserid($credentials['username']), $realname, $level, $can_modify_passwd, $email);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@@ -27,6 +27,7 @@ namespace LibreNMS;
|
||||
|
||||
use App\Models\GraphType;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Support\Arr;
|
||||
use LibreNMS\DB\Eloquent;
|
||||
|
||||
class Config
|
||||
@@ -130,6 +131,18 @@ class Config
|
||||
return $curr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset a config setting
|
||||
* or multiple
|
||||
*
|
||||
* @param string|array $key
|
||||
*/
|
||||
public static function forget($key)
|
||||
{
|
||||
global $config;
|
||||
Arr::forget($config, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a setting from a device, if that is not set,
|
||||
* fall back to the global config setting prefixed by $global_prefix
|
||||
|
@@ -10,12 +10,11 @@ interface Authorizer
|
||||
* Authenticate the user and password.
|
||||
* Some Authorizer methods may only check username.
|
||||
*
|
||||
* @param $username
|
||||
* @param $password
|
||||
* @param array $credentials
|
||||
* @return true throws an Exception on failure
|
||||
* @throws AuthenticationException thrown if the username or password is invalid
|
||||
*/
|
||||
public function authenticate($username, $password);
|
||||
public function authenticate($credentials);
|
||||
|
||||
/**
|
||||
* Check if a $username exists.
|
||||
|
@@ -62,7 +62,7 @@ class LegacyUserProvider implements UserProvider
|
||||
$legacy_user = LegacyAuth::get()->getUser($identifier);
|
||||
error_reporting(-1);
|
||||
|
||||
return $this->fetchUserByName($legacy_user['username']);
|
||||
return $this->retrieveByCredentials(['username' => $legacy_user['username']]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,17 +107,6 @@ class LegacyUserProvider implements UserProvider
|
||||
$user->timestamps = $timestamps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a user by the given credentials.
|
||||
*
|
||||
* @param array $credentials
|
||||
* @return \Illuminate\Contracts\Auth\Authenticatable|null
|
||||
*/
|
||||
public function retrieveByCredentials(array $credentials)
|
||||
{
|
||||
return $this->fetchUserByName($credentials['username'], $credentials['password']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a user against the given credentials.
|
||||
*
|
||||
@@ -133,16 +122,11 @@ class LegacyUserProvider implements UserProvider
|
||||
|
||||
try {
|
||||
// try authentication methods
|
||||
// collect username and password
|
||||
$password = null;
|
||||
if (isset($credentials['username']) && isset($credentials['password'])) {
|
||||
$username = $credentials['username'];
|
||||
$password = $credentials['password'];
|
||||
} elseif ($authorizer->authIsExternal()) {
|
||||
$username = $authorizer->getExternalUsername();
|
||||
if ($authorizer->authIsExternal()) {
|
||||
$credentials['username'] = $authorizer->getExternalUsername();
|
||||
}
|
||||
|
||||
if (!isset($username) || !$authorizer->authenticate($username, $password)) {
|
||||
if (empty($credentials['username']) || !$authorizer->authenticate($credentials)) {
|
||||
throw new AuthenticationException('Invalid Credentials');
|
||||
}
|
||||
|
||||
@@ -168,13 +152,12 @@ class LegacyUserProvider implements UserProvider
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch user by username from legacy auth, update it or add it to the db then return it.
|
||||
* Retrieve a user by the given credentials.
|
||||
*
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @return User|null
|
||||
* @param array $credentials
|
||||
* @return \Illuminate\Contracts\Auth\Authenticatable|null
|
||||
*/
|
||||
protected function fetchUserByName($username, $password = null)
|
||||
public function retrieveByCredentials(array $credentials)
|
||||
{
|
||||
error_reporting(0);
|
||||
|
||||
@@ -183,9 +166,10 @@ class LegacyUserProvider implements UserProvider
|
||||
|
||||
// ldap based auth we should bind before using, otherwise searches may fail due to anonymous bind
|
||||
if (method_exists($auth, 'bind')) {
|
||||
$auth->bind($username, $password);
|
||||
$auth->bind($credentials);
|
||||
}
|
||||
|
||||
$username = $credentials['username'] ?? null;
|
||||
$auth_id = $auth->getUserid($username);
|
||||
$new_user = $auth->getUser($auth_id);
|
||||
|
||||
@@ -196,7 +180,7 @@ class LegacyUserProvider implements UserProvider
|
||||
try {
|
||||
error_reporting(0);
|
||||
|
||||
$auth->authenticate($username, $password);
|
||||
$auth->authenticate($credentials);
|
||||
$auth_id = $auth->getUserid($username);
|
||||
$new_user = $auth->getUser($auth_id);
|
||||
|
||||
|
@@ -69,7 +69,8 @@
|
||||
"suggest": {
|
||||
"ext-memcached": "Required if you utilize distributed polling",
|
||||
"ext-posix": "Allows for additional validation tests",
|
||||
"ext-mysqlnd": "*"
|
||||
"ext-mysqlnd": "*",
|
||||
"ext-ldap": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"exclude-from-classmap": [
|
||||
|
@@ -14,7 +14,7 @@ if (LegacyAuth::user()->isDemoUser()) {
|
||||
demo_account();
|
||||
} else {
|
||||
if ($_POST['action'] == 'changepass') {
|
||||
if (LegacyAuth::get()->authenticate(LegacyAuth::user()->username, $_POST['old_pass'])) {
|
||||
if (LegacyAuth::get()->authenticate(['username' => LegacyAuth::user()->username, 'password' => $_POST['old_pass']])) {
|
||||
if ($_POST['new_pass'] == '' || $_POST['new_pass2'] == '') {
|
||||
$changepass_message = 'Password must not be blank.';
|
||||
} elseif ($_POST['new_pass'] == $_POST['new_pass2']) {
|
||||
|
@@ -101,7 +101,7 @@ try {
|
||||
echo PHP_EOL;
|
||||
|
||||
echo "Authenticate user $test_username: \n";
|
||||
$auth = $authorizer->authenticate($test_username, $test_password);
|
||||
$auth = $authorizer->authenticate(['username' => $test_username, 'password' => $test_password]);
|
||||
unset($test_password);
|
||||
|
||||
if ($auth) {
|
||||
|
@@ -26,7 +26,7 @@
|
||||
namespace LibreNMS\Tests;
|
||||
|
||||
use LibreNMS\Authentication\LegacyAuth;
|
||||
use LibreNMS\Exceptions\AuthenticationException;
|
||||
use LibreNMS\Config;
|
||||
|
||||
class AuthSSOTest extends DBTestCase
|
||||
{
|
||||
@@ -37,10 +37,9 @@ class AuthSSOTest extends DBTestCase
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
global $config;
|
||||
|
||||
$this->original_auth_mech = $config['auth_mechanism'];
|
||||
$config['auth_mechanism'] = 'sso';
|
||||
$this->original_auth_mech = Config::get('auth_mechanism');
|
||||
Config::set('auth_mechanism', 'sso');
|
||||
|
||||
$this->server = $_SERVER;
|
||||
}
|
||||
@@ -48,32 +47,29 @@ class AuthSSOTest extends DBTestCase
|
||||
// Set up an SSO config for tests
|
||||
public function basicConfig()
|
||||
{
|
||||
global $config;
|
||||
|
||||
$config['sso']['mode'] = 'env';
|
||||
$config['sso']['create_users'] = true;
|
||||
$config['sso']['update_users'] = true;
|
||||
$config['sso']['trusted_proxies'] = array('127.0.0.1', '::1');
|
||||
$config['sso']['user_attr'] = 'REMOTE_USER';
|
||||
$config['sso']['realname_attr'] = 'displayName';
|
||||
$config['sso']['email_attr'] = 'mail';
|
||||
$config['sso']['descr_attr'] = null;
|
||||
$config['sso']['level_attr'] = null;
|
||||
$config['sso']['group_strategy'] = 'static';
|
||||
$config['sso']['group_attr'] = 'member';
|
||||
$config['sso']['group_filter'] = '/(.*)/i';
|
||||
$config['sso']['group_delimiter'] = ';';
|
||||
$config['sso']['group_level_map'] = null;
|
||||
$config['sso']['static_level'] = -1;
|
||||
Config::set('sso.mode', 'env');
|
||||
Config::set('sso.create_users', true);
|
||||
Config::set('sso.update_users', true);
|
||||
Config::set('sso.trusted_proxies', ['127.0.0.1', '::1']);
|
||||
Config::set('sso.user_attr', 'REMOTE_USER');
|
||||
Config::set('sso.realname_attr', 'displayName');
|
||||
Config::set('sso.email_attr', 'mail');
|
||||
Config::set('sso.descr_attr', null);
|
||||
Config::set('sso.level_attr', null);
|
||||
Config::set('sso.group_strategy', 'static');
|
||||
Config::set('sso.group_attr', 'member');
|
||||
Config::set('sso.group_filter', '/(.*)/i');
|
||||
Config::set('sso.group_delimiter', ';');
|
||||
Config::set('sso.group_level_map', null);
|
||||
Config::set('sso.static_level', -1);
|
||||
}
|
||||
|
||||
// Set up $_SERVER in env mode
|
||||
public function basicEnvironmentEnv()
|
||||
{
|
||||
global $config;
|
||||
unset($_SERVER);
|
||||
|
||||
$config['sso']['mode'] = 'env';
|
||||
Config::set('sso.mode', 'env');
|
||||
|
||||
$_SERVER['REMOTE_ADDR'] = '::1';
|
||||
$_SERVER['REMOTE_USER'] = 'test';
|
||||
@@ -86,10 +82,9 @@ class AuthSSOTest extends DBTestCase
|
||||
// Set up $_SERVER in header mode
|
||||
public function basicEnvironmentHeader()
|
||||
{
|
||||
global $config;
|
||||
unset($_SERVER);
|
||||
|
||||
$config['sso']['mode'] = 'header';
|
||||
Config::set('sso.mode', 'header');
|
||||
|
||||
$_SERVER['REMOTE_ADDR'] = '::1';
|
||||
$_SERVER['REMOTE_USER'] = bin2hex(openssl_random_pseudo_bytes(16));
|
||||
@@ -125,92 +120,84 @@ class AuthSSOTest extends DBTestCase
|
||||
// Excercise general auth flow
|
||||
public function testValidAuthNoCreateUpdate()
|
||||
{
|
||||
global $config;
|
||||
|
||||
$this->basicConfig();
|
||||
$a = LegacyAuth::reset();
|
||||
|
||||
$config['sso']['create_users'] = false;
|
||||
$config['sso']['update_users'] = false;
|
||||
Config::set('sso.create_users', false);
|
||||
Config::set('sso.update_users', false);
|
||||
|
||||
// Create a random username and store it with the defaults
|
||||
$this->basicEnvironmentEnv();
|
||||
$user = $this->makeBreakUser();
|
||||
$this->assertTrue($a->authenticate($user, null));
|
||||
$this->assertTrue($a->authenticate(['username' => $user]));
|
||||
|
||||
// Retrieve it and validate
|
||||
$dbuser = $a->getUser($a->getUserid($user));
|
||||
$this->assertFalse($a->authSSOGetAttr($config['sso']['realname_attr']) === $dbuser['realname']);
|
||||
$this->assertFalse($a->authSSOGetAttr(Config::get('sso.realname_attr')) === $dbuser['realname']);
|
||||
$this->assertFalse($dbuser['level'] === "0");
|
||||
$this->assertFalse($a->authSSOGetAttr($config['sso']['email_attr']) === $dbuser['email']);
|
||||
$this->assertFalse($a->authSSOGetAttr(Config::get('sso.email_attr')) === $dbuser['email']);
|
||||
}
|
||||
|
||||
// Excercise general auth flow with creation enabled
|
||||
public function testValidAuthCreateOnly()
|
||||
{
|
||||
global $config;
|
||||
|
||||
$this->basicConfig();
|
||||
$a = LegacyAuth::reset();
|
||||
|
||||
$config['sso']['create_users'] = true;
|
||||
$config['sso']['update_users'] = false;
|
||||
Config::set('sso.create_users', true);
|
||||
Config::set('sso.update_users', false);
|
||||
|
||||
// Create a random username and store it with the defaults
|
||||
$this->basicEnvironmentEnv();
|
||||
$user = $this->makeBreakUser();
|
||||
$this->assertTrue($a->authenticate($user, null));
|
||||
$this->assertTrue($a->authenticate(['username' => $user]));
|
||||
|
||||
// Retrieve it and validate
|
||||
$dbuser = $a->getUser($a->getUserid($user));
|
||||
$this->assertTrue($a->authSSOGetAttr($config['sso']['realname_attr']) === $dbuser['realname']);
|
||||
$this->assertTrue($a->authSSOGetAttr(Config::get('sso.realname_attr')) === $dbuser['realname']);
|
||||
$this->assertTrue($dbuser['level'] == -1);
|
||||
$this->assertTrue($a->authSSOGetAttr($config['sso']['email_attr']) === $dbuser['email']);
|
||||
$this->assertTrue($a->authSSOGetAttr(Config::get('sso.email_attr')) === $dbuser['email']);
|
||||
|
||||
// Change a few things and reauth
|
||||
$_SERVER['mail'] = 'test@example.net';
|
||||
$_SERVER['displayName'] = 'Testier User';
|
||||
$config['sso']['static_level'] = 10;
|
||||
$this->assertTrue($a->authenticate($user, null));
|
||||
Config::set('sso.static_level', 10);
|
||||
$this->assertTrue($a->authenticate(['username' => $user]));
|
||||
|
||||
// Retrieve it and validate the update was not persisted
|
||||
$dbuser = $a->getUser($a->getUserid($user));
|
||||
$this->assertFalse($a->authSSOGetAttr($config['sso']['realname_attr']) === $dbuser['realname']);
|
||||
$this->assertFalse($a->authSSOGetAttr(Config::get('sso.realname_attr')) === $dbuser['realname']);
|
||||
$this->assertFalse($dbuser['level'] === "10");
|
||||
$this->assertFalse($a->authSSOGetAttr($config['sso']['email_attr']) === $dbuser['email']);
|
||||
$this->assertFalse($a->authSSOGetAttr(Config::get('sso.email_attr')) === $dbuser['email']);
|
||||
}
|
||||
|
||||
// Excercise general auth flow with updates enabled
|
||||
public function testValidAuthUpdate()
|
||||
{
|
||||
global $config;
|
||||
|
||||
$this->basicConfig();
|
||||
$a = LegacyAuth::reset();
|
||||
|
||||
// Create a random username and store it with the defaults
|
||||
$this->basicEnvironmentEnv();
|
||||
$user = $this->makeBreakUser();
|
||||
$this->assertTrue($a->authenticate($user, null));
|
||||
$this->assertTrue($a->authenticate(['username' => $user]));
|
||||
|
||||
// Change a few things and reauth
|
||||
$_SERVER['mail'] = 'test@example.net';
|
||||
$_SERVER['displayName'] = 'Testier User';
|
||||
$config['sso']['static_level'] = 10;
|
||||
$this->assertTrue($a->authenticate($user, null));
|
||||
Config::set('sso.static_level', 10);
|
||||
$this->assertTrue($a->authenticate(['username' => $user]));
|
||||
|
||||
// Retrieve it and validate the update persisted
|
||||
$dbuser = $a->getUser($a->getUserid($user));
|
||||
$this->assertTrue($a->authSSOGetAttr($config['sso']['realname_attr']) === $dbuser['realname']);
|
||||
$this->assertTrue($a->authSSOGetAttr(Config::get('sso.realname_attr')) === $dbuser['realname']);
|
||||
$this->assertTrue($dbuser['level'] == 10);
|
||||
$this->assertTrue($a->authSSOGetAttr($config['sso']['email_attr']) === $dbuser['email']);
|
||||
$this->assertTrue($a->authSSOGetAttr(Config::get('sso.email_attr')) === $dbuser['email']);
|
||||
}
|
||||
|
||||
// Check some invalid authentication modes
|
||||
public function testBadAuth()
|
||||
{
|
||||
global $config;
|
||||
|
||||
$this->basicConfig();
|
||||
$a = LegacyAuth::reset();
|
||||
|
||||
@@ -218,20 +205,18 @@ class AuthSSOTest extends DBTestCase
|
||||
unset($_SERVER);
|
||||
|
||||
$this->expectException('LibreNMS\Exceptions\AuthenticationException');
|
||||
$a->authenticate(null, null);
|
||||
$a->authenticate([]);
|
||||
|
||||
$this->basicEnvironmentHeader();
|
||||
unset($_SERVER);
|
||||
|
||||
$this->expectException('LibreNMS\Exceptions\AuthenticationException');
|
||||
$a->authenticate(null, null);
|
||||
$a->authenticate([]);
|
||||
}
|
||||
|
||||
// Test some missing attributes
|
||||
public function testNoAttribute()
|
||||
{
|
||||
global $config;
|
||||
|
||||
$this->basicConfig();
|
||||
$a = LegacyAuth::reset();
|
||||
|
||||
@@ -239,13 +224,13 @@ class AuthSSOTest extends DBTestCase
|
||||
unset($_SERVER['displayName']);
|
||||
unset($_SERVER['mail']);
|
||||
|
||||
$this->assertTrue($a->authenticate($this->makeBreakUser(), null));
|
||||
$this->assertTrue($a->authenticate(['username' => $this->makeBreakUser()]));
|
||||
|
||||
$this->basicEnvironmentHeader();
|
||||
unset($_SERVER['HTTP_DISPLAYNAME']);
|
||||
unset($_SERVER['HTTP_MAIL']);
|
||||
|
||||
$this->assertTrue($a->authenticate($this->makeBreakUser(), null));
|
||||
$this->assertTrue($a->authenticate(['username' => $this->makeBreakUser()]));
|
||||
}
|
||||
|
||||
// Document the modules current behaviour, so that changes trigger test failures
|
||||
@@ -264,8 +249,6 @@ class AuthSSOTest extends DBTestCase
|
||||
|
||||
public function testGetExternalUserName()
|
||||
{
|
||||
global $config;
|
||||
|
||||
$this->basicConfig();
|
||||
$a = LegacyAuth::reset();
|
||||
|
||||
@@ -278,42 +261,41 @@ class AuthSSOTest extends DBTestCase
|
||||
$this->basicEnvironmentEnv();
|
||||
|
||||
// Missing pointer to attribute
|
||||
unset($config['sso']['user_attr']);
|
||||
Config::forget('sso.user_attr');
|
||||
$this->assertNull($a->getExternalUsername());
|
||||
$this->basicEnvironmentEnv();
|
||||
|
||||
// Non-existant attribute
|
||||
$config['sso']['user_attr'] = 'foobar';
|
||||
Config::set('sso.user_attr', 'foobar');
|
||||
$this->assertNull($a->getExternalUsername());
|
||||
$this->basicEnvironmentEnv();
|
||||
|
||||
// null pointer to attribute
|
||||
$config['sso']['user_attr'] = null;
|
||||
Config::set('sso.user_attr', null);
|
||||
$this->assertNull($a->getExternalUsername());
|
||||
$this->basicEnvironmentEnv();
|
||||
|
||||
// null attribute
|
||||
$config['sso']['user_attr'] = 'REMOTE_USER';
|
||||
Config::set('sso.user_attr', 'REMOTE_USER');
|
||||
$_SERVER['REMOTE_USER'] = null;
|
||||
$this->assertNull($a->getExternalUsername());
|
||||
}
|
||||
|
||||
public function testGetAttr()
|
||||
{
|
||||
global $config;
|
||||
$a = LegacyAuth::reset();
|
||||
|
||||
$_SERVER['HTTP_VALID_ATTR'] = 'string';
|
||||
$_SERVER['alsoVALID-ATTR'] = 'otherstring';
|
||||
|
||||
$config['sso']['mode'] = 'env';
|
||||
Config::set('sso.mode', 'env');
|
||||
$this->assertNull($a->authSSOGetAttr('foobar'));
|
||||
$this->assertNull($a->authSSOGetAttr(null));
|
||||
$this->assertNull($a->authSSOGetAttr(1));
|
||||
$this->assertIsString($a->authSSOGetAttr('alsoVALID-ATTR'));
|
||||
$this->assertIsString($a->authSSOGetAttr('HTTP_VALID_ATTR'));
|
||||
|
||||
$config['sso']['mode'] = 'header';
|
||||
Config::set('sso.mode', 'header');
|
||||
$this->assertNull($a->authSSOGetAttr('foobar'));
|
||||
$this->assertNull($a->authSSOGetAttr(null));
|
||||
$this->assertNull($a->authSSOGetAttr(1));
|
||||
@@ -323,10 +305,9 @@ class AuthSSOTest extends DBTestCase
|
||||
|
||||
public function testTrustedProxies()
|
||||
{
|
||||
global $config;
|
||||
$a = LegacyAuth::reset();
|
||||
|
||||
$config['sso']['trusted_proxies'] = array('127.0.0.1', '::1', '2001:630:50::/48', '8.8.8.0/25');
|
||||
Config::set('sso.trusted_proxies', ['127.0.0.1', '::1', '2001:630:50::/48', '8.8.8.0/25']);
|
||||
|
||||
// v4 valid CIDR
|
||||
$_SERVER['REMOTE_ADDR'] = '8.8.8.8';
|
||||
@@ -365,7 +346,7 @@ class AuthSSOTest extends DBTestCase
|
||||
$this->assertFalse($a->authSSOProxyTrusted());
|
||||
|
||||
// Not a list
|
||||
$config['sso']['trusted_proxies'] = '8.8.8.0/25';
|
||||
Config::set('sso.trusted_proxies', '8.8.8.0/25');
|
||||
$_SERVER['REMOTE_ADDR'] = '8.8.8.8';
|
||||
$this->assertFalse($a->authSSOProxyTrusted());
|
||||
|
||||
@@ -376,42 +357,41 @@ class AuthSSOTest extends DBTestCase
|
||||
|
||||
public function testLevelCaulculationFromAttr()
|
||||
{
|
||||
global $config;
|
||||
$a = LegacyAuth::reset();
|
||||
|
||||
$config['sso']['mode'] = 'env';
|
||||
$config['sso']['group_strategy'] = 'attribute';
|
||||
Config::set('sso.mode', 'env');
|
||||
Config::set('sso.group_strategy', 'attribute');
|
||||
|
||||
//Integer
|
||||
$config['sso']['level_attr'] = 'level';
|
||||
Config::set('sso.level_attr', 'level');
|
||||
$_SERVER['level'] = 9;
|
||||
$this->assertTrue($a->authSSOCalculateLevel() === 9);
|
||||
|
||||
//String
|
||||
$config['sso']['level_attr'] = 'level';
|
||||
Config::set('sso.level_attr', 'level');
|
||||
$_SERVER['level'] = "9";
|
||||
$this->assertTrue($a->authSSOCalculateLevel() === 9);
|
||||
|
||||
//Invalid String
|
||||
$config['sso']['level_attr'] = 'level';
|
||||
Config::set('sso.level_attr', 'level');
|
||||
$_SERVER['level'] = 'foobar';
|
||||
$this->expectException('LibreNMS\Exceptions\AuthenticationException');
|
||||
$a->authSSOCalculateLevel();
|
||||
|
||||
//null
|
||||
$config['sso']['level_attr'] = 'level';
|
||||
Config::set('sso.level_attr', 'level');
|
||||
$_SERVER['level'] = null;
|
||||
$this->expectException('LibreNMS\Exceptions\AuthenticationException');
|
||||
$a->authSSOCalculateLevel();
|
||||
|
||||
//Unset pointer
|
||||
unset($config['sso']['level_attr']);
|
||||
Config::forget('sso.level_attr');
|
||||
$_SERVER['level'] = "9";
|
||||
$this->expectException('LibreNMS\Exceptions\AuthenticationException');
|
||||
$a->authSSOCalculateLevel();
|
||||
|
||||
//Unset attr
|
||||
$config['sso']['level_attr'] = 'level';
|
||||
Config::set('sso.level_attr', 'level');
|
||||
unset($_SERVER['level']);
|
||||
$this->expectException('LibreNMS\Exceptions\AuthenticationException');
|
||||
$a->authSSOCalculateLevel();
|
||||
@@ -419,17 +399,15 @@ class AuthSSOTest extends DBTestCase
|
||||
|
||||
public function testGroupParsing()
|
||||
{
|
||||
global $config;
|
||||
|
||||
$this->basicConfig();
|
||||
$a = LegacyAuth::reset();
|
||||
|
||||
$this->basicEnvironmentEnv();
|
||||
|
||||
$config['sso']['group_strategy'] = 'map';
|
||||
$config['sso']['group_delimiter'] = ';';
|
||||
$config['sso']['group_attr'] = 'member';
|
||||
$config['sso']['group_level_map'] = array('librenms-admins' => 10, 'librenms-readers' => 1, 'librenms-billingcontacts' => 5);
|
||||
Config::set('sso.group_strategy', 'map');
|
||||
Config::set('sso.group_delimiter', ';');
|
||||
Config::set('sso.group_attr', 'member');
|
||||
Config::set('sso.group_level_map', ['librenms-admins' => 10, 'librenms-readers' => 1, 'librenms-billingcontacts' => 5]);
|
||||
$_SERVER['member'] = "librenms-admins;librenms-readers;librenms-billingcontacts;unrelatedgroup;confluence-admins";
|
||||
|
||||
// Valid options
|
||||
@@ -458,47 +436,45 @@ class AuthSSOTest extends DBTestCase
|
||||
$_SERVER['member'] = "librenms-admins;librenms-readers;librenms-billingcontacts;unrelatedgroup;confluence-admins";
|
||||
|
||||
// Empty
|
||||
$config['sso']['group_level_map'] = array();
|
||||
Config::set('sso.group_level_map', []);
|
||||
$this->assertTrue($a->authSSOParseGroups() === 0);
|
||||
|
||||
// Not associative
|
||||
$config['sso']['group_level_map'] = array('foo', 'bar', 'librenms-admins');
|
||||
Config::set('sso.group_level_map', ['foo', 'bar', 'librenms-admins']);
|
||||
$this->assertTrue($a->authSSOParseGroups() === 0);
|
||||
|
||||
// Null
|
||||
$config['sso']['group_level_map'] = null;
|
||||
Config::set('sso.group_level_map', null);
|
||||
$this->assertTrue($a->authSSOParseGroups() === 0);
|
||||
|
||||
// Unset
|
||||
unset($config['sso']['group_level_map']);
|
||||
Config::forget('sso.group_level_map');
|
||||
$this->assertTrue($a->authSSOParseGroups() === 0);
|
||||
|
||||
// No delimiter
|
||||
unset($config['sso']['group_delimiter']);
|
||||
Config::forget('sso.group_delimiter');
|
||||
$this->assertTrue($a->authSSOParseGroups() === 0);
|
||||
|
||||
// Test group filtering by regex
|
||||
$config['sso']['group_filter'] = "/confluence-(.*)/i";
|
||||
$config['sso']['group_delimiter'] = ';';
|
||||
$config['sso']['group_level_map'] = array('librenms-admins' => 10, 'librenms-readers' => 1, 'librenms-billingcontacts' => 5, 'confluence-admins' => 7);
|
||||
Config::set('sso.group_filter', "/confluence-(.*)/i");
|
||||
Config::set('sso.group_delimiter', ';');
|
||||
Config::set('sso.group_level_map', ['librenms-admins' => 10, 'librenms-readers' => 1, 'librenms-billingcontacts' => 5, 'confluence-admins' => 7]);
|
||||
$this->assertTrue($a->authSSOParseGroups() === 7);
|
||||
|
||||
// Test group filtering by empty regex
|
||||
$config['sso']['group_filter'] = "";
|
||||
Config::set('sso.group_filter', "");
|
||||
$this->assertTrue($a->authSSOParseGroups() === 10);
|
||||
|
||||
// Test group filtering by null regex
|
||||
$config['sso']['group_filter'] = null;
|
||||
Config::set('sso.group_filter', null);
|
||||
$this->assertTrue($a->authSSOParseGroups() === 10);
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
parent::tearDown();
|
||||
global $config;
|
||||
|
||||
$config['auth_mechanism'] = $this->original_auth_mech;
|
||||
unset($config['sso']);
|
||||
Config::set('auth_mechanism', $this->original_auth_mech);
|
||||
Config::forget('sso');
|
||||
$this->breakUser();
|
||||
|
||||
$_SERVER = $this->server;
|
||||
|
Reference in New Issue
Block a user