Skip to content
This repository has been archived by the owner on Jul 24, 2023. It is now read-only.

Commit

Permalink
Clean up authentication logic and forward missing calls to EloquentUs…
Browse files Browse the repository at this point in the history
…erProvider

The cleanup with this logic will assist in the extending of its API. Related: #867
  • Loading branch information
stevebauman committed May 28, 2020
1 parent 9fe6006 commit 51c0f28
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 57 deletions.
169 changes: 117 additions & 52 deletions src/Auth/DatabaseUserProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,19 @@
use Adldap\Laravel\Events\DiscoveredWithCredentials;
use Adldap\Laravel\Events\Imported;
use Adldap\Laravel\Facades\Resolver;
use Adldap\Laravel\Traits\ValidatesUsers;
use Adldap\Models\User;
use Illuminate\Auth\EloquentUserProvider;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Hashing\Hasher as HasherContract;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Traits\ForwardsCalls;

class DatabaseUserProvider extends EloquentUserProvider
/** @mixin EloquentUserProvider */
class DatabaseUserProvider extends UserProvider
{
use ValidatesUsers;
use ForwardsCalls;

/**
* The currently authenticated LDAP user.
Expand All @@ -29,86 +31,149 @@ class DatabaseUserProvider extends EloquentUserProvider
*/
protected $user;

/**
* The fallback eloquent user provider.
*
* @var EloquentUserProvider
*/
protected $eloquent;

/**
* Constructor.
*
* @param HasherContract $hasher
* @param string $model
*/
public function __construct(HasherContract $hasher, $model)
{
$this->eloquent = new EloquentUserProvider($hasher, $model);
}

/**
* Forward missing method calls to the underlying Eloquent provider.
*
* @param string $method
* @param mixed $parameters
*
* @return mixed
*/
public function __call($method, $parameters)
{
return $this->forwardCallTo($this->eloquent, $method, $parameters);
}

/**
* @inheritDoc
*/
public function retrieveById($identifier)
{
return $this->eloquent->retrieveById($identifier);
}

/**
* @inheritDoc
*/
public function retrieveByToken($identifier, $token)
{
return $this->eloquent->retrieveByToken($identifier, $token);
}

/**
* @inheritDoc
*/
public function updateRememberToken(Authenticatable $user, $token)
{
$this->eloquent->updateRememberToken($user, $token);
}

/**
* {@inheritdoc}
*/
public function retrieveByCredentials(array $credentials)
{
// Retrieve the LDAP user who is authenticating.
$user = Resolver::byCredentials($credentials);

if ($user instanceof User) {
// Set the currently authenticating LDAP user.
$this->user = $user;

Event::dispatch(new DiscoveredWithCredentials($user));

// Import / locate the local user account.
return Bus::dispatch(
new Import($user, $this->createModel())
);
return $this->setAndImportAuthenticatingUser($user);
}

if ($this->isFallingBack()) {
return parent::retrieveByCredentials($credentials);
return $this->eloquent->retrieveByCredentials($credentials);
}
}

/**
* Set and import the authenticating LDAP user.
*
* @param User $user
*
* @return \Illuminate\Database\Eloquent\Model
*/
protected function setAndImportAuthenticatingUser(User $user)
{
// Set the currently authenticating LDAP user.
$this->user = $user;

Event::dispatch(new DiscoveredWithCredentials($user));

// Import / locate the local user account.
return Bus::dispatch(
new Import($user, $this->eloquent->createModel())
);
}

/**
* {@inheritdoc}
*/
public function validateCredentials(Authenticatable $model, array $credentials)
{
if ($this->user instanceof User) {
// If an LDAP user was discovered, we can go
// ahead and try to authenticate them.
if (Resolver::authenticate($this->user, $credentials)) {
Event::dispatch(new AuthenticatedWithCredentials($this->user, $model));

// Here we will perform authorization on the LDAP user. If all
// validation rules pass, we will allow the authentication
// attempt. Otherwise, it is automatically rejected.
if ($this->passesValidation($this->user, $model)) {
// Here we can now synchronize / set the users password since
// they have successfully passed authentication
// and our validation rules.
Bus::dispatch(new SyncPassword($model, $credentials));

$model->save();

if ($model->wasRecentlyCreated) {
// If the model was recently created, they
// have been imported successfully.
Event::dispatch(new Imported($this->user, $model));
}

Event::dispatch(new AuthenticationSuccessful($this->user, $model));

return true;
}

Event::dispatch(new AuthenticationRejected($this->user, $model));
}

// LDAP Authentication failed.
// If the user exists in the local database, fallback is enabled,
// and no LDAP user is was located for authentication, we will
// perform standard eloquent authentication to "fallback" to.
if (
$model->exists
&& $this->isFallingBack()
&& !$this->user instanceof User
) {
return $this->eloquent->validateCredentials($model, $credentials);
}

if (!Resolver::authenticate($this->user, $credentials)) {
return false;
}

if ($this->isFallingBack() && $model->exists) {
// If the user exists in our local database already and fallback is
// enabled, we'll perform standard eloquent authentication.
return parent::validateCredentials($model, $credentials);
Event::dispatch(new AuthenticatedWithCredentials($this->user, $model));

// Here we will perform authorization on the LDAP user. If all
// validation rules pass, we will allow the authentication
// attempt. Otherwise, it is automatically rejected.
if (!$this->passesValidation($this->user, $model)) {
Event::dispatch(new AuthenticationRejected($this->user, $model));

return false;
}

Bus::dispatch(new SyncPassword($model, $credentials));

$model->save();

if ($model->wasRecentlyCreated) {
// If the model was recently created, they
// have been imported successfully.
Event::dispatch(new Imported($this->user, $model));
}

return false;
Event::dispatch(new AuthenticationSuccessful($this->user, $model));

return true;
}

/**
* Determines if login fallback is enabled.
*
* @return bool
*/
protected function isFallingBack(): bool
protected function isFallingBack()
{
return Config::get('ldap_auth.login_fallback', false);
}
Expand Down
6 changes: 1 addition & 5 deletions src/Auth/NoDatabaseUserProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,11 @@
use Adldap\Laravel\Events\AuthenticationSuccessful;
use Adldap\Laravel\Events\DiscoveredWithCredentials;
use Adldap\Laravel\Facades\Resolver;
use Adldap\Laravel\Traits\ValidatesUsers;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Support\Facades\Event;

class NoDatabaseUserProvider implements UserProvider
class NoDatabaseUserProvider extends UserProvider
{
use ValidatesUsers;

/**
* {@inheritdoc}
*/
Expand Down
11 changes: 11 additions & 0 deletions src/Auth/UserProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Adldap\Laravel\Auth;

use Adldap\Laravel\Traits\ValidatesUsers;
use Illuminate\Contracts\Auth\UserProvider as UserProviderContract;

abstract class UserProvider implements UserProviderContract
{
use ValidatesUsers;
}

0 comments on commit 51c0f28

Please sign in to comment.