Integrating LDAP and Email Authentication in Laravel Filament


Overview
In this implementation, we enable dual authentication for users in a Laravel Filament application. Users can log in using either:
LDAP Authentication (via an LDAP server)
Email Authentication (via a traditional email/password-based authentication stored in the database)
Step 1: Install Required Packages
To implement LDAP authentication, we need to install the adldap2/adldap2-laravel
package, which allows easy integration of LDAP with Laravel.
Install the LDAP package:
composer require directorytree/ldaprecord-laravel
Publish the configuration files for the LDAP package:
php artisan vendor:publish --provider="LdapRecord\Laravel\LdapServiceProvider"
Step 2: Configure LDAP Authentication
Edit the LDAP Configuration (
config/ldap.php
)Open the
config/ldap.php
configuration file and set it up according to your LDAP server's details. Here's an example of what it might look like:'connections' => [ 'default' => [ 'hosts' => [env('LDAP_HOST', '127.0.0.1')], 'username' => env('LDAP_USERNAME', 'cn=user,dc=local,dc=com'), 'password' => env('LDAP_PASSWORD', 'secret'), 'port' => env('LDAP_PORT', 389), 'base_dn' => env('LDAP_BASE_DN', 'dc=local,dc=com'), 'timeout' => env('LDAP_TIMEOUT', 5), 'use_ssl' => env('LDAP_SSL', false), 'use_tls' => env('LDAP_TLS', false), 'use_sasl' => env('LDAP_SASL', false), 'sasl_options' => [ // 'mech' => 'GSSAPI', ], ],
Configure the Authentication Guard:
In
config/auth.php
, add a custom LDAP guard. For example:'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'db' => [ 'driver' => 'session', 'provider' => 'db_users', // New provider for DB users ], ],
Set up LDAP User Provider:
Also in
config/auth.php
, add a user provider for the LDAP users:```plaintext
'providers' => [ 'users' => [ 'driver' => 'ldap', 'model' => LdapRecord\Models\OpenLDAP\User::class, 'rules' => [], 'scopes' => [], 'database' => [ 'model' => App\Models\User::class, 'sync_passwords' => false, 'sync_attributes' => [ 'name' => 'cn', 'email' => 'mail', 'username' => 'uid' ], ], ],
'db_users' => [ 'driver' => 'eloquent', 'model' => App\Models\User::class, ], ],
### **Step 3: Handle Authentication Logic**
1. \*\*Modify the Login logic (\*\**app/Filament/Admin/Pages/Login.php*)
In this step, you need to modify the login logic to allow both email and LDAP-based logins.
For example, you can check if the email entered by the user matches an LDAP record, and if it doesn't, attempt to authenticate the user from the database:
```plaintext
public function authenticate(): ?LoginResponse
{
try {
$this->rateLimit(5);
} catch (TooManyRequestsException $exception) {
$this->getRateLimitedNotification($exception)?->send();
return null;
}
$data = $this->form->getState();
if (($data['login_type'] ?? 'username') === 'username') {
// LDAP
if (Filament::auth()->attempt([
'uid' => $data['uid'],
'password' => $data['password'],
], $data['remember'] ?? false)) {
$user = Filament::auth()->user();
if (
($user instanceof FilamentUser) &&
(! $user->canAccessPanel(Filament::getCurrentPanel()))
) {
Filament::auth()->logout();
$this->throwFailureValidationException();
}
session()->regenerate();
return app(LoginResponse::class);
} else {
throw ValidationException::withMessages([
'data.uid' => __('filament-panels::pages/auth/login.messages.failed'),
]);
return null;
}
} else {
// Database
if (Auth::guard('db')->attempt([
'email' => $data['email'],
'password' => $data['password'],
], $data['remember'] ?? false)) {
$user = Auth::guard('db')->user();
if (
($user instanceof FilamentUser) &&
(! $user->canAccessPanel(Filament::getCurrentPanel()))
) {
Auth::guard('db')->logout();
$this->throwFailureValidationException();
}
Auth::guard('web')->login($user, $data['remember'] ?? false);
session()->regenerate();
return app(LoginResponse::class);
} else {
throw ValidationException::withMessages([
'data.email' => __('filament-panels::pages/auth/login.messages.failed'),
]);
return null;
}
}
$this->throwFailureValidationException();
}
Modify the Form
public function form(Form $form): Form { return $form ->schema([ Radio::make('login_type') ->label('Login With') ->options([ 'username' => 'Username (LDAP)', 'email' => 'Email' ]) ->default('username') ->inline() ->live() ->required(), // $this->getEmailFormComponent(), TextInput::make('uid') ->label(__('Username')) ->required() ->visible(fn ($get) => $get('login_type') === 'username') ->autocomplete() ->autofocus() ->extraInputAttributes(['tabindex' => 1]), TextInput::make('email') ->label('Email') ->email() ->required() ->visible(fn ($get) => $get('login_type') === 'email') ->autocomplete() ->extraInputAttributes(['tabindex' => 1]), $this->getPasswordFormComponent(), // MyCaptchaField::make('captcha'), $this->getRememberFormComponent(), ]) ->statePath('data'); }
Step 4: Add your credentials to your env file
After making these changes, clear your cache to ensure the configurations are applied correctly:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=employee
DB_USERNAME=root
DB_PASSWORD=
LDAP_CACHE=false
LDAP_LOGGING=true
LDAP_CONNECTION=default
LDAP_HOST=ldap.forumsys.com
LDAP_USERNAME=null
LDAP_PASSWORD=null
LDAP_PORT=389
LDAP_BASE_DN="dc=example,dc=com"
LDAP_TIMEOUT=5
LDAP_SSL=false
LDAP_TLS=false
LDAP_SASL=false
Step 5: Clear Cache
After making these changes, clear your cache to ensure the configurations are applied correctly:
bashCopyphp artisan config:clear
php artisan cache:clear
php artisan route:clear
Conclusion
By following these steps, you’ve successfully integrated both LDAP and email-based authentication in your Laravel Filament application. Users can now log in with either their LDAP credentials or traditional database email/password authentication, giving you flexibility in user management.
Subscribe to my newsletter
Read articles from david ibitoye directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
