I've been using this Userprovider with Symfony, which extends the original LdapUserProvider and only adds some roles, depending on the ActiveDirectory groups the user is in. It was working fine, but since Symfony 4.4 Symfony\Component\Security\Core\User\LdapUserProvider
is deprecated and Symfony\Component\Ldap\Security\LdapUserProvider
should be used instead.
src/Security/LdapUserProvider.php
namespace App\Security;
use Symfony\Component\Ldap\Entry;
use Symfony\Component\Security\Core\User\LdapUserProvider as SymfonyLdapUserProvider;
#use Symfony\Component\Ldap\Security\LdapUserProvider as SymfonyLdapUserProvider;
use Symfony\Component\Security\Core\User\User;
class LdapUserProvider extends SymfonyLdapUserProvider
{
private static $roles = [
'ROLE_MANAGEMENT' => [
'name' => 'Verwaltung',
'groups' => [
'CN=Verwaltung,OU=Personen,DC=example,DC=com',
],
],
'ROLE_SC' => [
'name' => 'IT',
'groups' => [
'CN=IT-MA,OU=Gruppen,DC=example,DC=com',
],
],
'ROLE_DOMAINADMIN' => [
'name' => 'Domain Admin',
'groups' => [
'CN=Domain Admins,CN=Users,DC=example,DC=com',
],
],
// some more roles ...
];
protected function loadUser($username, Entry $entry)
{
$roles = ['ROLE_USER'];
if ($entry->hasAttribute('memberOf')) {
$roles = array_merge($roles, $this->getRolesFromGroups($entry->getAttribute('memberOf')));
}
$dn = $entry->getAttribute('distinguishedName')[0];
$elements = explode(',', $dn);
$basePath = array_slice($elements, ($_ENV['ADLDAP_BASEDN_DEPTH']*-1));
$_SESSION['currentUser']['baseDn'] = implode(',', $basePath);
return new User($username, null, $roles);
}
private function getRolesFromGroups(array $userGroups)
{
$roles = [];
foreach ($this::$roles as $key => $role) {
foreach ($role['groups'] as $group) {
if (in_array($group, $userGroups)) {
$roles[] = $key;
break;
}
}
}
return $roles;
}
public function supportsClass($class)
{
$test = User::class === $class || is_subclass_of($class, User::class);
dump($test);
return $test;
}
}
However, when I replace Symfony\Component\Security\Core\User\LdapUserProvider
with Symfony\Component\Ldap\Security\LdapUserProvider
I get the following Exception:
There is no user provider for user "Symfony\Component\Security\Core\User\User". Shouldn't the "supportsClass()" method of your user provider return true for this classname?
The funny thing is: I tested the return value of function supportsClass($class)
and it returns true
.
I found some questions like this one:
but they deal with custom User entities, which I don't have. Can anybody give me a hint where this error is coming from, if not from my UserProvider?
Symfony is at version 4.4.29. Excerpts from other relevant files:
config/services.yaml
Symfony\Component\Ldap\Ldap:
arguments: ['@Symfony\Component\Ldap\Adapter\ExtLdap\Adapter']
Symfony\Component\Ldap\Adapter\ExtLdap\Adapter:
arguments:
- host: '%env(ADLDAP_HOST)%'
port: '%env(ADLDAP_PORT)%'
options:
protocol_version: 3
referrals: false
config/packages/security.yaml
security:
providers:
ad:
ldap:
service: Symfony\Component\Ldap\Ldap
base_dn: '%env(ADLDAP_BASEDN)%'
search_dn: '%env(ADLDAP_USERDN)%'
search_password: '%env(ADLDAP_PASSWORD)%'
default_roles: ROLE_USER
uid_key: 'samaccountname'
extra_fields: ['distinguishedName']
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: ~
form_login_ldap:
service: Symfony\Component\Ldap\Ldap
login_path: login
check_path: login
dn_string: '%env(ADLDAP_BASEDN)%'
query_string: '(samaccountname={username})'
logout:
path: /logout
target: login
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_USER }