I'm using the ldap component on my project in Symfony 4. It works great, authenticates successfully but the only role that I can set on users is the default_role provided in the option of the ldap provider in the security.yaml... All the doc I found wasn't very helpfull whether people use database to manage users or they don't talk about role when they're using the ldap component. Here is my security.yaml if needed :
security.yaml :
security:
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
#in_memory: { memory: null }
my_ldap:
ldap:
service: Symfony\Component\Ldap\Ldap
base_dn: 'my_base_dn'
search_dn: 'my_search_dn'
search_password: '%env(resolve:LDAP_PASSWORD)%'
default_roles: ROLE_USER #rôle par défaut donné à l'utilisateur authentifié
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: ~
form_login_ldap:
provider: my_ldap
service: Symfony\Component\Ldap\Ldap
dn_string: 'my_dn_string'
query_string: '(&(sAMAccountName={username})(memberOf=CN=***))'
login_path: login #route vers laquelle l'utilisateur sera redirigé si il tente d'accéder à une ressource protégé sans être authentifié
#/!\/!\/!\ NE PAS METTRE EN COMMENTAIRE SINON SUPPRESSION DES LOGS D'ERREURS !! /!\/!\/!\
check_path: login #route vers laquelle doit être envoyé la requête POST du formulaire
always_use_default_target_path: true
default_target_path: homePage #page vers laquelle l'utilisateur authentifié est redirigé
logout:
path: app_logout
target: login
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#firewalls-authentication
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true
If anyone have a solution or an idea !!
I am looking for the same feature, but it appears that this hasn't been implemented yet.
However, there is a feature request for this on GitHub.
IF your LDAP saves the group membership as an attribute of the user, one workaround would be to check the user object for this attribute in the controller and possibly deny access. You can create a separate method for this, and make sure to call it in every action method that needs security check, like so:
<?php
namespace App\Controller;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
class SampleController extends AbstractController
{
public function index()
{
$ldapGroup = 'LDAP-User-Group';
$this->denyAccessUnlessLdapGroup($ldapGroup, 'ROLE_USER');
// continue if authenticated
}
/**
* Throws an exception unless the current user is member of the specified ldap group
*
* @throws AccessDeniedException
*
*/
private function denyAccessUnlessLdapGroup($ldapGroup, $attributes, string $message = 'Access Denied.') {
$ldapAttribute = 'memberof';
// usually you'll want to make sure the user is authenticated first
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
// returns your User object, or null if the user is not authenticated
// use inline documentation to tell your editor your exact User class
// in this case: \Symfony\Component\Ldap\Security\LdapUser
/** @var \App\Entity\User $user */
$user = $this->getUser();
/** @var \Synfony\Component\Ldap\Entry $entry */
$entry = $user->getEntry();
if(!$entry->getAttribute($ldapAttribute) ||
!in_array($ldapGroup, $entry->getAttribute($ldapAttribute))) {
$exception = $this->createAccessDeniedException($message);
$exception->setAttributes($attributes);
throw $exception;
}
}
}
Make sure to customize $ldapGroup
and ldapAttribute
. The value passed to $attributes
is meaningless at this point; I have kept it for consistency for the other denyAccess*
methods.