Merge pull request #3531 from wiad/issue-3530

Added auth module combining http authentication and AD authorization
This commit is contained in:
Neil Lathwood 2016-05-26 19:46:26 +01:00
commit 2a1ae6a3f9
2 changed files with 383 additions and 0 deletions

View File

@ -168,3 +168,27 @@ $config['radius']['timeout'] = 3;
$config['radius']['users_purge'] = 14;//Purge users who haven't logged in for 14 days.
$config['radius']['default_level'] = 1;//Set the default user level when automatically creating a user.
```
#### HTTP Authentication / AD Authorization
Config option: `ad-authorization`
This module is a combination of ___http-auth___ and ___active_directory___
LibreNMS will expect the user to have authenticated via your webservice already (e.g. using Kerberos Authentication in Apache) but will use Active Directory lookups to determine and assign the userlevel of a user.
The userlevel will be calculated by using AD group membership information as the ___active_directory___ module does.
The configuration is the same as for the ___active_directory___ module with two extra, optional options: auth_ad_binduser and auth_ad_bindpassword.
These should be set to a AD user with read capabilities in your AD Domain in order to be able to perform searches.
If these options are omitted, the module will attempt an anonymous bind (which then of course must be allowed by your Active Directory server(s)).
There is also one extra option for controlling user information caching: auth_ldap_cache_ttl.
This option allows to control how long user information (user_exists, userid, userlevel) are cached within the PHP Session.
The default value is 300 seconds.
To disable this caching (highly discourage) set this option to 0.
```php
$config['auth_ad_binduser'] = "ad_binduser";
$config['auth_ad_bindpassword'] = "ad_bindpassword";
$config['auth_ldap_cache_ttl'] = 300;
```

View File

@ -0,0 +1,359 @@
<?php
if (! isset ($_SESSION['username'])) {
$_SESSION['username'] = '';
}
// Disable certificate checking before connect if required
if (isset($config['auth_ad_check_certificates']) &&
$config['auth_ad_check_certificates'] == 0) {
putenv('LDAPTLS_REQCERT=never');
};
// Set up connection to LDAP server
$ds = @ldap_connect($config['auth_ad_url']);
if (! $ds) {
echo '<h2>Fatal error while connecting to AD url ' . $config['auth_ad_url'] . ': ' . ldap_error($ds) . '</h2>';
exit;
}
// disable referrals and force ldap version to 3
ldap_set_option($ds, LDAP_OPT_REFERRALS, 0);
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
// Bind to AD
if (isset($config['auth_ad_binduser']) && isset($config['auth_ad_bindpassword'])) {
// With specified bind user
if (! ldap_bind($ds, "${config['auth_ad_binduser']}@${config['auth_ad_domain']}", "${config['auth_ad_bindpassword']}")) {
echo ldap_error($ds);
}
}
else {
// Anonymous
if (! ldap_bind($ds)) {
echo ldap_error($ds);
}
}
function authenticate ($username, $password) {
global $config;
if (isset ($_SERVER['REMOTE_USER'])) {
$_SESSION['username'] = mres ($_SERVER['REMOTE_USER']);
if (user_exists ($_SESSION['username'])) {
adduser($username);
return 1;
}
$_SESSION['username'] = $config['http_auth_guest'];
return 1;
}
return 0;
}
function reauthenticate() {
// not supported so return 0
return 0;
}
function passwordscanchange() {
// not supported so return 0
return 0;
}
function changepassword() {
// not supported so return 0
return 0;
}
function auth_usermanagement() {
// not supported so return 0
return 0;
}
function adduser($username, $level=0, $email='', $realname='', $can_modify_passwd=0, $description='', $twofactor=0) {
// Check to see if user is already added in the database
if (!user_exists_in_db($username)) {
$userid = dbInsert(array('username' => $username, 'realname' => $realname, 'email' => $email, 'descr' => $description, 'level' => $level, 'can_modify_passwd' => $can_modify_passwd, 'twofactor' => $twofactor, 'user_id' => get_userid($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;
}
}
function user_exists_in_db($username) {
$return = dbFetchCell('SELECT COUNT(*) FROM users WHERE username = ?', array($username), true);
return $return;
}
function user_exists($username) {
global $config, $ds;
if (auth_ldap_session_cache_get ('user_exists'))
return 1;
$search = ldap_search($ds, $config['auth_ad_base_dn'],
"(samaccountname=${username})",array('samaccountname'));
$entries = ldap_get_entries($ds, $search);
if ($entries['count']) {
/*
* Cache positiv result as this will result in more queries which we
* want to speed up.
*/
auth_ldap_session_cache_set ('user_exists', 1);
return 1;
}
return 0;
}
function get_userlevel($username) {
global $config, $ds;
$userlevel = auth_ldap_session_cache_get ('userlevel');
if ($userlevel) {
return $userlevel;
}
else {
$userlevel = 0;
}
// Find all defined groups $username is in
$search = ldap_search($ds, $config['auth_ad_base_dn'],
"(samaccountname={$username})", array('memberOf'));
$entries = ldap_get_entries($ds, $search);
// Loop the list and find the highest level
foreach ($entries[0]['memberof'] as $entry) {
$group_cn = get_cn($entry);
if ($config['auth_ad_groups'][$group_cn]['level'] > $userlevel) {
$userlevel = $config['auth_ad_groups'][$group_cn]['level'];
}
}
auth_ldap_session_cache_set ('userlevel', $userlevel);
return $userlevel;
}
function get_userid($username) {
global $config, $ds;
$user_id = auth_ldap_session_cache_get ('userid');
if (isset ($user_id)) {
return $user_id;
}
else {
$user_id = -1;
}
$attributes = array('objectsid');
$search = ldap_search($ds, $config['auth_ad_base_dn'],
"(samaccountname={$username})", $attributes);
$entries = ldap_get_entries($ds, $search);
if ($entries['count']) {
$user_id = preg_replace('/.*-(\d+)$/','$1',sid_from_ldap($entries[0]['objectsid'][0]));
}
auth_ldap_session_cache_set ('userid', $user_id);
return $user_id;
}
function deluser($username) {
dbDelete('bill_perms', '`user_name` = ?', array($username));
dbDelete('devices_perms', '`user_name` = ?', array($username));
dbDelete('ports_perms', '`user_name` = ?', array($username));
dbDelete('users_prefs', '`user_name` = ?', array($username));
dbDelete('users', '`user_name` = ?', array($username));
return dbDelete('users', '`username` = ?', array($username));
}
function get_userlist() {
global $config, $ds;
$userlist = array();
$userhash = array();
$ldap_groups = get_group_list();
foreach($ldap_groups as $ldap_group) {
$group_cn = get_cn($ldap_group);
$search = ldap_search($ds, $config['auth_ad_base_dn'], "(cn={$group_cn})", array('member'));
$entries = ldap_get_entries($ds, $search);
foreach($entries[0]['member'] as $member) {
$member_cn = get_cn($member);
$search = ldap_search($ds, $config['auth_ad_base_dn'], "(cn={$member_cn})",
array('sAMAccountname', 'displayName', 'objectSID', 'mail'));
$results = ldap_get_entries($ds, $search);
foreach($results as $result) {
if(isset($result['samaccountname'][0])) {
$userid = preg_replace('/.*-(\d+)$/','$1',
sid_from_ldap($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;
}
function can_update_users() {
// not supported so return 0
return 0;
}
function get_user($user_id) {
// not supported so return 0
return dbFetchRow('SELECT * FROM `users` WHERE `user_id` = ?', array($user_id), true);
}
function update_user($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));
}
function get_fullname($username) {
global $config, $ds;
$attributes = array('name');
$result = ldap_search($ds, $config['auth_ad_base_dn'],
"(samaccountname={$username})", $attributes);
$entries = ldap_get_entries($ds, $result);
if ($entries['count'] > 0) {
$membername = $entries[0]['name'][0];
}
else {
$membername = $username;
}
return $membername;
}
function get_group_list() {
global $config;
$ldap_groups = array();
// show all Active Directory Users by default
$default_group = 'Users';
if (isset($config['auth_ad_group'])) {
if ($config['auth_ad_group'] !== $default_group) {
$ldap_groups[] = $config['auth_ad_group'];
}
}
if (!isset($config['auth_ad_groups']) && !isset($config['auth_ad_group'])) {
$ldap_groups[] = get_dn($default_group);
}
foreach ($config['auth_ad_groups'] as $key => $value) {
$ldap_groups[] = get_dn($key);
}
return $ldap_groups;
}
function get_dn($samaccountname) {
global $config, $ds;
$attributes = array('dn');
$result = ldap_search($ds, $config['auth_ad_base_dn'],
"(samaccountname={$samaccountname})", $attributes);
$entries = ldap_get_entries($ds, $result);
if ($entries['count'] > 0) {
return $entries[0]['dn'];
}
else {
return '';
}
}
function get_cn($dn) {
preg_match('/[^,]*/', $dn, $matches, PREG_OFFSET_CAPTURE, 3);
return $matches[0][0];
}
function sid_from_ldap($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);
}
function auth_ldap_session_cache_get ($attr) {
global $config;
$ttl = 300;
if ($config['auth_ldap_cache_ttl'])
$ttl = $config['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'];
}
function auth_ldap_session_cache_set ($attr, $value) {
$_SESSION['auth_ldap'][$attr]['value'] = $value;
$_SESSION['auth_ldap'][$attr]['last_updated'] = time ();
}