directorytree/ldaprecord-laravel
Laravel integration for LdapRecord: authenticate and sync users against Active Directory/LDAP, manage directory connections, and map LDAP attributes to Eloquent models. Includes config, migrations, middleware, and easy-to-use auth/user providers.
Installation:
composer require directorytree/ldaprecord-laravel
Publish the config and migrations:
php artisan vendor:publish --provider="DirectoryTree\LdapRecord\Laravel\LdapRecordServiceProvider"
php artisan migrate
Configure LDAP Connection:
Edit config/ldap.php with your LDAP server details (host, base DN, bind credentials, etc.).
Example for Active Directory:
'connections' => [
'ad' => [
'host' => 'ldap.example.com',
'port' => 389,
'use_ssl' => true,
'base_dn' => 'dc=example,dc=com',
'username' => 'cn=admin,dc=example,dc=com',
'password' => 'password',
'account_suffix' => '@example.com',
],
],
First Use Case: LDAP Authentication
Create a model extending DirectoryTree\LdapRecord\Laravel\LdapModel:
use DirectoryTree\LdapRecord\Laravel\LdapModel;
class User extends LdapModel
{
protected $ldapConnection = 'ad';
protected $ldapBaseDn = 'ou=users,dc=example,dc=com';
protected $ldapUsernameAttribute = 'sAMAccountName';
protected $ldapPasswordAttribute = 'userPassword';
}
Configure the auth guard in config/auth.php:
'guards' => [
'ldap' => [
'driver' => 'ldap',
'provider' => 'ldap',
],
],
'providers' => [
'ldap' => [
'driver' => 'ldap',
'model' => User::class,
'connection' => 'ad',
],
],
Test authentication in a controller:
use Illuminate\Support\Facades\Auth;
public function login(Request $request)
{
$credentials = $request->validate([
'username' => 'required|string',
'password' => 'required|string',
]);
if (Auth::guard('ldap')->attempt($credentials)) {
return redirect()->intended('/dashboard');
}
return back()->withErrors(['credentials' => 'Invalid credentials']);
}
Standard Flow:
Use Laravel’s built-in Auth::guard('ldap')->attempt() with LDAP credentials.
if (Auth::guard('ldap')->attempt(['username' => 'jdoe', 'password' => 'secret'])) {
// Authenticated
}
Custom Rules:
Extend DirectoryTree\LdapRecord\Laravel\Auth\LdapUserProvider to add custom validation:
use DirectoryTree\LdapRecord\Laravel\Auth\LdapUserProvider;
class CustomLdapUserProvider extends LdapUserProvider
{
public function validateCredentials(User $user, $credentials)
{
if (!parent::validateCredentials($user, $credentials)) {
return false;
}
// Custom logic (e.g., check account expiry from LDAP)
return $user->getAttribute('accountExpiry') > time();
}
}
Multi-Domain Auth:
Use multiple connections in config/ldap.php and route users dynamically:
$connection = $request->input('domain') === 'example.com' ? 'ad' : 'ldap';
Auth::guard('ldap')->setConnection($connection);
CRUD Operations: Use Eloquent-like syntax for LDAP queries:
// Find a user
$user = User::where('mail', 'john@example.com')->first();
// Create/update (syncs with LDAP)
$user->update(['mail' => 'new@example.com', 'title' => 'Developer']);
// Delete (soft or hard)
$user->delete(); // Soft delete (uses `deleted_at`)
$user->forceDelete(); // Hard delete
Bulk Imports:
Use the ldap:import Artisan command:
php artisan ldap:import --connection=ad --base-dn="ou=users" --model=User --scopes="active"
Customize with scopes or filters:
// Define a scope in your User model
public function scopeActive($query)
{
return $query->where('accountStatus', 'active');
}
Attribute Mapping: Map LDAP attributes to Eloquent fields in the model:
protected $ldapAttributes = [
'mail' => 'email',
'givenName' => 'first_name',
'sn' => 'last_name',
'telephoneNumber' => 'phone',
'memberOf' => 'groups', // Virtual attribute
];
Sync Strategies:
Use LdapImporter for custom sync logic:
use DirectoryTree\LdapRecord\Laravel\LdapImporter;
$importer = new LdapImporter(User::class, $connection);
$importer->setResolveStrategy('merge'); // 'skip', 'delete', or 'merge'
$importer->import();
Event-Driven Sync: Listen for LDAP events to trigger workflows:
// In EventServiceProvider
protected $listen = [
'DirectoryTree\LdapRecord\Events\RulePassed' => [
'App\Listeners\LogLdapAuthSuccess',
],
'DirectoryTree\LdapRecord\Events\RuleFailed' => [
'App\Listeners\NotifyLdapAuthFailure',
],
];
Fluent Query Builder: Chain queries like Eloquent:
$users = User::where('department', 'Engineering')
->where('title', 'like', '%Developer%')
->orderBy('sn')
->get();
Virtual Attributes:
Define computed fields (e.g., memberOf):
public function getMemberOfAttribute()
{
return $this->getAttribute('memberOf') ?? [];
}
Directory Emulator: Test locally without LDAP:
// In config/ldap.php
'emulator' => [
'enabled' => env('LDAP_EMULATOR_ENABLED', false),
],
Run tests against the emulator:
$this->actingAs($user, 'ldap');
Hashing:
Use HasLdapPassword trait for secure password handling:
use DirectoryTree\LdapRecord\Laravel\HasLdapPassword;
class User extends LdapModel
{
use HasLdapPassword;
}
Password Policies:
Enforce rules via LdapUserProvider:
public function validatePassword($password, $user)
{
$validator = Validator::make(
['password' => $password],
[
'password' => [
'required',
'min:8',
'regex:/[A-Z]/', // At least one uppercase
'regex:/[0-9]/', // At least one number
],
]
);
return !$validator->fails();
}
Laravel Nova: Extend Nova resources to manage LDAP users:
public static $search = [
'mail',
'sn',
'givenName',
];
Laravel Passport: Combine LDAP auth with OAuth:
Auth::guard('ldap')->onceUsing(function () {
// Custom logic to issue tokens
});
Laravel Cashier: Sync subscriptions with LDAP groups:
$user->groups->contains('premium') ? $user->newTrial() : $user->cancel();
Batch Processing:
Use chunk() for large imports:
User::chunk(100, function ($users) {
foreach ($users as $user) {
// Process each user
}
});
Connection Pooling:
Enable in config/ldap.php:
'pool' => [
'enabled' => true,
'max_connections' => 10,
],
use DirectoryTree\Ld
How can I help you explore Laravel packages today?