mirror of
https://github.com/filegator/filegator.git
synced 2025-07-31 10:00:11 +02:00
Improve LDAP: attribute checks, handling, user filtering (#493)
This commit is contained in:
@@ -14,6 +14,8 @@ use Filegator\Services\Auth\User;
|
|||||||
use Filegator\Services\Auth\UsersCollection;
|
use Filegator\Services\Auth\UsersCollection;
|
||||||
use Filegator\Services\Service;
|
use Filegator\Services\Service;
|
||||||
use Filegator\Services\Session\SessionStorageInterface as Session;
|
use Filegator\Services\Session\SessionStorageInterface as Session;
|
||||||
|
use Filegator\Services\Logger\LoggerInterface;
|
||||||
|
use Monolog\Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
@@ -32,33 +34,38 @@ class LDAP implements Service, AuthInterface
|
|||||||
protected $ldap_filter;
|
protected $ldap_filter;
|
||||||
protected $ldap_attributes;
|
protected $ldap_attributes;
|
||||||
protected $ldap_userFieldMapping;
|
protected $ldap_userFieldMapping;
|
||||||
|
protected $logger;
|
||||||
|
|
||||||
public function __construct(Session $session)
|
public function __construct(Session $session, LoggerInterface $logger)
|
||||||
{
|
{
|
||||||
$this->session = $session;
|
$this->session = $session;
|
||||||
|
$this->logger = $logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function init(array $config = [])
|
public function init(array $config = [])
|
||||||
{
|
{
|
||||||
if(!isset($config['ldap_server']) || empty($config['ldap_server']))
|
if (!isset($config['ldap_server']) || empty($config['ldap_server']))
|
||||||
throw new \Exception('config ldap_server missing');
|
throw new \Exception('config ldap_server missing');
|
||||||
|
|
||||||
if (!extension_loaded('ldap')) throw new \Exception('ldap extension missing');
|
if (!extension_loaded('ldap'))
|
||||||
|
throw new \Exception('ldap extension missing');
|
||||||
|
|
||||||
if($connect=ldap_connect($config['ldap_server'])){
|
if ($connect = ldap_connect($config['ldap_server'])) {
|
||||||
ldap_set_option($connect, LDAP_OPT_PROTOCOL_VERSION, 3);
|
@ldap_set_option($connect, LDAP_OPT_PROTOCOL_VERSION, 3);
|
||||||
$this->private_repos = $config['private_repos'];
|
@ldap_set_option($connect, LDAP_OPT_REFERRALS, 0);
|
||||||
$this->ldap_server = $config['ldap_server'];
|
|
||||||
$this->ldap_bindDN = $config['ldap_bindDN'];
|
$this->private_repos = $config['private_repos'];
|
||||||
$this->ldap_bindPass = $config['ldap_bindPass'];
|
$this->ldap_server = $config['ldap_server'];
|
||||||
$this->ldap_baseDN = $config['ldap_baseDN'];
|
$this->ldap_bindDN = $config['ldap_bindDN'];
|
||||||
$this->ldap_filter = $config['ldap_filter'];
|
$this->ldap_bindPass = $config['ldap_bindPass'];
|
||||||
$this->ldap_attributes = isset($config['ldap_attributes']) ? $config['ldap_attributes'] : ['*'];
|
$this->ldap_baseDN = $config['ldap_baseDN'];
|
||||||
$this->ldap_userFieldMapping = $config['ldap_userFieldMapping'];
|
$this->ldap_filter = $config['ldap_filter'];
|
||||||
}else {
|
$this->ldap_attributes = isset($config['ldap_attributes']) ? $config['ldap_attributes'] : ['*'];
|
||||||
@ldap_close($connect);
|
$this->ldap_userFieldMapping = $config['ldap_userFieldMapping'];
|
||||||
throw new \Exception('could not connect to domain');
|
} else {
|
||||||
}
|
@ldap_close($connect);
|
||||||
|
throw new \Exception('could not connect to domain');
|
||||||
|
}
|
||||||
|
|
||||||
@ldap_close($connect);
|
@ldap_close($connect);
|
||||||
}
|
}
|
||||||
@@ -71,25 +78,27 @@ class LDAP implements Service, AuthInterface
|
|||||||
public function authenticate($username, $password): bool
|
public function authenticate($username, $password): bool
|
||||||
{
|
{
|
||||||
// prevent anonymous binding
|
// prevent anonymous binding
|
||||||
if(!isset($password) || empty($password)) return false;
|
if (!isset($password) || empty($password))
|
||||||
if(!isset($username) || empty($username)) return false;
|
return false;
|
||||||
|
if (!isset($username) || empty($username))
|
||||||
|
return false;
|
||||||
|
|
||||||
// remove (optional) domains from the username
|
// remove (optional) domains from the username
|
||||||
if(!empty($this->ldap_userFieldMapping['username_RemoveDomains']) && is_array($this->ldap_userFieldMapping['username_RemoveDomains'])) {
|
if (!empty($this->ldap_userFieldMapping['username_RemoveDomains']) && is_array($this->ldap_userFieldMapping['username_RemoveDomains'])) {
|
||||||
$username = str_replace($this->ldap_userFieldMapping['username_RemoveDomains'], '', $username);
|
$username = str_replace($this->ldap_userFieldMapping['username_RemoveDomains'], '', $username);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$all_users = $this->getUsers($username);
|
||||||
|
|
||||||
// add the domain to the username
|
// add the domain to the username
|
||||||
if(!empty($this->ldap_userFieldMapping['username_AddDomain'])) {
|
if (!empty($this->ldap_userFieldMapping['username_AddDomain'])) {
|
||||||
if(strpos($username, $this->ldap_userFieldMapping['username_AddDomain']) === false) {
|
if (strpos($username, $this->ldap_userFieldMapping['username_AddDomain']) === false) {
|
||||||
$username .= $this->ldap_userFieldMapping['username_AddDomain'];
|
$username .= $this->ldap_userFieldMapping['username_AddDomain'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$all_users = $this->getUsers();
|
|
||||||
|
|
||||||
foreach ($all_users as &$u) {
|
foreach ($all_users as &$u) {
|
||||||
if ($u['username'] == $username && $this->verifyPassword($u['userDN'], $password)) {
|
if (strtolower($u['username']) == strtolower($username) && $this->verifyPassword($u['userDN'], $password)) {
|
||||||
$user = $this->mapToUserObject($u);
|
$user = $this->mapToUserObject($u);
|
||||||
$this->store($user);
|
$this->store($user);
|
||||||
return true;
|
return true;
|
||||||
@@ -126,8 +135,8 @@ class LDAP implements Service, AuthInterface
|
|||||||
|
|
||||||
public function find($username): ?User
|
public function find($username): ?User
|
||||||
{
|
{
|
||||||
foreach ($this->getUsers() as $user) {
|
foreach ($this->getUsers($username) as $user) {
|
||||||
if ($user['username'] == $username) {
|
if (strtolower($user['username']) == strtolower($username)) {
|
||||||
return $this->mapToUserObject($user);
|
return $this->mapToUserObject($user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,77 +183,107 @@ class LDAP implements Service, AuthInterface
|
|||||||
return $new;
|
return $new;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getUsers(): array
|
protected function getUsers(string $username = null): array
|
||||||
{
|
{
|
||||||
$ldapConn = @ldap_connect($this->ldap_server);
|
$ldapConn = @ldap_connect($this->ldap_server);
|
||||||
if (!$ldapConn) throw new \Exception('Cannot Connect to LDAP server');
|
if (!$ldapConn)
|
||||||
@ldap_set_option($ldapConn, LDAP_OPT_PROTOCOL_VERSION, 3);
|
throw new \Exception('Cannot Connect to LDAP server');
|
||||||
|
@ldap_set_option($ldapConn, LDAP_OPT_PROTOCOL_VERSION, 3);
|
||||||
|
@ldap_set_option($ldapConn, LDAP_OPT_REFERRALS, 0);
|
||||||
|
|
||||||
$ldapBind = @ldap_bind($ldapConn, $this->ldap_bindDN,$this->ldap_bindPass);
|
$ldapBind = @ldap_bind($ldapConn, $this->ldap_bindDN, $this->ldap_bindPass);
|
||||||
if (!$ldapBind) throw new \Exception('Cannot Bind to LDAP server: Wrong credentials?');
|
if (!$ldapBind)
|
||||||
|
throw new \Exception('Cannot Bind to LDAP server: Wrong credentials?');
|
||||||
|
|
||||||
// search the LDAP server for users
|
// search the LDAP server for users
|
||||||
$ldapSearch = @ldap_search($ldapConn, $this->ldap_baseDN, $this->ldap_filter, $this->ldap_attributes);
|
$filter = $this->ldap_filter;
|
||||||
$ldapResults = @ldap_get_entries($ldapConn, $ldapSearch);
|
if (!empty($username))
|
||||||
@ldap_close($ldapConn);
|
$filter = '(&' . $filter . '(' . $this->ldap_userFieldMapping['username'] . '=' . $username . '))';
|
||||||
|
|
||||||
$users = [];
|
$ldapSearch = @ldap_search($ldapConn, $this->ldap_baseDN, $filter, $this->ldap_attributes);
|
||||||
|
|
||||||
for ($item = 0; $item < $ldapResults['count']; $item++)
|
if (!$ldapSearch) {
|
||||||
{
|
$this->logger->log($filter);
|
||||||
|
throw new \Exception('Cannot search LDAP server: Wrong filter?');
|
||||||
|
}
|
||||||
|
|
||||||
|
$ldapResults = @ldap_get_entries($ldapConn, $ldapSearch);
|
||||||
|
@ldap_close($ldapConn);
|
||||||
|
|
||||||
|
$users = [];
|
||||||
|
|
||||||
|
for ($item = 0; $item < $ldapResults['count']; $item++) {
|
||||||
|
|
||||||
|
$missingAttributes = [];
|
||||||
|
|
||||||
|
// Check if all required attributes are present
|
||||||
|
foreach (['username', 'name', 'userDN'] as $attribute) {
|
||||||
|
if (!isset($ldapResults[$item][$this->ldap_userFieldMapping[$attribute]])) {
|
||||||
|
$missingAttributes[] = '`' . $this->ldap_userFieldMapping[$attribute] . '` as `' . $attribute . '`';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if any required attribute is missing, log an info message
|
||||||
|
if (!empty($missingAttributes)) {
|
||||||
|
$this->logger->log('Missing LDAP attribues: ' . implode(', ', $missingAttributes) . '. Please check the spelling (including upper or lower case).', Logger::WARNING);
|
||||||
|
} else {
|
||||||
$user = [];
|
$user = [];
|
||||||
$user['username'] = $ldapResults[$item][$this->ldap_userFieldMapping['username']][0];
|
$user['username'] = $ldapResults[$item][$this->ldap_userFieldMapping['username']][0];
|
||||||
$user['name'] = $ldapResults[$item][$this->ldap_userFieldMapping['name']][0];
|
$user['name'] = $ldapResults[$item][$this->ldap_userFieldMapping['name']][0];
|
||||||
$user['role'] = 'user';
|
$user['role'] = 'user';
|
||||||
$user['homedir'] = '/';
|
$user['homedir'] = '/';
|
||||||
$user['permissions']=$this->ldap_userFieldMapping['default_permissions'];
|
$user['permissions'] = $this->ldap_userFieldMapping['default_permissions'];
|
||||||
$user['userDN'] = $ldapResults[$item][$this->ldap_userFieldMapping['userDN']];
|
$user['userDN'] = $ldapResults[$item][$this->ldap_userFieldMapping['userDN']];
|
||||||
|
|
||||||
if(!empty($this->ldap_userFieldMapping['username_AddDomain'])){
|
if (!empty($this->ldap_userFieldMapping['username_AddDomain'])) {
|
||||||
if(strpos($user['username'], $this->ldap_userFieldMapping['username_AddDomain']) === false)
|
if (strpos($user['username'], $this->ldap_userFieldMapping['username_AddDomain']) === false)
|
||||||
$user['username'] .= $this->ldap_userFieldMapping['username_AddDomain'];
|
$user['username'] .= $this->ldap_userFieldMapping['username_AddDomain'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_array($this->ldap_userFieldMapping['admin_usernames']))
|
if (is_array($this->ldap_userFieldMapping['admin_usernames'])) {
|
||||||
{
|
if (in_array($user['username'], $this->ldap_userFieldMapping['admin_usernames']))
|
||||||
if(in_array($user['username'], $this->ldap_userFieldMapping['admin_usernames'])) $user['role'] = 'admin';
|
$user['role'] = 'admin';
|
||||||
}
|
}
|
||||||
|
|
||||||
// private repositories for each user?
|
// private repositories for each user?
|
||||||
if ($this->private_repos) {
|
if ($this->private_repos) {
|
||||||
$user['homedir'] = '/'.$user['username'];
|
$user['homedir'] = '/' . $user['username'];
|
||||||
}
|
}
|
||||||
|
|
||||||
// ...but not for admins
|
// ...but not for admins
|
||||||
if ($user['role'] == 'admin'){
|
if ($user['role'] == 'admin') {
|
||||||
$user['homedir'] = '/';
|
$user['homedir'] = '/';
|
||||||
$user['permissions'] = 'read|write|upload|download|batchdownload|zip|chmod';
|
$user['permissions'] = 'read|write|upload|download|batchdownload|zip|chmod';
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_array($user) && !empty($user)) $users[] = $user;
|
if (is_array($user) && !empty($user))
|
||||||
|
$users[] = $user;
|
||||||
}
|
}
|
||||||
// print_r($users); // uncomment this line to see all available ldap-login-users
|
}
|
||||||
|
// print_r($users); // uncomment this line to see all available ldap-login-users
|
||||||
return is_array($users) ? $users : [];
|
return is_array($users) ? $users : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
private function verifyPassword($auth_user, $password)
|
private function verifyPassword($auth_user, $password)
|
||||||
{
|
{
|
||||||
if(!isset($this->ldap_server) || empty($this->ldap_server)) return false;
|
if (!isset($this->ldap_server) || empty($this->ldap_server))
|
||||||
if(!extension_loaded('ldap')) return false;
|
|
||||||
|
|
||||||
if($connect=ldap_connect($this->ldap_server))
|
|
||||||
{
|
|
||||||
ldap_set_option($connect, LDAP_OPT_PROTOCOL_VERSION, 3);
|
|
||||||
if($bind=ldap_bind($connect, $auth_user, $password)){
|
|
||||||
@ldap_close($connect);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
@ldap_close($connect);
|
|
||||||
return false;
|
return false;
|
||||||
|
if (!extension_loaded('ldap'))
|
||||||
|
return false;
|
||||||
|
$connect = @ldap_connect($this->ldap_server);
|
||||||
|
if ($connect) {
|
||||||
|
ldap_set_option($connect, LDAP_OPT_PROTOCOL_VERSION, 3);
|
||||||
|
ldap_set_option($connect, LDAP_OPT_REFERRALS, 0);
|
||||||
|
$bind = @ldap_bind($connect, $auth_user, $password);
|
||||||
|
if ($bind) {
|
||||||
|
@ldap_close($connect);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
@ldap_close($connect);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ldap_close($connect);
|
@ldap_close($connect);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user