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:
Tony Murray
2019-03-05 00:24:14 -06:00
committed by GitHub
parent e17f47a329
commit f4a33c1a34
15 changed files with 146 additions and 162 deletions

View File

@@ -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;
}

View File

@@ -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');

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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.

View File

@@ -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);

View File

@@ -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": [

View File

@@ -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']) {

View File

@@ -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) {

View File

@@ -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;