mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-08-07 23:03:00 +03:00
Updated laravel to 5.2 and started ldap implementation
This commit is contained in:
@@ -3,8 +3,11 @@
|
||||
namespace BookStack\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Contracts\Validation\ValidationException;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||
use Illuminate\Auth\Access\AuthorizationException;
|
||||
|
||||
class Handler extends ExceptionHandler
|
||||
{
|
||||
@@ -14,7 +17,10 @@ class Handler extends ExceptionHandler
|
||||
* @var array
|
||||
*/
|
||||
protected $dontReport = [
|
||||
AuthorizationException::class,
|
||||
HttpException::class,
|
||||
ModelNotFoundException::class,
|
||||
ValidationException::class,
|
||||
];
|
||||
|
||||
/**
|
||||
|
9
app/Exceptions/LdapException.php
Normal file
9
app/Exceptions/LdapException.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php namespace BookStack\Exceptions;
|
||||
|
||||
|
||||
use Exception;
|
||||
|
||||
class LdapException extends Exception
|
||||
{
|
||||
|
||||
}
|
@@ -29,7 +29,6 @@ class AuthController extends Controller
|
||||
|
||||
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
|
||||
|
||||
protected $loginPath = '/login';
|
||||
protected $redirectPath = '/';
|
||||
protected $redirectAfterLogout = '/login';
|
||||
|
||||
@@ -232,13 +231,9 @@ class AuthController extends Controller
|
||||
*/
|
||||
public function getLogin()
|
||||
{
|
||||
|
||||
if (view()->exists('auth.authenticate')) {
|
||||
return view('auth.authenticate');
|
||||
}
|
||||
|
||||
$socialDrivers = $this->socialAuthService->getActiveDrivers();
|
||||
return view('auth.login', ['socialDrivers' => $socialDrivers]);
|
||||
$authMethod = 'standard'; // TODO - rewrite to use config.
|
||||
return view('auth/login', ['socialDrivers' => $socialDrivers, 'authMethod' => $authMethod]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -253,7 +248,7 @@ class AuthController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to the social site for authentication initended to register.
|
||||
* Redirect to the social site for authentication intended to register.
|
||||
* @param $socialDriver
|
||||
* @return mixed
|
||||
*/
|
||||
|
@@ -48,7 +48,7 @@ abstract class Controller extends BaseController
|
||||
*/
|
||||
protected function preventAccessForDemoUsers()
|
||||
{
|
||||
if (env('APP_ENV', 'production') === 'demo') $this->showPermissionError();
|
||||
if (config('app.env') === 'demo') $this->showPermissionError();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -72,7 +72,7 @@ class UserController extends Controller
|
||||
$user->attachRoleId($request->get('role'));
|
||||
|
||||
// Get avatar from gravatar and save
|
||||
if (!env('DISABLE_EXTERNAL_SERVICES', false)) {
|
||||
if (!config('services.disable_services')) {
|
||||
$avatar = \Images::saveUserGravatar($user);
|
||||
$user->avatar()->associate($avatar);
|
||||
$user->save();
|
||||
|
@@ -1,5 +1,11 @@
|
||||
<?php
|
||||
|
||||
Route::get('/test', function() {
|
||||
// TODO - remove this
|
||||
$service = new \BookStack\Services\LdapService();
|
||||
$service->getUserDetails('ssmith');
|
||||
});
|
||||
|
||||
// Authenticated routes...
|
||||
Route::group(['middleware' => 'auth'], function () {
|
||||
|
||||
|
31
app/Providers/AuthServiceProvider.php
Normal file
31
app/Providers/AuthServiceProvider.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace BookStack\Providers;
|
||||
|
||||
use Auth;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class AuthServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap the application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
Auth::provider('ldap', function($app, array $config) {
|
||||
return new LdapUserProvider($config['model']);
|
||||
});
|
||||
}
|
||||
}
|
117
app/Providers/LdapUserProvider.php
Normal file
117
app/Providers/LdapUserProvider.php
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
namespace BookStack\Providers;
|
||||
|
||||
|
||||
use BookStack\User;
|
||||
use Illuminate\Contracts\Auth\Authenticatable;
|
||||
use Illuminate\Contracts\Auth\UserProvider;
|
||||
|
||||
class LdapUserProvider implements UserProvider
|
||||
{
|
||||
|
||||
/**
|
||||
* The user model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model;
|
||||
|
||||
|
||||
/**
|
||||
* LdapUserProvider constructor.
|
||||
* @param $model
|
||||
*/
|
||||
public function __construct($model)
|
||||
{
|
||||
$this->model = $model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of the model.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Model
|
||||
*/
|
||||
public function createModel()
|
||||
{
|
||||
$class = '\\'.ltrim($this->model, '\\');
|
||||
|
||||
return new $class;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve a user by their unique identifier.
|
||||
*
|
||||
* @param mixed $identifier
|
||||
* @return \Illuminate\Contracts\Auth\Authenticatable|null
|
||||
*/
|
||||
public function retrieveById($identifier)
|
||||
{
|
||||
return $this->createModel()->newQuery()->find($identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a user by their unique identifier and "remember me" token.
|
||||
*
|
||||
* @param mixed $identifier
|
||||
* @param string $token
|
||||
* @return \Illuminate\Contracts\Auth\Authenticatable|null
|
||||
*/
|
||||
public function retrieveByToken($identifier, $token)
|
||||
{
|
||||
$model = $this->createModel();
|
||||
|
||||
return $model->newQuery()
|
||||
->where($model->getAuthIdentifierName(), $identifier)
|
||||
->where($model->getRememberTokenName(), $token)
|
||||
->first();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the "remember me" token for the given user in storage.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable $user
|
||||
* @param string $token
|
||||
* @return void
|
||||
*/
|
||||
public function updateRememberToken(Authenticatable $user, $token)
|
||||
{
|
||||
$user->setRememberToken($token);
|
||||
|
||||
$user->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a user by the given credentials.
|
||||
*
|
||||
* @param array $credentials
|
||||
* @return \Illuminate\Contracts\Auth\Authenticatable|null
|
||||
*/
|
||||
public function retrieveByCredentials(array $credentials)
|
||||
{
|
||||
// TODO: Implement retrieveByCredentials() method.
|
||||
|
||||
// Get user via LDAP
|
||||
|
||||
// Search current user base by looking up a uid
|
||||
|
||||
// If not exists create a new user instance with attached role
|
||||
// but do not store it in the database yet
|
||||
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a user against the given credentials.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable $user
|
||||
* @param array $credentials
|
||||
* @return bool
|
||||
*/
|
||||
public function validateCredentials(Authenticatable $user, array $credentials)
|
||||
{
|
||||
// TODO: Implement validateCredentials() method.
|
||||
}
|
||||
}
|
@@ -200,7 +200,7 @@ class ImageService
|
||||
{
|
||||
if ($this->storageInstance !== null) return $this->storageInstance;
|
||||
|
||||
$storageType = env('STORAGE_TYPE');
|
||||
$storageType = config('filesystems.default');
|
||||
$this->storageInstance = $this->fileSystem->disk($storageType);
|
||||
|
||||
return $this->storageInstance;
|
||||
@@ -226,10 +226,10 @@ class ImageService
|
||||
private function getPublicUrl($filePath)
|
||||
{
|
||||
if ($this->storageUrl === null) {
|
||||
$storageUrl = env('STORAGE_URL');
|
||||
$storageUrl = config('filesystems.url');
|
||||
|
||||
// Get the standard public s3 url if s3 is set as storage type
|
||||
if ($storageUrl == false && env('STORAGE_TYPE') === 's3') {
|
||||
if ($storageUrl == false && config('filesystems.default') === 's3') {
|
||||
$storageDetails = config('filesystems.disks.s3');
|
||||
$storageUrl = 'https://s3-' . $storageDetails['region'] . '.amazonaws.com/' . $storageDetails['bucket'];
|
||||
}
|
||||
|
60
app/Services/LdapService.php
Normal file
60
app/Services/LdapService.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php namespace BookStack\Services;
|
||||
|
||||
|
||||
use BookStack\Exceptions\LdapException;
|
||||
|
||||
class LdapService
|
||||
{
|
||||
|
||||
public function getUserDetails($userName)
|
||||
{
|
||||
|
||||
if(!function_exists('ldap_connect')) {
|
||||
throw new LdapException('LDAP PHP extension not installed');
|
||||
}
|
||||
|
||||
|
||||
$ldapServer = explode(':', config('services.ldap.server'));
|
||||
$ldapConnection = ldap_connect($ldapServer[0], count($ldapServer) > 1 ? $ldapServer[1] : 389);
|
||||
|
||||
if ($ldapConnection === false) {
|
||||
throw new LdapException('Cannot connect to ldap server, Initial connection failed');
|
||||
}
|
||||
|
||||
// Options
|
||||
|
||||
ldap_set_option($ldapConnection, LDAP_OPT_PROTOCOL_VERSION, 3); // TODO - make configurable
|
||||
|
||||
$ldapDn = config('services.ldap.dn');
|
||||
$ldapPass = config('services.ldap.pass');
|
||||
$isAnonymous = ($ldapDn === false || $ldapPass === false);
|
||||
if ($isAnonymous) {
|
||||
$ldapBind = ldap_bind($ldapConnection);
|
||||
} else {
|
||||
$ldapBind = ldap_bind($ldapConnection, $ldapDn, $ldapPass);
|
||||
}
|
||||
|
||||
if (!$ldapBind) throw new LdapException('LDAP access failed using ' . $isAnonymous ? ' anonymous bind.' : ' given dn & pass details');
|
||||
|
||||
// Find user
|
||||
$userFilter = $this->buildFilter(config('services.ldap.user_filter'), ['user' => $userName]);
|
||||
//dd($userFilter);
|
||||
$baseDn = config('services.ldap.base_dn');
|
||||
$ldapSearch = ldap_search($ldapConnection, $baseDn, $userFilter);
|
||||
$users = ldap_get_entries($ldapConnection, $ldapSearch);
|
||||
|
||||
dd($users);
|
||||
}
|
||||
|
||||
|
||||
private function buildFilter($filterString, $attrs)
|
||||
{
|
||||
$newAttrs = [];
|
||||
foreach ($attrs as $key => $attrText) {
|
||||
$newKey = '${'.$key.'}';
|
||||
$newAttrs[$newKey] = $attrText;
|
||||
}
|
||||
return strtr($filterString, $newAttrs);
|
||||
}
|
||||
|
||||
}
|
@@ -76,9 +76,9 @@ class SocialAuthService
|
||||
throw new UserRegistrationException('This ' . $socialDriver . ' account is already in use, Try logging in via the ' . $socialDriver . ' option.', '/login');
|
||||
}
|
||||
|
||||
if($this->userRepo->getByEmail($socialUser->getEmail())) {
|
||||
if ($this->userRepo->getByEmail($socialUser->getEmail())) {
|
||||
$email = $socialUser->getEmail();
|
||||
throw new UserRegistrationException('The email '. $email.' is already in use. If you already have an account you can connect your ' . $socialDriver .' account from your profile settings.', '/login');
|
||||
throw new UserRegistrationException('The email ' . $email . ' is already in use. If you already have an account you can connect your ' . $socialDriver . ' account from your profile settings.', '/login');
|
||||
}
|
||||
|
||||
return $socialUser;
|
||||
@@ -172,9 +172,10 @@ class SocialAuthService
|
||||
*/
|
||||
private function checkDriverConfigured($driver)
|
||||
{
|
||||
$upperName = strtoupper($driver);
|
||||
$config = [env($upperName . '_APP_ID', false), env($upperName . '_APP_SECRET', false), env('APP_URL', false)];
|
||||
return (!in_array(false, $config) && !in_array(null, $config));
|
||||
$lowerName = strtolower($driver);
|
||||
$configPrefix = 'services.' . $lowerName . '.';
|
||||
$config = [config($configPrefix . 'client_id'), config($configPrefix . 'client_secret'), config('services.callback_url')];
|
||||
return !in_array(false, $config) && !in_array(null, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -193,7 +194,7 @@ class SocialAuthService
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $socialDriver
|
||||
* @param string $socialDriver
|
||||
* @param \Laravel\Socialite\Contracts\User $socialUser
|
||||
* @return SocialAccount
|
||||
*/
|
||||
|
Reference in New Issue
Block a user