1
0
mirror of https://github.com/BookStackApp/BookStack.git synced 2025-08-07 23:03:00 +03:00

Cleaned tests up, Started LDAP tests, Created LDAP wrapper

This commit is contained in:
Dan Brown
2016-01-15 23:21:47 +00:00
parent 14feef3679
commit 0821672e70
15 changed files with 259 additions and 79 deletions

View File

@@ -118,17 +118,20 @@ class AuthController extends Controller
*/
protected function authenticated(Request $request, Authenticatable $user)
{
if(!$user->exists && $user->email === null && !$request->has('email')) {
// Explicitly log them out for now if they do no exist.
if (!$user->exists) auth()->logout($user);
if (!$user->exists && $user->email === null && !$request->has('email')) {
$request->flash();
session()->flash('request-email', true);
return redirect('/login');
}
if(!$user->exists && $user->email === null && $request->has('email')) {
if (!$user->exists && $user->email === null && $request->has('email')) {
$user->email = $request->get('email');
}
if(!$user->exists) {
if (!$user->exists) {
$user->save();
$this->userRepo->attachDefaultRole($user);
auth()->login($user);

View File

@@ -38,6 +38,7 @@ class Authenticate
if(auth()->check() && auth()->user()->email_confirmed == false) {
return redirect()->guest('/register/confirm/awaiting');
}
if ($this->auth->guest() && !Setting::get('app-public')) {
if ($request->ajax()) {
return response('Unauthorized.', 401);

View File

@@ -1,11 +1,5 @@
<?php
Route::get('/test', function() {
// TODO - remove this
$service = new \BookStack\Services\LdapService();
dd($service->getUserDetails('ksmith'));
});
// Authenticated routes...
Route::group(['middleware' => 'auth'], function () {

View File

@@ -86,8 +86,10 @@ class LdapUserProvider implements UserProvider
*/
public function updateRememberToken(Authenticatable $user, $token)
{
$user->setRememberToken($token);
$user->save();
if ($user->exists) {
$user->setRememberToken($token);
$user->save();
}
}
/**
@@ -113,6 +115,7 @@ class LdapUserProvider implements UserProvider
$model->name = $userDetails['name'];
$model->external_auth_id = $userDetails['uid'];
$model->email = $userDetails['email'];
$model->email_confirmed = true;
return $model;
}

86
app/Services/Ldap.php Normal file
View File

@@ -0,0 +1,86 @@
<?php namespace BookStack\Services;
/**
* Class Ldap
* An object-orientated thin abstraction wrapper for common PHP LDAP functions.
* Allows the standard LDAP functions to be mocked for testing.
* @package BookStack\Services
*/
class Ldap
{
/**
* Connect to a LDAP server.
* @param string $hostName
* @param int $port
* @return resource
*/
public function connect($hostName, $port)
{
return ldap_connect($hostName, $port);
}
/**
* Set the value of a LDAP option for the given connection.
* @param resource $ldapConnection
* @param int $option
* @param mixed $value
* @return bool
*/
public function setOption($ldapConnection, $option, $value)
{
return ldap_set_option($ldapConnection, $option, $value);
}
/**
* Search LDAP tree using the provided filter.
* @param resource $ldapConnection
* @param string $baseDn
* @param string $filter
* @param array|null $attributes
* @return resource
*/
public function search($ldapConnection, $baseDn, $filter, array $attributes = null)
{
return ldap_search($ldapConnection, $baseDn, $filter, $attributes);
}
/**
* Get entries from an ldap search result.
* @param resource $ldapConnection
* @param resource $ldapSearchResult
* @return array
*/
public function getEntries($ldapConnection, $ldapSearchResult)
{
return ldap_get_entries($ldapConnection, $ldapSearchResult);
}
/**
* Search and get entries immediately.
* @param resource $ldapConnection
* @param string $baseDn
* @param string $filter
* @param array|null $attributes
* @return resource
*/
public function searchAndGetEntries($ldapConnection, $baseDn, $filter, array $attributes = null)
{
$search = $this->search($ldapConnection, $baseDn, $filter, $attributes);
return $this->getEntries($ldapConnection, $search);
}
/**
* Bind to LDAP directory.
* @param resource $ldapConnection
* @param string $bindRdn
* @param string $bindPassword
* @return bool
*/
public function bind($ldapConnection, $bindRdn = null, $bindPassword = null)
{
return ldap_bind($ldapConnection, $bindRdn, $bindPassword);
}
}

View File

@@ -4,10 +4,27 @@
use BookStack\Exceptions\LdapException;
use Illuminate\Contracts\Auth\Authenticatable;
/**
* Class LdapService
* Handles any app-specific LDAP tasks.
* @package BookStack\Services
*/
class LdapService
{
protected $ldap;
protected $ldapConnection;
protected $config;
/**
* LdapService constructor.
* @param Ldap $ldap
*/
public function __construct(Ldap $ldap)
{
$this->ldap = $ldap;
$this->config = config('services.ldap');
}
/**
* Get the details of a user from LDAP using the given username.
@@ -21,17 +38,16 @@ class LdapService
$ldapConnection = $this->getConnection();
// Find user
$userFilter = $this->buildFilter(config('services.ldap.user_filter'), ['user' => $userName]);
$baseDn = config('services.ldap.base_dn');
$ldapSearch = ldap_search($ldapConnection, $baseDn, $userFilter, ['cn', 'uid', 'dn', 'mail']);
$users = ldap_get_entries($ldapConnection, $ldapSearch);
$userFilter = $this->buildFilter($this->config['user_filter'], ['user' => $userName]);
$baseDn = $this->config['base_dn'];
$users = $this->ldap->searchAndGetEntries($ldapConnection, $baseDn, $userFilter, ['cn', 'uid', 'dn', 'mail']);
if ($users['count'] === 0) return null;
$user = $users[0];
return [
'uid' => $user['uid'][0],
'name' => $user['cn'][0],
'dn' => $user['dn'],
'uid' => $user['uid'][0],
'name' => $user['cn'][0],
'dn' => $user['dn'],
'email' => (isset($user['mail'])) ? $user['mail'][0] : null
];
}
@@ -50,7 +66,12 @@ class LdapService
if ($ldapUser['uid'] !== $user->external_auth_id) return false;
$ldapConnection = $this->getConnection();
$ldapBind = @ldap_bind($ldapConnection, $ldapUser['dn'], $password);
try {
$ldapBind = $this->ldap->bind($ldapConnection, $ldapUser['dn'], $password);
} catch (\ErrorException $e) {
$ldapBind = false;
}
return $ldapBind;
}
@@ -62,14 +83,14 @@ class LdapService
*/
protected function bindSystemUser($connection)
{
$ldapDn = config('services.ldap.dn');
$ldapPass = config('services.ldap.pass');
$ldapDn = $this->config['dn'];
$ldapPass = $this->config['pass'];
$isAnonymous = ($ldapDn === false || $ldapPass === false);
if ($isAnonymous) {
$ldapBind = ldap_bind($connection);
$ldapBind = $this->ldap->bind($connection);
} else {
$ldapBind = ldap_bind($connection, $ldapDn, $ldapPass);
$ldapBind = $this->ldap->bind($connection, $ldapDn, $ldapPass);
}
if (!$ldapBind) throw new LdapException('LDAP access failed using ' . $isAnonymous ? ' anonymous bind.' : ' given dn & pass details');
@@ -86,20 +107,22 @@ class LdapService
if ($this->ldapConnection !== null) return $this->ldapConnection;
// Check LDAP extension in installed
if (!function_exists('ldap_connect')) {
if (!function_exists('ldap_connect') && config('app.env') !== 'testing') {
throw new LdapException('LDAP PHP extension not installed');
}
// Get port from server string if specified.
$ldapServer = explode(':', config('services.ldap.server'));
$ldapConnection = ldap_connect($ldapServer[0], count($ldapServer) > 1 ? $ldapServer[1] : 389);
$ldapServer = explode(':', $this->config['server']);
$ldapConnection = $this->ldap->connect($ldapServer[0], count($ldapServer) > 1 ? $ldapServer[1] : 389);
if ($ldapConnection === false) {
throw new LdapException('Cannot connect to ldap server, Initial connection failed');
}
// Set any required options
ldap_set_option($ldapConnection, LDAP_OPT_PROTOCOL_VERSION, 3); // TODO - make configurable
if ($this->config['version']) {
$this->ldap->setOption($ldapConnection, LDAP_OPT_PROTOCOL_VERSION, $this->config['version']);
}
$this->ldapConnection = $ldapConnection;
return $this->ldapConnection;
@@ -107,7 +130,7 @@ class LdapService
/**
* Build a filter string by injecting common variables.
* @param $filterString
* @param string $filterString
* @param array $attrs
* @return string
*/