Skip to content

Commit

Permalink
Updated laravel to 5.2 and started ldap implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
ssddanbrown committed Jan 9, 2016
1 parent e27a630 commit 14ca317
Show file tree
Hide file tree
Showing 20 changed files with 907 additions and 474 deletions.
6 changes: 6 additions & 0 deletions app/Exceptions/Handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -14,7 +17,10 @@ class Handler extends ExceptionHandler
* @var array
*/
protected $dontReport = [
AuthorizationException::class,
HttpException::class,
ModelNotFoundException::class,
ValidationException::class,
];

/**
Expand Down
9 changes: 9 additions & 0 deletions app/Exceptions/LdapException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php namespace BookStack\Exceptions;


use Exception;

class LdapException extends Exception
{

}
11 changes: 3 additions & 8 deletions app/Http/Controllers/Auth/AuthController.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ class AuthController extends Controller

use AuthenticatesAndRegistersUsers, ThrottlesLogins;

protected $loginPath = '/login';
protected $redirectPath = '/';
protected $redirectAfterLogout = '/login';

Expand Down Expand Up @@ -232,13 +231,9 @@ public function resendConfirmation(Request $request)
*/
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]);
}

/**
Expand All @@ -253,7 +248,7 @@ public function getSocialLogin($socialDriver)
}

/**
* Redirect to the social site for authentication initended to register.
* Redirect to the social site for authentication intended to register.
* @param $socialDriver
* @return mixed
*/
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Controllers/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public function __construct()
*/
protected function preventAccessForDemoUsers()
{
if (env('APP_ENV', 'production') === 'demo') $this->showPermissionError();
if (config('app.env') === 'demo') $this->showPermissionError();
}

/**
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Controllers/UserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public function store(Request $request)
$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();
Expand Down
6 changes: 6 additions & 0 deletions app/Http/routes.php
Original file line number Diff line number Diff line change
@@ -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 () {

Expand Down
31 changes: 31 additions & 0 deletions app/Providers/AuthServiceProvider.php
Original file line number Diff line number Diff line change
@@ -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 changes: 117 additions & 0 deletions app/Providers/LdapUserProvider.php
Original file line number Diff line number Diff line change
@@ -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.
}
}
6 changes: 3 additions & 3 deletions app/Services/ImageService.php
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ private function getStorage()
{
if ($this->storageInstance !== null) return $this->storageInstance;

$storageType = env('STORAGE_TYPE');
$storageType = config('filesystems.default');
$this->storageInstance = $this->fileSystem->disk($storageType);

return $this->storageInstance;
Expand All @@ -226,10 +226,10 @@ private function isFolderEmpty($path)
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'];
}
Expand Down
60 changes: 60 additions & 0 deletions app/Services/LdapService.php
Original file line number Diff line number Diff line change
@@ -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);
}

}
13 changes: 7 additions & 6 deletions app/Services/SocialAuthService.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ public function handleRegistrationCallback($socialDriver)
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;
Expand Down Expand Up @@ -172,9 +172,10 @@ private function validateDriver($socialDriver)
*/
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);
}

/**
Expand All @@ -193,7 +194,7 @@ public function getActiveDrivers()
}

/**
* @param string $socialDriver
* @param string $socialDriver
* @param \Laravel\Socialite\Contracts\User $socialUser
* @return SocialAccount
*/
Expand Down
6 changes: 4 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"type": "project",
"require": {
"php": ">=5.5.9",
"laravel/framework": "5.1.*",
"laravel/framework": "5.2.*",
"intervention/image": "^2.3",
"laravel/socialite": "^2.0",
"barryvdh/laravel-ide-helper": "^2.1",
Expand All @@ -17,7 +17,9 @@
"fzaninotto/faker": "~1.4",
"mockery/mockery": "0.9.*",
"phpunit/phpunit": "~4.0",
"phpspec/phpspec": "~2.1"
"phpspec/phpspec": "~2.1",
"symfony/dom-crawler": "~3.0",
"symfony/css-selector": "~3.0"
},
"autoload": {
"classmap": [
Expand Down
Loading

0 comments on commit 14ca317

Please sign in to comment.