Implemented LDAP authentication support (closes #305)

This commit is contained in:
Bernd Bestel 2020-10-20 21:43:58 +02:00
parent def61eee6e
commit 31fcdf377a
No known key found for this signature in database
GPG Key ID: 71BD34C0D4891300
3 changed files with 88 additions and 4 deletions

View File

@ -14,10 +14,15 @@
- Other users only see their API keys on that page - Other users only see their API keys on that page
- (Thanks @fipwmaqzufheoxq92ebc) - (Thanks @fipwmaqzufheoxq92ebc)
### New feature: Reverse proxy authenticaton support ### New feature: External authentication support
- New `config.php` settings `AUTH_CLASS` and `REVERSE_PROXY_AUTH_HEADER` - New `config.php` setting `AUTH_CLASS` to change the used authentication provider
- If you set `AUTH_CLASS` to `Grocy\Middleware\ReverseProxyAuthMiddleware` and your reverse proxy sends a username in the HTTP header `REMOTE_USER` (header name can be changed by the setting `REVERSE_PROXY_AUTH_HEADER`), the user is automatically authenticated (and will also be created, if not already present) - Via LDAP
- (Thanks @fipwmaqzufheoxq92ebc for the initial work on this) - New `config.php` settings `LDAP_DOMAIN`, `LDAP_ADDRESS` and `LDAP_BASE_DN`
- If you set `AUTH_CLASS` to `Grocy\Middleware\LdapAuthMiddleware`, users will be authenticated against your directory (and will also be created (in grocy), if not already present)
- Via a reverse proxy
- New `config.php` setting `REVERSE_PROXY_AUTH_HEADER`
- If you set `AUTH_CLASS` to `Grocy\Middleware\ReverseProxyAuthMiddleware` and your reverse proxy sends a username in the HTTP header `REMOTE_USER` (header name can be changed by the setting `REVERSE_PROXY_AUTH_HEADER`), the user is automatically authenticated (and will also be created (in grocy), if not already present)
- (Thanks @fipwmaqzufheoxq92ebc for the initial work on this)
### Stock improvements/fixes ### Stock improvements/fixes
- When creating a quantity unit conversion it's now possible to automatically create the inverse conversion (thanks @kriddles) - When creating a quantity unit conversion it's now possible to automatically create the inverse conversion (thanks @kriddles)

View File

@ -73,6 +73,11 @@ Setting('AUTH_CLASS', 'Grocy\Middleware\DefaultAuthMiddleware');
// the name of the HTTP header which your reverse proxy uses to pass the username (on successful authentication) // the name of the HTTP header which your reverse proxy uses to pass the username (on successful authentication)
Setting('REVERSE_PROXY_AUTH_HEADER', 'REMOTE_USER'); Setting('REVERSE_PROXY_AUTH_HEADER', 'REMOTE_USER');
// When using LdapAuthMiddleware
Setting('LDAP_DOMAIN', ''); // Example value "local"
Setting('LDAP_ADDRESS', ''); // Example value "ldap://vm-dc2019.local.berrnd.net"
Setting('LDAP_BASE_DN', ''); // Example value "OU=OU_Users,DC=local,DC=berrnd,DC=net"
// Set this to true if you want to disable the ability to scan a barcode via the device camera (Browser API) // Set this to true if you want to disable the ability to scan a barcode via the device camera (Browser API)
Setting('DISABLE_BROWSER_BARCODE_CAMERA_SCANNING', false); Setting('DISABLE_BROWSER_BARCODE_CAMERA_SCANNING', false);

View File

@ -0,0 +1,74 @@
<?php
namespace Grocy\Middleware;
use Grocy\Services\DatabaseService;
use Grocy\Services\UsersService;
use Grocy\Services\SessionService;
use Psr\Http\Message\ServerRequestInterface as Request;
class LdapAuthMiddleware extends AuthMiddleware
{
public function authenticate(Request $request)
{
// TODO: Reuse DefaultAuthMiddleware->authenticate somehow
// First try to authenticate by API key
$auth = new ApiKeyAuthMiddleware($this->AppContainer, $this->ResponseFactory);
$user = $auth->authenticate($request);
if ($user !== null)
{
return $user;
}
// Then by session cookie
$auth = new SessionAuthMiddleware($this->AppContainer, $this->ResponseFactory);
$user = $auth->authenticate($request);
return $user;
}
public static function ProcessLogin(array $postParams)
{
if ($connect = ldap_connect(GROCY_LDAP_ADDRESS))
{
ldap_set_option($connect, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($connect, LDAP_OPT_REFERRALS, 0);
if ($bind = ldap_bind($connect, GROCY_LDAP_DOMAIN . '\\' . $postParams['username'], $postParams['password']))
{
$fields = '(|(samaccountname=*' . $postParams['username'] . '*))';
$search = ldap_search($connect, GROCY_LDAP_BASE_DN, $fields);
$result = ldap_get_entries($connect, $search);
$ldapFirstName = $result[0]['givenname'][0];
$ldapLastName = $result[0]['sn'][0];
ldap_close($connect);
$db = DatabaseService::getInstance()->GetDbConnection();
$user = $db->users()->where('username', $postParams['username'])->fetch();
if ($user == null)
{
$user = UsersService::getInstance()->CreateUser($postParams['username'], $ldapFirstName, $ldapLastName, '');
}
$sessionKey = SessionService::getInstance()->CreateSession($user->id, $postParams['stay_logged_in'] == 'on');
self::SetSessionCookie($sessionKey);
return true;
}
else
{
// LDAP authentication failed
return false;
}
}
else
{
// LDAP connection failed
return false;
}
}
}