From f603c6ce635ddd1d8e6008598f7d23c426c9e64f Mon Sep 17 00:00:00 2001 From: PhilVanB Date: Thu, 23 May 2024 14:35:07 +0200 Subject: [PATCH 1/3] Refactored LdapBundle to work with Mapbender v4.0 --- CHANGELOG.md | 3 + Component/LdapClient.php | 85 -------------- .../Factory/MapbenderLDAPLoginFactory.php | 45 -------- .../MissconfiguredLDAPClientException.php | 19 ---- MapbenderLDAPBundle.php | 11 -- README.md | 93 ++++++++++++++++ Resources/config/services.yml | 105 ++++++++++-------- Security/LdapClient.php | 57 ++++++++++ Security/LdapGroup.php | 17 +++ Security/{User/LDAPUser.php => LdapUser.php} | 28 +++-- Security/LdapUserProvider.php | 102 +++++++++++++++++ Security/MapbenderLdapAuthenticator.php | 81 ++++++++++++++ .../Permission/SubjectDomainLdapGroup.php | 84 ++++++++++++++ .../Permission/SubjectDomainLdapTrait.php | 26 +++++ Security/Permission/SubjectDomainLdapUser.php | 78 +++++++++++++ Security/Provider/LDAPGroupProvider.php | 90 --------------- Security/Provider/LDAPIdentitiesProvider.php | 27 ----- Security/Provider/LDAPUserProvider.php | 83 -------------- ...apbenderLdapBindAuthenticationProvider.php | 60 ---------- Security/User/MapbenderGroupInterface.php | 13 --- 20 files changed, 614 insertions(+), 493 deletions(-) delete mode 100644 Component/LdapClient.php delete mode 100644 DependencyInjection/Factory/MapbenderLDAPLoginFactory.php delete mode 100644 Exceptions/MissconfiguredLDAPClientException.php create mode 100644 Security/LdapClient.php create mode 100644 Security/LdapGroup.php rename Security/{User/LDAPUser.php => LdapUser.php} (61%) create mode 100644 Security/LdapUserProvider.php create mode 100644 Security/MapbenderLdapAuthenticator.php create mode 100644 Security/Permission/SubjectDomainLdapGroup.php create mode 100644 Security/Permission/SubjectDomainLdapTrait.php create mode 100644 Security/Permission/SubjectDomainLdapUser.php delete mode 100644 Security/Provider/LDAPGroupProvider.php delete mode 100644 Security/Provider/LDAPIdentitiesProvider.php delete mode 100644 Security/Provider/LDAPUserProvider.php delete mode 100644 Security/Provider/MapbenderLdapBindAuthenticationProvider.php delete mode 100644 Security/User/MapbenderGroupInterface.php diff --git a/CHANGELOG.md b/CHANGELOG.md index ee4393e..66687d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## v2.0.0 +* Refactored LdapBundle to work with Mapbender v4.0 + ## v1.1.4 * Add toString() function for LdapUser: Fixes storage of LDAP username in database diff --git a/Component/LdapClient.php b/Component/LdapClient.php deleted file mode 100644 index 36ab0af..0000000 --- a/Component/LdapClient.php +++ /dev/null @@ -1,85 +0,0 @@ -= 3) - /** @see \Symfony\Component\Ldap\Adapter\AbstractConnection::configureOptions for possible options */ - $adapterOptions = array_filter(array( - 'host' => $host, - 'version' => $version, - 'port' => $port, - )); - if ($useSsl) { - $adapterOptions['encryption'] = 'ssl'; - } - if ($useTls) { - $adapterOptions['encryption'] = 'tls'; - } - $this->adapter = new Adapter($adapterOptions); - parent::__construct($host, $port, $version, $bindDn, $bindPassword); - } - - public function bind($dn = null, $password = null) - { - $this->adapter->getConnection()->bind($dn ?: $this->bindDn, $password ?: $this->bindPassword); - } - - public function query($dn, $query, array $options = []) - { - return $this->adapter->createQuery($dn, $query, $options); - } - - public function getEntryManager() - { - return $this->adapter->getEntryManager(); - } - - public function escape($subject, $ignore = '', $flags = 0) - { - return $this->adapter->escape($subject, $ignore, $flags); - } - - /** - * FOM client compatibility - * @see \FOM\UserBundle\Component\Ldap\Client::getObjects - * - * @param $baseDn - * @param $filter - * @return \array[][] - */ - public function getObjects($baseDn, $filter) - { - if (!$this->host) { - return array(); - } - if (!$this->adapter->getConnection()->isBound()) { - $this->adapter->getConnection()->bind($this->bindDn, $this->bindPassword); - } - $query = $this->adapter->createQuery($baseDn, $filter, array( - 'scope' => QueryInterface::SCOPE_ONE, - )); - $records = array(); - foreach ($query->execute() as $entry) { - $records[] = $entry->getAttributes(); - } - return $records; - } - - public function getHost() - { - return $this->host; - } -} diff --git a/DependencyInjection/Factory/MapbenderLDAPLoginFactory.php b/DependencyInjection/Factory/MapbenderLDAPLoginFactory.php deleted file mode 100644 index 92423c3..0000000 --- a/DependencyInjection/Factory/MapbenderLDAPLoginFactory.php +++ /dev/null @@ -1,45 +0,0 @@ -getParameterBag()->resolveValue('%ldap.user.dn%'), - $container->getParameterBag()->resolveValue('%ldap.user.query%'), - $container->getParameterBag()->resolveValue('%ldap.bind.dn%'), - $container->getParameterBag()->resolveValue('%ldap.bind.pwd%'), - )); - $container->setDefinition($providerId, $providerDefinition); - - return $providerId; - } - - public function getKey() - { - return 'mapbender-ldap'; - } - -} diff --git a/Exceptions/MissconfiguredLDAPClientException.php b/Exceptions/MissconfiguredLDAPClientException.php deleted file mode 100644 index a13d490..0000000 --- a/Exceptions/MissconfiguredLDAPClientException.php +++ /dev/null @@ -1,19 +0,0 @@ -load('services.yml'); $container->addResource(new FileResource($configLocator->locate('services.yml'))); - - $extension = $container->getExtension('security'); - $extension->addSecurityListenerFactory(new MapbenderLDAPLoginFactory()); - } - - public function getContainerExtension() - { - return null; } } diff --git a/README.md b/README.md index 094e58a..eb71d7b 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,99 @@ The LDAP Bundle provides LDAP integration for Mapbender. Install Mapbender LDAP via Composer: +```sh +composer require mapbender/ldapbundle +``` +Register the bundle in bundles.php: + +```php +Mapbender\LDAPBundle\MapbenderLDAPBundle::class => ['all' => true], +``` + +Enable the LDAP extension for php. + +### 2. Configuration + +In the `security.yml` add the ldap- and chain-provider, some firewall configuration and a password hasher for the LdapUser: + +```yml +... + +providers: + main: + entity: + class: FOM\UserBundle\Entity\User + property: username + ldap_provider: + id: 'mapbender.ldap.user_provider' + all_users: + chain: + providers: ['main', 'ldap_provider'] +... + +firewalls: + + ... + + secured_area: + pattern: ^/ + entry_point: form_login + provider: all_users + custom_authenticators: + - 'mapbender.ldap.authenticator' + form_login: + check_path: /user/login/check + login_path: /user/login + enable_csrf: true + form_login_ldap: + check_path: /user/login/check + login_path: /user/login + enable_csrf: true + logout: + path: /user/logout + target: / + +... + +password_hashers: + FOM\UserBundle\Entity\User: sha512 + Mapbender\LDAPBundle\Security\LdapUser: auto + +... +``` + +Add your LDAP server settings at the bottom of the `parameters.yml`: + +```yml +ldap.host: ldap.example.com +ldap.port: 389 +ldap.version: 3 +ldap.encryption: none # +ldap.bind.dn: read@example.com +ldap.bind.pwd: passwort + +ldap.user.baseDn: cn=users,dc=example,dc=com +ldap.user.query: (&(sAMAccountName={username})(objectClass=user)) +ldap.user.adminQuery: (objectClass=user) +ldap.user.id: sAMAccountName +ldap.user.commonName: cn +ldap.user.groupKey: memberOf + +ldap.group.baseDn: ou=groups,dc=example,dc=com +ldap.group.query: (&(distinguishedName={groupname})(objectClass=group)) +ldap.group.adminQuery: (objectClass=group) +ldap.group.id: sAMAccountName +ldap.group.commonName: cn +ldap.group.defaultRoles: [ROLE_USER] # this should be ROLE_USER in most cases +``` + +--- +### Follow these instructions if you use Mapbender v3.3.5 or older: + +### 1. Installation + +Install Mapbender LDAP via Composer: + ```sh composer require mapbender/ldapbundle ``` diff --git a/Resources/config/services.yml b/Resources/config/services.yml index 2abb417..057ddfe 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -1,57 +1,66 @@ -parameters: - # Alias to values Mapbender ACL assignment machinery evaluates - ## for fom.ldap_user_identities_provider - ldap_user_base_dn: '%ldap.user.baseDN%' - ldap_user_name_attribute: '%ldap.user.nameAttribute%' - ldap_user_filter: '%ldap.user.adminFilter%' - ## for fom.ldap_client - ldap_host: '%ldap.host%' - ldap_port: '%ldap.port%' - ldap_version: '%ldap.version%' - ldap_bind_dn: '%ldap.bind.dn%' - ldap_bind_pwd: '%ldap.bind.pwd%' +services: + Symfony\Component\Ldap\Ldap: + arguments: ['@Symfony\Component\Ldap\Adapter\ExtLdap\Adapter'] + tags: + - ldap -# Fix bad parameter case baseDN (expected) vs baseDn (from bad example config in README.md) -# parameter names are now case sensitive - ldap.user.baseDN: '%ldap.user.baseDn%' - ldap.group.baseDN: '%ldap.group.baseDn%' - ldap.group.id: cn - ldap.group.role_prefix: ROLE_GROUP_ + Symfony\Component\Ldap\Adapter\ExtLdap\Adapter: + arguments: + - host: '%ldap.host%' + - port: '%ldap.port%' + - encryption: '%ldap.encryption' + - options: + protocol_version: '%ldap.version' + referrals: false -services: - ldapClient: - class: Mapbender\LDAPBundle\Component\LdapClient + mapbender.ldap.client: + class: Mapbender\LDAPBundle\Security\LdapClient arguments: - - '%ldap.host%' #Address to LDAPServer - - '%ldap.port%' #Port where LDAPServer is listening - - '%ldap.version%' #LDAP Protocol version - - '%ldap.useSSL%' # SSL #Use SSL - - '%ldap.useTLS%' # TLS 'Use TLS + - '%ldap.host%' + - '%ldap.port%' + - '%ldap.version%' + - '%ldap.encryption%' - '%ldap.bind.dn%' - '%ldap.bind.pwd%' - LDAPUserProvider: - class: Mapbender\LDAPBundle\Security\Provider\LDAPUserProvider + + mapbender.ldap.user_provider: + class: Mapbender\LDAPBundle\Security\LdapUserProvider arguments: - - '@ldapClient' - - '@mbldap.group_identities_provider' - - '%ldap.user.baseDN%' + - '@mapbender.ldap.client' + - '%ldap.user.baseDn%' - '%ldap.user.query%' - - [ROLE_USER] - mbldap.group_identities_provider: - class: Mapbender\LDAPBundle\Security\Provider\LDAPGroupProvider - arguments: - - '@fom.ldap_client' - - '%ldap.group.baseDN%' - - '%ldap.group.id%' - - '%ldap.group.adminFilter%' + - '%ldap.user.groupKey%' + - '%ldap.group.baseDn%' - '%ldap.group.query%' - - '%ldap.group.role_prefix%' - fom.ldap_client: - alias: ldapClient - fom.identities.provider: - class: Mapbender\LDAPBundle\Security\Provider\LDAPIdentitiesProvider + - '%ldap.group.id%' + - '%ldap.group.defaultRoles%' + + mapbender.ldap.authenticator: + class: Mapbender\LDAPBundle\Security\MapbenderLdapAuthenticator + arguments: + - '@security.authenticator.form_login.secured_area' + - '@mapbender.ldap.client' + - '%ldap.user.baseDn%' + - '%ldap.user.query%' + + ldap.security.subject_domain.user: + class: Mapbender\LDAPBundle\Security\Permission\SubjectDomainLdapUser + tags: + - fom.security.subject_domain + arguments: + - '@mapbender.ldap.client' + - '%ldap.user.baseDn%' + - '%ldap.user.adminQuery%' + - '%ldap.user.id%' + - '%ldap.user.commonName%' + + ldap.security.subject_domain.group: + class: Mapbender\LDAPBundle\Security\Permission\SubjectDomainLdapGroup + tags: + - fom.security.subject_domain arguments: - - '@doctrine' - - '@fom.ldap_user_identities_provider' - - '@mbldap.group_identities_provider' - - '%fom.user_entity%' + - '@mapbender.ldap.client' + - '%ldap.group.baseDn%' + - '%ldap.group.adminQuery%' + - '%ldap.group.id%' + - '%ldap.group.commonName%' diff --git a/Security/LdapClient.php b/Security/LdapClient.php new file mode 100644 index 0000000..4bc362f --- /dev/null +++ b/Security/LdapClient.php @@ -0,0 +1,57 @@ + $host, + 'port' => $port, + 'version' => $version, + 'encryption' => $encryption, + ]); + $this->adapter = new Adapter($adapterOptions); + $this->host = $host; + $this->bindDn = $bindDn; + $this->bindPwd = $bindPwd; + } + + public function bind($dn = null, $password = null) + { + $this->adapter->getConnection()->bind($dn ?: $this->bindDn, $password ?: $this->bindPwd); + } + + public function query($dn, $query, array $options = []) + { + return $this->adapter->createQuery($dn, $query, $options); + } + + public function escape($subject, $ignore = '', $flags = 0) + { + return $this->adapter->escape($subject, $ignore, $flags); + } + + public function getHost() + { + return $this->host; + } + + public function getBindDn() + { + return $this->bindDn; + } + + public function getBindPwd() + { + return $this->bindPwd; + } +} diff --git a/Security/LdapGroup.php b/Security/LdapGroup.php new file mode 100644 index 0000000..32305d6 --- /dev/null +++ b/Security/LdapGroup.php @@ -0,0 +1,17 @@ +roles = $roles; } - public function getRoles() + public function getRoles(): array { return $this->roles; } - public function getPassword() + public function getPassword(): string { - return ''; + return ''; } public function getSalt() @@ -46,15 +47,18 @@ public function eraseCredentials() return false; } - /* - * This is uses to create proper ACEs in Mapbender - */ - public function getClass() { - return 'Mapbender\LDAPBundle\Security\User\LDAPUser'; - } - public function __toString() { return $this->getUsername() ?: ''; } + + public function getId() + { + return null; + } + + public function getUserIdentifier(): string + { + return $this->getUsername(); + } } diff --git a/Security/LdapUserProvider.php b/Security/LdapUserProvider.php new file mode 100644 index 0000000..6214f6e --- /dev/null +++ b/Security/LdapUserProvider.php @@ -0,0 +1,102 @@ + + */ +class LdapUserProvider implements UserProviderInterface +{ + private $client; + private $baseDn; + private $query; + private $groupKey; + private $baseDnGroup; + private $queryGroup; + private $idGroup; + private $defaultRoles; + + /** + * @param LdapClient $client + * @param string $baseDn + * @param string $query + * @param string $groupKey + * @param string $baseDnGroup + * @param string $queryGroup + * @param string $idGroup + * @param string[] $defaultRoles + */ + public function __construct(LdapClient $client, $baseDn, $query, $groupKey, $baseDnGroup, $queryGroup, $idGroup, $defaultRoles = ['ROLE_USER']) + { + $this->client = $client; + $this->baseDn = $baseDn; + $this->query = $query; + $this->groupKey = $groupKey; + $this->baseDnGroup = $baseDnGroup; + $this->queryGroup = $queryGroup; + $this->idGroup = $idGroup; + $this->defaultRoles = $defaultRoles; + } + + /** + * {@inheritdoc} + */ + public function refreshUser(UserInterface $user) + { + if (!$user instanceof LdapUser) { + throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user))); + } + + return new LdapUser($user->getUsername(), $user->getRoles()); + } + + public function loadUserByIdentifier(string $username): UserInterface + { + // NOTE: when wrapped in a chain provider, UserNameNotFoundException is caught and silently + // skips to the next provider, if any + /** @see \Symfony\Component\Security\Core\User\ChainUserProvider::loadUserByUsername() */ + if (!$this->client->getHost()) { + throw new UsernameNotFoundException('LDAP lookup disabled with empty host configuration', 0); + } + + $this->client->bind(); + $queryString = str_replace('{username}', $this->client->escape($username, '', LDAP_ESCAPE_FILTER), $this->query); + $results = $this->client->query($this->baseDn, $queryString)->execute(); + + if ($results->count() === 1) { + $roles = $this->findLdapUserRoles($results[0]); + return new LdapUser($username, $roles); + } else { + throw new UsernameNotFoundException(sprintf('User "%s" could not be fetched from LDAP.', $username), 0); + } + } + + public function supportsClass($class) + { + return true; + } + + protected function findLdapUserRoles(Entry $user) + { + $roles = []; + + foreach ($user->getAttribute($this->groupKey) as $role) { + $queryString = str_replace('{groupname}', $this->client->escape($role, '', LDAP_ESCAPE_FILTER), $this->queryGroup); + $results = $this->client->query($this->baseDnGroup, $queryString)->execute(); + if ($results->count() === 1) { + $roles[] = $results[0]->getAttribute($this->idGroup)[0]; + } + } + + return \array_unique(\array_merge($this->defaultRoles, $roles)); + } +} diff --git a/Security/MapbenderLdapAuthenticator.php b/Security/MapbenderLdapAuthenticator.php new file mode 100644 index 0000000..d5e629a --- /dev/null +++ b/Security/MapbenderLdapAuthenticator.php @@ -0,0 +1,81 @@ +authenticator = $authenticator; + $this->client = $client; + $this->baseDn = $baseDn; + $this->query = $query; + } + + protected function getLoginUrl(Request $request): string + { + return $this->httpUtils->generateUri($request, $this->options['login_path']); + } + + public function supports(Request $request): bool + { + return $this->authenticator->supports($request); + } + + public function authenticate(Request $request): Passport + { + $passport = $this->authenticator->authenticate($request); + $username = $passport->getUser()->getUsername(); + $this->client->bind(); + $queryString = str_replace('{username}', $this->client->escape($username, '', LDAP_ESCAPE_FILTER), $this->query); + $query = $this->client->query($this->baseDn, $queryString, [ + 'scope' => QueryInterface::SCOPE_ONE, + ]); + $results = $query->execute(); + + if ($results->count() === 1) { + $bindDn = $this->client->getBindDn(); + $bindPwd = $this->client->getBindPwd(); + $passport->addBadge(new LdapBadge('Symfony\Component\Ldap\Ldap', $this->baseDn, $bindDn, $bindPwd, $this->query)); + return $passport; + } + + return $passport; + } + + public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response + { + return $this->authenticator->onAuthenticationSuccess($request, $token, $firewallName); + } + + public function onAuthenticationFailure(Request $request, AuthenticationException $exception): Response + { + return $this->authenticator->onAuthenticationFailure($request, $exception); + } +} + + diff --git a/Security/Permission/SubjectDomainLdapGroup.php b/Security/Permission/SubjectDomainLdapGroup.php new file mode 100644 index 0000000..0de9f7e --- /dev/null +++ b/Security/Permission/SubjectDomainLdapGroup.php @@ -0,0 +1,84 @@ +orWhere("p.subjectDomain = '" . self::SLUG . "' AND p.subject IN (:groups)") + ->setParameter('groups', $user->getRoles()) + ; + } + } + + function getIconClass(): string + { + return 'fas fa-users'; + } + + public function getTitle(SubjectInterface $subject): string + { + return $subject->getSubject(); + } + + public function getAssignableSubjects(): array + { + $this->client->bind(); + $query = $this->client->query($this->baseDn, $this->query, [ + 'scope' => QueryInterface::SCOPE_ONE, + ]); + $ldapGroups = []; + + foreach ($query->execute() as $entry) { + $ldapGroups[] = [ + 'id' => $entry->getAttribute($this->id)[0], + 'cn' => $entry->getAttribute($this->commonName)[0], + ]; + } + + + return array_map( + fn($group) => new AssignableSubject( + self::SLUG, + $group['cn'], + $this->getIconClass(), + null, + null, + $group['id'] + ), + $ldapGroups + ); + } + + public function supports(mixed $subject, ?string $action = null): bool + { + return $subject instanceof LdapGroup; + } + + public function populatePermission(Permission $permission, mixed $subject): void + { + parent::populatePermission($permission, $subject); + $permission->setGroup($subject); + } +} diff --git a/Security/Permission/SubjectDomainLdapTrait.php b/Security/Permission/SubjectDomainLdapTrait.php new file mode 100644 index 0000000..e5a8e4e --- /dev/null +++ b/Security/Permission/SubjectDomainLdapTrait.php @@ -0,0 +1,26 @@ +client = $client; + $this->baseDn = $baseDn; + $this->query = $query; + $this->id = $id; + $this->commonName = $commonName; + } +} diff --git a/Security/Permission/SubjectDomainLdapUser.php b/Security/Permission/SubjectDomainLdapUser.php new file mode 100644 index 0000000..8b58d08 --- /dev/null +++ b/Security/Permission/SubjectDomainLdapUser.php @@ -0,0 +1,78 @@ +orWhere("p.subjectDomain = '" . self::SLUG . "' AND p.subject = :username") + ->setParameter('username', $user->getUsername()) + ; + } + } + + public function getTitle(SubjectInterface $subject): string + { + return $subject->getSubject(); + } + + public function getAssignableSubjects(): array + { + $this->client->bind(); + $query = $this->client->query($this->baseDn, $this->query, [ + 'scope' => QueryInterface::SCOPE_ONE, + ]); + $ldapUsers = []; + + foreach ($query->execute() as $entry) { + $ldapUsers[] = [ + 'id' => $entry->getAttribute($this->id)[0], + 'cn' => $entry->getAttribute($this->commonName)[0], + ]; + } + + return array_map( + fn($user) => new AssignableSubject( + self::SLUG, + $user['cn'], + $this->getIconClass(), + null, + null, + $user['id'] + ), + $ldapUsers + ); + } + + public function supports(mixed $subject, ?string $action = null): bool + { + return $subject instanceof LdapUser; + } + + public function populatePermission(Permission $permission, mixed $subject): void + { + parent::populatePermission($permission, $subject); + $permission->setUser($subject); + } +} diff --git a/Security/Provider/LDAPGroupProvider.php b/Security/Provider/LDAPGroupProvider.php deleted file mode 100644 index 655f94c..0000000 --- a/Security/Provider/LDAPGroupProvider.php +++ /dev/null @@ -1,90 +0,0 @@ -client = $client; - $this->baseDn = $baseDn; - $this->identifierAttribute = $identifierAttribute; - $this->filter = $filter; - $this->queryTemplate = $queryTemplate; - $this->rolePrefix = $rolePrefix; - } - - /** - * @return DummyGroup[] - */ - public function getGroups() - { - $groups = array(); - foreach ($this->client->getObjects($this->baseDn, $this->filter) as $record) { - $groups[] = $this->transformGroupRecord($record); - - } - return $groups; - } - - /** - * @param array $record - * @return DummyGroup - */ - protected function transformGroupRecord(array $record) - { - $identifier = $record[$this->identifierAttribute][0]; - $role = $this->rolePrefix . strtoupper($identifier); - $title = $this->mb_ucfirst($identifier) . ' (LDAP)'; - return new DummyGroup($role, $title); - } - - /** - * @param Entry $user - * @param string $name - * @return string[] - */ - public function getRolesByUserEntry(Entry $user, $name) - { - $query = $this->queryTemplate; - $query = \str_replace('{userDN}', $this->client->escape($user->getDn(), LDAP_ESCAPE_FILTER), $query); - $query = \str_replace('{username}', $this->client->escape($name, LDAP_ESCAPE_FILTER), $query); - - $roleNames = array(); - $ldapGroups = $this->client->query($this->baseDn, $query)->execute(); - foreach ($ldapGroups as $group) { - $groupIds = $group->getAttribute($this->identifierAttribute); - if ($groupIds) { - $roleNames[] = $this->rolePrefix . strtoupper($groupIds[0]); - } - } - return $roleNames; - } - - /** - * @param string $value - * @return string - */ - protected static function mb_ucfirst($value) - { - return - \mb_strtoupper(\mb_substr($value, 0, 1)) - . \mb_substr($value, 1) - ; - } -} diff --git a/Security/Provider/LDAPIdentitiesProvider.php b/Security/Provider/LDAPIdentitiesProvider.php deleted file mode 100644 index ab6fbfa..0000000 --- a/Security/Provider/LDAPIdentitiesProvider.php +++ /dev/null @@ -1,27 +0,0 @@ -groupProvider = $groupProvider; - } - - public function getAllGroups() - { - $groups = $this->getRepository(\FOM\UserBundle\Entity\Group::class)->findAll(); - return \array_merge($groups, $this->groupProvider->getGroups()); - } -} diff --git a/Security/Provider/LDAPUserProvider.php b/Security/Provider/LDAPUserProvider.php deleted file mode 100644 index 54623ec..0000000 --- a/Security/Provider/LDAPUserProvider.php +++ /dev/null @@ -1,83 +0,0 @@ - - */ -class LDAPUserProvider implements UserProviderInterface -{ - /** @var LdapClient */ - private $ldapClient; - /** @var LDAPGroupProvider */ - protected $groupProvider; - private $userDN; - private $defaultRoles; - private $userQuery; - - /** - * @param LdapClient $ldapClient - * @param LdapGroupProvider $groupProvider - * @param string $userDN - * @param string $userQuery - * @param string[] $defaultRoles - */ - public function __construct(LdapClient $ldapClient, - LDAPGroupProvider $groupProvider, - $userDN, - $userQuery, - Array $defaultRoles = ['ROLE_USER']) - { - $this->ldapClient = $ldapClient; - $this->groupProvider = $groupProvider; - $this->userDN = $userDN; - $this->userQuery = $userQuery; - $this->defaultRoles = $defaultRoles; - } - - /** - * {@inheritdoc} - */ - public function refreshUser(UserInterface $user) - { - if (!$user instanceof LdapUser) { - throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user))); - } - - return new LdapUser($user->getUsername(), $user->getRoles()); - } - - public function loadUserByUsername($username) - { - // NOTE: when wrapped in a chain provider, UserNameNotFoundException is caught and silently - // skips to the next provider, if any - /** @see \Symfony\Component\Security\Core\User\ChainUserProvider::loadUserByUsername() */ - if (!$this->ldapClient->getHost()) { - throw new UsernameNotFoundException('LDAP lookup disabled with empty host configuration', 0); - } - - $this->ldapClient->bind(); - $userQuery = str_replace('{username}', $this->ldapClient->escape($username, '', LDAP_ESCAPE_FILTER), $this->userQuery); - $matches = $this->ldapClient->query($this->userDN, $userQuery)->execute()->toArray(); - - if ($matches) { - $roles = \array_unique(\array_merge($this->defaultRoles, $this->groupProvider->getRolesByUserEntry($matches[0], $username))); - return new LdapUser($username, $roles); - } else { - throw new UsernameNotFoundException(sprintf('User "%s" could not be fetched from LDAP.', $username), 0); - } - } - - public function supportsClass($class) - { - return true; - } -} diff --git a/Security/Provider/MapbenderLdapBindAuthenticationProvider.php b/Security/Provider/MapbenderLdapBindAuthenticationProvider.php deleted file mode 100644 index 11a4518..0000000 --- a/Security/Provider/MapbenderLdapBindAuthenticationProvider.php +++ /dev/null @@ -1,60 +0,0 @@ -encoderFactory = $encoderFactory ; - - // support Mapbender < 3.2.x (Symfony 2.8) - if (method_exists(get_parent_class($this), 'setQueryString')) { - $this->setQueryString($userQuery); - } - } - - /** - * {@inheritdoc} - */ - protected function checkAuthentication(UserInterface $user, UsernamePasswordToken $token) - { - $password = $token->getCredentials(); - try { - parent::checkAuthentication($user, $token); - } catch (BadCredentialsException $e) { - try { - if (!$this->encoderFactory->getEncoder($user)->isPasswordValid($user->getPassword(), $password, $user->getSalt())) { - throw new BadCredentialsException('The presented password is invalid.'); - } - } catch (\Exception $e){ - throw new BadCredentialsException('The presented password is invalid.'); - } - } - } -} diff --git a/Security/User/MapbenderGroupInterface.php b/Security/User/MapbenderGroupInterface.php deleted file mode 100644 index 236ae3c..0000000 --- a/Security/User/MapbenderGroupInterface.php +++ /dev/null @@ -1,13 +0,0 @@ - Date: Fri, 24 May 2024 08:48:40 +0200 Subject: [PATCH 2/3] Fix version constraint --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eb71d7b..04d67c6 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ ldap.group.defaultRoles: [ROLE_USER] # this should be ROLE_USER in most cases Install Mapbender LDAP via Composer: ```sh -composer require mapbender/ldapbundle +composer require mapbender/ldapbundle:v1.1.4 ``` Register the bundle in AppKernel.php: From f484fea81c868eff9913ea76115bb62f83cb7945 Mon Sep 17 00:00:00 2001 From: PhilVanB Date: Wed, 29 May 2024 10:11:14 +0200 Subject: [PATCH 3/3] Fix class support --- Security/LdapUserProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Security/LdapUserProvider.php b/Security/LdapUserProvider.php index 6214f6e..cc4c76d 100644 --- a/Security/LdapUserProvider.php +++ b/Security/LdapUserProvider.php @@ -82,7 +82,7 @@ public function loadUserByIdentifier(string $username): UserInterface public function supportsClass($class) { - return true; + return $class === LdapUser::class; } protected function findLdapUserRoles(Entry $user)