symfony/ldap
Symfony LDAP Component: a PHP LDAP client built on top of the PHP ldap extension. Stable since Symfony 3.1, offering tools to connect, bind, search, and manage directory entries. Docs, issues, and PRs are handled in the main Symfony repo.
composer require symfony/ldap
php.ini:
extension=ldap
use Symfony\Component\Ldap\LdapClient;
$client = new LdapClient('ext_ldap', [
'host' => 'ldap.example.com',
'port' => 389,
'encryption' => 'ssl',
'options' => [
LDAP_OPT_PROTOCOL_VERSION => 3,
LDAP_OPT_REFERRALS => 0,
],
]);
use Symfony\Component\Ldap\Entry;
use Symfony\Component\Ldap\Query;
// Bind to LDAP with user credentials
$client->bind('uid=user1,dc=example,dc=com', 'password');
// Search for a user
$query = new Query();
$query->where('uid')->equals('user1');
$results = $client->search('dc=example,dc=com', $query);
$entry = $results->first();
if ($entry) {
$dn = $entry->getDn(); // e.g., "uid=user1,ou=users,dc=example,dc=com"
$attributes = $entry->getAttribute('mail'); // ['user1@example.com']
}
LdapClient:
// In AppServiceProvider::boot()
$this->app->singleton(LdapClient::class, function () {
return new LdapClient('ext_ldap', [
'host' => config('ldap.host'),
'port' => config('ldap.port'),
'encryption' => config('ldap.encryption'),
]);
});
try {
$client->bind(...);
} catch (\Exception $e) {
$client->reset();
$client->bind(...);
}
Query builder:
$query = new Query();
$query
->where('objectClass')->equals('person')
->andWhere('mail')->like('%@example.com')
->orderBy('sn', 'ASC')
->limit(10);
$results = $client->search('ou=users,dc=example,dc=com', $query, ['attributes' => ['cn', 'mail']]);
$results->count(); // Total entries (may exceed limit)
$results->all(); // Load all entries (use cautiously)
$entry = Entry::fromDn('uid=newuser,ou=users,dc=example,dc=com');
$entry->setAttribute('objectClass', ['top', 'person', 'inetOrgPerson']);
$entry->setAttribute('cn', 'New User');
$entry->setAttribute('sn', 'User');
$entry->setAttribute('uid', 'newuser');
$entry->setAttribute('mail', 'newuser@example.com');
$entry->setAttribute('userPassword', 'password');
$client->update($entry);
EntryManager:
$manager = new EntryManager($client);
$manager->update($entry, ['preserveExistingAttributes' => true]);
$query = new Query();
$query->where('member')->equals($userEntry->getDn());
$results = $client->search('ou=groups,dc=example,dc=com', $query);
$isAdmin = $results->count() > 0;
GSSAPI for Kerberos):
$client->bind('uid=user1,dc=example,dc=com', null, [
'mechanism' => 'GSSAPI',
'auth' => 'user1@example.com',
]);
use Illuminate\Contracts\Auth\Authenticatable;
use Symfony\Component\Ldap\Entry;
class LdapUser implements Authenticatable {
protected $entry;
public function __construct(Entry $entry) {
$this->entry = $entry;
}
public function getAuthIdentifier() {
return $this->entry->getDn();
}
public function getAuthPassword() {
return $this->entry->getAttribute('userPassword')[0] ?? '';
}
public function getRoles() {
return $this->entry->getAttribute('memberOf') ?? [];
}
}
use Illuminate\Support\Facades\Cache;
$cacheKey = 'ldap_users_' . md5($query->getWhere());
$results = Cache::remember($cacheKey, now()->addHours(1), function () use ($client, $query) {
return $client->search('dc=example,dc=com', $query);
});
config/ldap.php:
return [
'host' => env('LDAP_HOST', 'ldap.example.com'),
'port' => env('LDAP_PORT', 389),
'encryption' => env('LDAP_ENCRYPTION', 'ssl'),
'base_dn' => 'dc=example,dc=com',
'user_dn_pattern' => 'uid=%s,' . env('LDAP_USER_BASE_DN', 'ou=users,dc=example,dc=com'),
'group_dn_pattern' => 'cn=%s,' . env('LDAP_GROUP_BASE_DN', 'ou=groups,dc=example,dc=com'),
];
Connection Timeouts
'options' => [
LDAP_OPT_TIMEOUT => 10, // 10 seconds
]
Case Sensitivity in DN
ldap extension may not handle this consistently.$dn = strtolower($entry->getDn());
Attribute Name Variations
uid vs. sAMAccountName for AD).'attribute_mappings' => [
'username' => env('LDAP_USERNAME_ATTR', 'uid'),
'email' => env('LDAP_EMAIL_ATTR', 'mail'),
]
Referrals
'options' => [
LDAP_OPT_REFERRALS => 0,
]
Memory Leaks with Large Results
$query->limit(100);
$results = $client->search(..., $query);
SASL Bind Failures
GSSAPI) may fail due to misconfigured Kerberos.// Test simple bind
$client->bind('uid=user1,dc=example,dc=com', 'password');
// Then enable SASL
$client->bind('uid=user1,dc=example,dc=com', null, [
'mechanism' => 'GSSAPI',
]);
Enable LDAP Debugging
LDAP_OPT_DEBUG_LEVEL option to log operations:
'options' => [
LDAP_OPT_DEBUG_LEVEL => 7,
]
**Validate LDAP Filters
How can I help you explore Laravel packages today?