-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: Refactored authorizers to classes (#7497)
* Refactored authorizers to classes * Merge changes for #7335 * ! fix php 5.3 incompatibility * Update ADAuthorizationAuthorizer.php * Fix get_user -> getUser * Rename AuthorizerFactory to Auth, fix interface missing functions * Add phpdocs to all interface methods and normalize the names a bit. * Re-work auth_test.php AD bind tests to work properly with the new class. Reflection is not the nicest tool, but I think it is appropriate here. Handle exceptions more nicely in auth_test.php * Restore AD getUseList fix Not sure how it got removed * fix auth_test.php style
- Loading branch information
Showing
35 changed files
with
2,419 additions
and
2,394 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,354 @@ | ||
<?php | ||
|
||
namespace LibreNMS\Authentication; | ||
|
||
use LibreNMS\Config; | ||
use LibreNMS\Exceptions\AuthenticationException; | ||
|
||
class ADAuthorizationAuthorizer extends AuthorizerBase | ||
{ | ||
protected $ldap_connection; | ||
|
||
public function __construct() | ||
{ | ||
if (! isset($_SESSION['username'])) { | ||
$_SESSION['username'] = ''; | ||
} | ||
|
||
// Disable certificate checking before connect if required | ||
if (Config::has('auth_ad_check_certificates') && | ||
Config::get('auth_ad_check_certificates') == 0) { | ||
putenv('LDAPTLS_REQCERT=never'); | ||
}; | ||
|
||
// Set up connection to LDAP server | ||
$this->ldap_connection = @ldap_connect(Config::get('auth_ad_url')); | ||
if (! $this->ldap_connection) { | ||
echo '<h2>Fatal error while connecting to AD url ' . Config::get('auth_ad_url') . ': ' . ldap_error($this->ldap_connection) . '</h2>'; | ||
exit; | ||
} | ||
|
||
// disable referrals and force ldap version to 3 | ||
ldap_set_option($this->ldap_connection, LDAP_OPT_REFERRALS, 0); | ||
ldap_set_option($this->ldap_connection, LDAP_OPT_PROTOCOL_VERSION, 3); | ||
|
||
// Bind to AD | ||
if (Config::has('auth_ad_binduser') && Config::has('auth_ad_bindpassword')) { | ||
// With specified bind user | ||
if (! ldap_bind($this->ldap_connection, Config::get('auth_ad_binduser') . '@' . Config::get('auth_ad_domain'), Config::get('auth_ad_bindpassword'))) { | ||
echo ldap_error($this->ldap_connection); | ||
} | ||
} else { | ||
// Anonymous | ||
if (! ldap_bind($this->ldap_connection)) { | ||
echo ldap_error($this->ldap_connection); | ||
} | ||
} | ||
} | ||
|
||
public function authenticate($username, $password) | ||
{ | ||
if (isset($_SERVER['REMOTE_USER'])) { | ||
$_SESSION['username'] = mres($_SERVER['REMOTE_USER']); | ||
|
||
if ($this->userExists($_SESSION['username'])) { | ||
$this->addUser($username, null); | ||
return true; | ||
} | ||
|
||
$_SESSION['username'] = Config::get('http_auth_guest'); | ||
return true; | ||
} | ||
|
||
throw new AuthenticationException(); | ||
} | ||
|
||
public function addUser($username, $password, $level = 0, $email = '', $realname = '', $can_modify_passwd = 0, $description = '') | ||
{ | ||
// Check to see if user is already added in the database | ||
if (!$this->userExists($username)) { | ||
$userid = dbInsert(array('username' => $username, 'realname' => $realname, 'email' => $email, 'descr' => $description, 'level' => $level, 'can_modify_passwd' => $can_modify_passwd, 'user_id' => $this->getUserid($username)), 'users'); | ||
if ($userid == false) { | ||
return false; | ||
} else { | ||
foreach (dbFetchRows('select notifications.* from notifications where not exists( select 1 from notifications_attribs where notifications.notifications_id = notifications_attribs.notifications_id and notifications_attribs.user_id = ?) order by notifications.notifications_id desc', array($userid)) as $notif) { | ||
dbInsert(array('notifications_id'=>$notif['notifications_id'],'user_id'=>$userid,'key'=>'read','value'=>1), 'notifications_attribs'); | ||
} | ||
} | ||
return $userid; | ||
} else { | ||
return false; | ||
} | ||
} | ||
|
||
protected function userExistsInDb($username) | ||
{ | ||
$return = dbFetchCell('SELECT COUNT(*) FROM users WHERE username = ?', array($username), true); | ||
return $return; | ||
} | ||
|
||
public function userExists($username, $throw_exception = false) | ||
{ | ||
if ($this->authLdapSessionCacheGet('user_exists')) { | ||
return 1; | ||
} | ||
|
||
$search = ldap_search( | ||
$this->ldap_connection, | ||
Config::get('auth_ad_base_dn'), | ||
get_auth_ad_user_filter($username), | ||
array('samaccountname') | ||
); | ||
$entries = ldap_get_entries($this->ldap_connection, $search); | ||
|
||
if ($entries['count']) { | ||
/* | ||
* Cache positiv result as this will result in more queries which we | ||
* want to speed up. | ||
*/ | ||
$this->authLdapSessionCacheSet('user_exists', 1); | ||
return 1; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
|
||
public function getUserlevel($username) | ||
{ | ||
$userlevel = $this->authLdapSessionCacheGet('userlevel'); | ||
if ($userlevel) { | ||
return $userlevel; | ||
} else { | ||
$userlevel = 0; | ||
} | ||
|
||
// Find all defined groups $username is in | ||
$search = ldap_search( | ||
$this->ldap_connection, | ||
Config::get('auth_ad_base_dn'), | ||
get_auth_ad_user_filter($username), | ||
array('memberOf') | ||
); | ||
$entries = ldap_get_entries($this->ldap_connection, $search); | ||
|
||
// Loop the list and find the highest level | ||
foreach ($entries[0]['memberof'] as $entry) { | ||
$group_cn = $this->getCn($entry); | ||
$auth_ad_groups = Config::get('auth_ad_groups'); | ||
if ($auth_ad_groups[$group_cn]['level'] > $userlevel) { | ||
$userlevel = $auth_ad_groups[$group_cn]['level']; | ||
} | ||
} | ||
|
||
$this->authLdapSessionCacheSet('userlevel', $userlevel); | ||
return $userlevel; | ||
} | ||
|
||
|
||
public function getUserid($username) | ||
{ | ||
$user_id = $this->authLdapSessionCacheGet('userid'); | ||
if (isset($user_id)) { | ||
return $user_id; | ||
} else { | ||
$user_id = -1; | ||
} | ||
|
||
$attributes = array('objectsid'); | ||
$search = ldap_search( | ||
$this->ldap_connection, | ||
Config::get('auth_ad_base_dn'), | ||
get_auth_ad_user_filter($username), | ||
$attributes | ||
); | ||
$entries = ldap_get_entries($this->ldap_connection, $search); | ||
|
||
if ($entries['count']) { | ||
$user_id = preg_replace('/.*-(\d+)$/', '$1', $this->sidFromLdap($entries[0]['objectsid'][0])); | ||
} | ||
|
||
$this->authLdapSessionCacheSet('userid', $user_id); | ||
return $user_id; | ||
} | ||
|
||
|
||
public function deleteUser($userid) | ||
{ | ||
dbDelete('bill_perms', '`user_id` = ?', array($userid)); | ||
dbDelete('devices_perms', '`user_id` = ?', array($userid)); | ||
dbDelete('ports_perms', '`user_id` = ?', array($userid)); | ||
dbDelete('users_prefs', '`user_id` = ?', array($userid)); | ||
dbDelete('users', '`user_id` = ?', array($userid)); | ||
return dbDelete('users', '`user_id` = ?', array($userid)); | ||
} | ||
|
||
|
||
public function getUserlist() | ||
{ | ||
$userlist = array(); | ||
$userhash = array(); | ||
|
||
$ldap_groups = $this->getGroupList(); | ||
|
||
foreach ($ldap_groups as $ldap_group) { | ||
$search_filter = "(memberOf=$ldap_group)"; | ||
if (Config::get('auth_ad_user_filter')) { | ||
$search_filter = "(&{" . Config::get('auth_ad_user_filter') . $search_filter . ")"; | ||
} | ||
$search = ldap_search($this->ldap_connection, Config::get('auth_ad_base_dn'), $search_filter, array('samaccountname','displayname','objectsid','mail')); | ||
$results = ldap_get_entries($this->ldap_connection, $search); | ||
|
||
foreach ($results as $result) { | ||
if (isset($result['samaccountname'][0])) { | ||
$userid = preg_replace( | ||
'/.*-(\d+)$/', | ||
'$1', | ||
$this->sidFromLdap($result['objectsid'][0]) | ||
); | ||
|
||
// don't make duplicates, user may be member of more than one group | ||
$userhash[$result['samaccountname'][0]] = array( | ||
'realname' => $result['displayName'][0], | ||
'user_id' => $userid, | ||
'email' => $result['mail'][0] | ||
); | ||
} | ||
} | ||
} | ||
|
||
foreach (array_keys($userhash) as $key) { | ||
$userlist[] = array( | ||
'username' => $key, | ||
'realname' => $userhash[$key]['realname'], | ||
'user_id' => $userhash[$key]['user_id'], | ||
'email' => $userhash[$key]['email'] | ||
); | ||
} | ||
|
||
return $userlist; | ||
} | ||
|
||
public function getUser($user_id) | ||
{ | ||
// not supported so return 0 | ||
return dbFetchRow('SELECT * FROM `users` WHERE `user_id` = ?', array($user_id), true); | ||
} | ||
|
||
|
||
public function updateUser($user_id, $realname, $level, $can_modify_passwd, $email) | ||
{ | ||
dbUpdate(array('realname' => $realname, 'can_modify_passwd' => $can_modify_passwd, 'email' => $email), 'users', '`user_id` = ?', array($user_id)); | ||
} | ||
|
||
|
||
protected function getFullname($username) | ||
{ | ||
$attributes = array('name'); | ||
$result = ldap_search( | ||
$this->ldap_connection, | ||
Config::get('auth_ad_base_dn'), | ||
get_auth_ad_user_filter($username), | ||
$attributes | ||
); | ||
$entries = ldap_get_entries($this->ldap_connection, $result); | ||
if ($entries['count'] > 0) { | ||
$membername = $entries[0]['name'][0]; | ||
} else { | ||
$membername = $username; | ||
} | ||
|
||
return $membername; | ||
} | ||
|
||
|
||
public function getGroupList() | ||
{ | ||
$ldap_groups = array(); | ||
|
||
// show all Active Directory Users by default | ||
$default_group = 'Users'; | ||
|
||
if (Config::has('auth_ad_group')) { | ||
if (Config::get('auth_ad_group') !== $default_group) { | ||
$ldap_groups[] = Config::get('auth_ad_group'); | ||
} | ||
} | ||
|
||
if (!Config::has('auth_ad_groups') && !Config::has('auth_ad_group')) { | ||
$ldap_groups[] = $this->getDn($default_group); | ||
} | ||
|
||
foreach (Config::get('auth_ad_groups') as $key => $value) { | ||
$ldap_groups[] = $this->getDn($key); | ||
} | ||
|
||
return $ldap_groups; | ||
} | ||
|
||
protected function getDn($samaccountname) | ||
{ | ||
$attributes = array('dn'); | ||
$result = ldap_search( | ||
$this->ldap_connection, | ||
Config::get('auth_ad_base_dn'), | ||
get_auth_ad_group_filter($samaccountname), | ||
$attributes | ||
); | ||
$entries = ldap_get_entries($this->ldap_connection, $result); | ||
if ($entries['count'] > 0) { | ||
return $entries[0]['dn']; | ||
} else { | ||
return ''; | ||
} | ||
} | ||
|
||
protected function getCn($dn) | ||
{ | ||
preg_match('/[^,]*/', $dn, $matches, PREG_OFFSET_CAPTURE, 3); | ||
return $matches[0][0]; | ||
} | ||
|
||
protected function sidFromLdap($sid) | ||
{ | ||
$sidHex = unpack('H*hex', $sid); | ||
$subAuths = unpack('H2/H2/n/N/V*', $sid); | ||
$revLevel = hexdec(substr($sidHex, 0, 2)); | ||
$authIdent = hexdec(substr($sidHex, 4, 12)); | ||
return 'S-'.$revLevel.'-'.$authIdent.'-'.implode('-', $subAuths); | ||
} | ||
|
||
protected function authLdapSessionCacheGet($attr) | ||
{ | ||
$ttl = 300; | ||
if (Config::get('auth_ldap_cache_ttl')) { | ||
$ttl = Config::get('auth_ldap_cache_ttl'); | ||
} | ||
|
||
// auth_ldap cache present in this session? | ||
if (! isset($_SESSION['auth_ldap'])) { | ||
return null; | ||
} | ||
|
||
$cache = $_SESSION['auth_ldap']; | ||
|
||
// $attr present in cache? | ||
if (! isset($cache[$attr])) { | ||
return null; | ||
} | ||
|
||
// Value still valid? | ||
if (time() - $cache[$attr]['last_updated'] >= $ttl) { | ||
return null; | ||
} | ||
|
||
return $cache[$attr]['value']; | ||
} | ||
|
||
|
||
protected function authLdapSessionCacheSet($attr, $value) | ||
{ | ||
$_SESSION['auth_ldap'][$attr]['value'] = $value; | ||
$_SESSION['auth_ldap'][$attr]['last_updated'] = time(); | ||
} | ||
} |
Oops, something went wrong.