Improving ldap auth

This commit is contained in:
Sergio Brighenti 2020-03-31 20:12:22 +02:00
parent b87faad0c9
commit 64772d190c
7 changed files with 78 additions and 61 deletions

View file

@ -51,20 +51,17 @@ class LoginController extends Controller
}
$username = param($request, 'username');
$user = $this->database->query('SELECT `id`, `email`, `username`, `password`,`is_admin`, `active`, `current_disk_quota`, `max_disk_quota` FROM `users` WHERE `username` = ? OR `email` = ? LIMIT 1', [$username, $username])->fetch();
$user = $this->database->query('SELECT `id`, `email`, `username`, `password`,`is_admin`, `active`, `current_disk_quota`, `max_disk_quota`, `ldap` FROM `users` WHERE `username` = ? OR `email` = ? LIMIT 1', [$username, $username])->fetch();
if ($this->config['ldap']['enabled']) {
$result = $this->ldapLogin($username, param($request, 'password'), $user);
if ($result) {
$user = $this->database->query('SELECT `id`, `email`, `username`, `password`,`is_admin`, `active`, `current_disk_quota`, `max_disk_quota` FROM `users` WHERE `username` = ? OR `email` = ? LIMIT 1', [$username, $username])->fetch();
}
$user = $this->ldapLogin($request, $username, param($request, 'password'), $user);
}
$validator = ValidationChecker::make()
->rules([
'login' => $user && password_verify(param($request, 'password'), $user->password),
'maintenance' => !isset($this->config['maintenance']) || !$this->config['maintenance'] || $user->is_admin,
'user_active' => $user->active,
'maintenance' => !isset($this->config['maintenance']) || !$this->config['maintenance'] || $user->is_admin ?? false,
'user_active' => $user->active ?? false,
])
->onFail(function ($rule) {
$alerts = [
@ -119,29 +116,55 @@ class LoginController extends Controller
}
/**
* @param Request $request
* @param string $username
* @param string $password
* @param $dbUser
* @return bool
* @throws \Slim\Exception\HttpNotFoundException
* @throws \Slim\Exception\HttpUnauthorizedException
*/
protected function ldapLogin(string $username, string $password, $dbUser)
protected function ldapLogin(Request $request, string $username, string $password, $dbUser)
{
if (!extension_loaded('ldap')) {
$this->logger->error('The LDAP extension is not loaded.');
return false;
}
$server = ldap_connect($this->config['ldap']['host'], $this->config['ldap']['port']);
$server = $this->ldapConnect();
if (!$server) {
$this->session->alert(lang('ldap_cant_connect'), 'warning');
return false;
return $dbUser;
}
if (!@ldap_bind($server, $this->getLdapRdn($username), $password)) {
if ($dbUser && !$dbUser->ldap) {
return $dbUser;
}
return null;
}
if (!$dbUser) {
$email = $username;
if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
$search = ldap_search($server, $this->config['ldap']['user_domain'].','.$this->config['ldap']['base_domain'], 'uid='.addslashes($username), ['mail']);
$entry = ldap_first_entry($server, $search);
$email = @ldap_get_values($server, $entry, 'mail')[0] ?? platform_mail($username.rand(0, 100)); // if the mail is not set, generate a placeholder
}
/** @var UserQuery $userQuery */
$userQuery = make(UserQuery::class);
$userQuery->create($email, $username, $password, 0, 1, (int) $this->getSetting('default_user_quota', -1), null, 1);
return $userQuery->get($request, $this->database->getPdo()->lastInsertId());
}
ldap_set_option($server, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($server, LDAP_OPT_REFERRALS, 0);
ldap_set_option($server, LDAP_OPT_NETWORK_TIMEOUT, 10);
if (!password_verify($password, $dbUser->password)) {
$userQuery = make(UserQuery::class);
$userQuery->update($dbUser->id, $dbUser->email, $username, $password, $dbUser->is_admin, $dbUser->active, $dbUser->max_disk_quota, $dbUser->ldap);
return $userQuery->get($request, $dbUser->id);
}
return $dbUser;
}
/**
* @param string $username
* @return string
*/
private function getLdapRdn(string $username)
{
$bindString = 'uid='.addslashes($username);
if ($this->config['ldap']['user_domain'] !== null) {
$bindString .= ','.$this->config['ldap']['user_domain'];
@ -151,40 +174,6 @@ class LoginController extends Controller
$bindString .= ','.$this->config['ldap']['base_domain'];
}
if (!@ldap_bind($server, $bindString, $password)) {
return false;
}
if (!$dbUser) {
$email = $username;
if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
$search = ldap_search($server, $this->config['ldap']['user_domain'].','.$this->config['ldap']['base_domain'], 'uid='.addslashes($username), ['mail']);
$entry = ldap_first_entry($server, $search);
$email = @ldap_get_values($server, $entry, 'mail')[0] ?? platform_mail($username.uniqid());
}
make(UserQuery::class)->create(
$email,
$username,
$password,
0,
1,
(int) $this->getSetting('default_user_quota', -1)
);
return true;
}
if (!password_verify($password, $dbUser->password)) {
make(UserQuery::class)->update(
$dbUser->id,
$dbUser->email,
$username,
$password,
$dbUser->is_admin,
$dbUser->active,
$dbUser->max_disk_quota
);
}
return true;
return $bindString;
}
}

View file

@ -39,7 +39,7 @@ class PasswordRecoveryController extends Controller
return redirect($response, route('home'));
}
$user = $this->database->query('SELECT `id`, `username` FROM `users` WHERE `email` = ? LIMIT 1', param($request, 'email'))->fetch();
$user = $this->database->query('SELECT `id`, `username` FROM `users` WHERE `email` = ? AND NOT `ldap` LIMIT 1', param($request, 'email'))->fetch();
if (!isset($user->id)) {
$this->session->alert(lang('recover_email_sent'), 'success');

View file

@ -167,4 +167,25 @@ abstract class Controller
$this->session->alert($alerts[$rule], 'danger');
});
}
/**
* @return bool|false|resource
*/
public function ldapConnect()
{
if (!extension_loaded('ldap')) {
$this->logger->error('The LDAP extension is not loaded.');
return false;
}
$server = ldap_connect($this->config['ldap']['host'], $this->config['ldap']['port']);
if ($server) {
ldap_set_option($server, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($server, LDAP_OPT_REFERRALS, 0);
ldap_set_option($server, LDAP_OPT_NETWORK_TIMEOUT, 10);
}
return $server;
}
}

View file

@ -79,9 +79,10 @@ class UserQuery
* @param int $isActive
* @param int $maxUserQuota
* @param string|null $activateToken
* @param int $ldap
* @return bool|\PDOStatement|string
*/
public function create(string $email, string $username, string $password = null, int $isAdmin = 0, int $isActive = 0, int $maxUserQuota = -1, string $activateToken = null)
public function create(string $email, string $username, string $password = null, int $isAdmin = 0, int $isActive = 0, int $maxUserQuota = -1, string $activateToken = null, int $ldap =0)
{
do {
$userCode = humanRandomString(5);
@ -89,7 +90,7 @@ class UserQuery
$token = $this->generateUserUploadToken();
return $this->database->query('INSERT INTO `users`(`email`, `username`, `password`, `is_admin`, `active`, `user_code`, `token`, `max_disk_quota`, `activate_token`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)', [
return $this->database->query('INSERT INTO `users`(`email`, `username`, `password`, `is_admin`, `active`, `user_code`, `token`, `max_disk_quota`, `activate_token`, `ldap`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', [
$email,
$username,
$password !== null ? password_hash($password, PASSWORD_DEFAULT) : null,
@ -99,6 +100,7 @@ class UserQuery
$token,
$maxUserQuota,
$activateToken,
$ldap
]);
}
@ -110,27 +112,30 @@ class UserQuery
* @param int $isAdmin
* @param int $isActive
* @param int $maxUserQuota
* @param int $ldap
* @return bool|\PDOStatement|string
*/
public function update($id, string $email, string $username, string $password = null, int $isAdmin = 0, int $isActive = 0, int $maxUserQuota = -1)
public function update($id, string $email, string $username, string $password = null, int $isAdmin = 0, int $isActive = 0, int $maxUserQuota = -1, int $ldap = 0)
{
if (!empty($password)) {
return $this->database->query('UPDATE `users` SET `email`=?, `username`=?, `password`=?, `is_admin`=?, `active`=?, `max_disk_quota`=? WHERE `id` = ?', [
return $this->database->query('UPDATE `users` SET `email`=?, `username`=?, `password`=?, `is_admin`=?, `active`=?, `max_disk_quota`=?, `ldap`=? WHERE `id` = ?', [
$email,
$username,
password_hash($password, PASSWORD_DEFAULT),
$isAdmin,
$isActive,
$maxUserQuota,
$ldap,
$id,
]);
} else {
return $this->database->query('UPDATE `users` SET `email`=?, `username`=?, `is_admin`=?, `active`=?, `max_disk_quota`=? WHERE `id` = ?', [
return $this->database->query('UPDATE `users` SET `email`=?, `username`=?, `is_admin`=?, `active`=?, `max_disk_quota`=?, `ldap`=? WHERE `id` = ?', [
$email,
$username,
$isAdmin,
$isActive,
$maxUserQuota,
$ldap,
$id,
]);
}

View file

@ -34,7 +34,7 @@ if (isset($argv[1]) && $argv[1] === '--install') {
}
if (file_exists(__DIR__.'/../install') && (!isset($config['debug']) || !$config['debug'])) {
//removeDirectory(__DIR__.'/../install');
removeDirectory(__DIR__.'/../install');
}
echo 'If you are upgrading from a previous version, please run a "php bin\clean".'.PHP_EOL;

View file

@ -0,0 +1 @@
ALTER TABLE `users` ADD COLUMN `ldap` BOOLEAN NOT NULL DEFAULT 0;

View file

@ -0,0 +1 @@
ALTER TABLE `users` ADD COLUMN `ldap` BOOLEAN NOT NULL DEFAULT 0;