From 3b68f6ca727f52f9dc84fa1a134c092b44c49103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Isma=C3=ABl=20Bouya?= Date: Sat, 16 Jun 2018 11:40:00 +0200 Subject: Add ldap --- .../DependencyInjection/WallabagUserExtension.php | 30 +++++- src/Wallabag/UserBundle/Entity/User.php | 49 +++++++++- src/Wallabag/UserBundle/LdapHydrator.php | 103 +++++++++++++++++++++ .../UserBundle/OAuthStorageLdapWrapper.php | 43 +++++++++ src/Wallabag/UserBundle/Resources/config/ldap.yml | 28 ++++++ .../UserBundle/Resources/config/ldap_services.yml | 22 +++++ 6 files changed, 273 insertions(+), 2 deletions(-) create mode 100644 src/Wallabag/UserBundle/LdapHydrator.php create mode 100644 src/Wallabag/UserBundle/OAuthStorageLdapWrapper.php create mode 100644 src/Wallabag/UserBundle/Resources/config/ldap.yml create mode 100644 src/Wallabag/UserBundle/Resources/config/ldap_services.yml (limited to 'src/Wallabag/UserBundle') diff --git a/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php b/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php index 5ca3482e..904a6af1 100644 --- a/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php +++ b/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php @@ -6,9 +6,34 @@ use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Loader; use Symfony\Component\HttpKernel\DependencyInjection\Extension; +use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; -class WallabagUserExtension extends Extension +class WallabagUserExtension extends Extension implements PrependExtensionInterface { + public function prepend(ContainerBuilder $container) + { + $ldap = $container->getParameter('ldap_enabled'); + + if ($ldap) { + $container->prependExtensionConfig('security', array( + 'providers' => array( + 'chain_provider' => array(), + ), + )); + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader->load('ldap.yml'); + } elseif ($container->hasExtension('fr3d_ldap')) { + $container->prependExtensionConfig('fr3_d_ldap', array( + 'driver' => array( + 'host' => 'localhost', + ), + 'user' => array( + 'baseDn' => 'dc=example,dc=com', + ), + )); + } + } + public function load(array $configs, ContainerBuilder $container) { $configuration = new Configuration(); @@ -16,6 +41,9 @@ class WallabagUserExtension extends Extension $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); $loader->load('services.yml'); + if ($container->getParameter('ldap_enabled')) { + $loader->load('ldap_services.yml'); + } $container->setParameter('wallabag_user.registration_enabled', $config['registration_enabled']); } diff --git a/src/Wallabag/UserBundle/Entity/User.php b/src/Wallabag/UserBundle/Entity/User.php index 48446e3c..f93c59c7 100644 --- a/src/Wallabag/UserBundle/Entity/User.php +++ b/src/Wallabag/UserBundle/Entity/User.php @@ -1,5 +1,15 @@ clients->first(); } } + + /** + * Set dn. + * + * @param string $dn + * + * @return User + */ + public function setDn($dn) + { + $this->dn = $dn; + + return $this; + } + + /** + * Get dn. + * + * @return string + */ + public function getDn() + { + return $this->dn; + } + + public function isLdapUser() + { + return $this->dn !== null; + } } diff --git a/src/Wallabag/UserBundle/LdapHydrator.php b/src/Wallabag/UserBundle/LdapHydrator.php new file mode 100644 index 00000000..cea2450f --- /dev/null +++ b/src/Wallabag/UserBundle/LdapHydrator.php @@ -0,0 +1,103 @@ +userManager = $user_manager; + $this->eventDispatcher = $event_dispatcher; + + $this->attributesMap = array( + 'setUsername' => $attributes_map[0], + 'setEmail' => $attributes_map[1], + 'setName' => $attributes_map[2], + ); + $this->enabledAttribute = $attributes_map[3]; + + $this->ldapBaseDn = $ldap_base_dn; + $this->ldapAdminFilter = $ldap_admin_filter; + $this->ldapDriver = $ldap_driver; + } + + public function hydrate(array $ldapEntry) + { + $user = $this->userManager->findUserBy(array('dn' => $ldapEntry['dn'])); + + if (!$user) { + $user = $this->userManager->createUser(); + $user->setDn($ldapEntry['dn']); + $user->setPassword(''); + $user->setSalt(''); + $this->updateUserFields($user, $ldapEntry); + + $event = new UserEvent($user); + $this->eventDispatcher->dispatch(FOSUserEvents::USER_CREATED, $event); + + $this->userManager->reloadUser($user); + } else { + $this->updateUserFields($user, $ldapEntry); + } + + return $user; + } + + private function updateUserFields($user, $ldapEntry) + { + foreach ($this->attributesMap as $key => $value) { + if (is_array($ldapEntry[$value])) { + $ldap_value = $ldapEntry[$value][0]; + } else { + $ldap_value = $ldapEntry[$value]; + } + + call_user_func([$user, $key], $ldap_value); + } + + if ($this->enabledAttribute !== null) { + $user->setEnabled($ldapEntry[$this->enabledAttribute]); + } else { + $user->setEnabled(true); + } + + if ($this->isAdmin($user)) { + $user->addRole('ROLE_SUPER_ADMIN'); + } else { + $user->removeRole('ROLE_SUPER_ADMIN'); + } + + $this->userManager->updateUser($user, true); + } + + private function isAdmin($user) + { + if ($this->ldapAdminFilter === null) { + return false; + } + + $escaped_username = ldap_escape($user->getUsername(), '', LDAP_ESCAPE_FILTER); + $filter = sprintf($this->ldapAdminFilter, $escaped_username); + $entries = $this->ldapDriver->search($this->ldapBaseDn, $filter); + + return $entries['count'] == 1; + } +} diff --git a/src/Wallabag/UserBundle/OAuthStorageLdapWrapper.php b/src/Wallabag/UserBundle/OAuthStorageLdapWrapper.php new file mode 100644 index 00000000..8a851f12 --- /dev/null +++ b/src/Wallabag/UserBundle/OAuthStorageLdapWrapper.php @@ -0,0 +1,43 @@ +ldapManager = $ldap_manager; + } + + public function checkUserCredentials(IOAuth2Client $client, $username, $password) + { + try { + $user = $this->userProvider->loadUserByUsername($username); + } catch (AuthenticationException $e) { + return false; + } + + if ($user->isLdapUser()) { + return $this->checkLdapUserCredentials($user, $password); + } else { + return parent::checkUserCredentials($client, $username, $password); + } + } + + private function checkLdapUserCredentials($user, $password) + { + if ($this->ldapManager->bind($user, $password)) { + return array( + 'data' => $user, + ); + } else { + return false; + } + } +} diff --git a/src/Wallabag/UserBundle/Resources/config/ldap.yml b/src/Wallabag/UserBundle/Resources/config/ldap.yml new file mode 100644 index 00000000..5ec16088 --- /dev/null +++ b/src/Wallabag/UserBundle/Resources/config/ldap.yml @@ -0,0 +1,28 @@ +fr3d_ldap: + service: + user_hydrator: ldap_user_hydrator + driver: + host: "%ldap_host%" + port: "%ldap_port%" + useSsl: "%ldap_ssl%" + useStartTls: "%ldap_tls%" + bindRequiresDn: "%ldap_bind_requires_dn%" + username: "%ldap_manager_dn%" + password: "%ldap_manager_pw%" + user: + baseDn: "%ldap_base%" + filter: "%ldap_filter%" + usernameAttribute: "%ldap_username_attribute%" +security: + providers: + chain_provider: + chain: + providers: [ fr3d_ldapbundle, fos_userbundle ] + fr3d_ldapbundle: + id: fr3d_ldap.security.user.provider + firewalls: + secured_area: + fr3d_ldap: ~ + form_login: + provider: chain_provider + diff --git a/src/Wallabag/UserBundle/Resources/config/ldap_services.yml b/src/Wallabag/UserBundle/Resources/config/ldap_services.yml new file mode 100644 index 00000000..b3e3fd8a --- /dev/null +++ b/src/Wallabag/UserBundle/Resources/config/ldap_services.yml @@ -0,0 +1,22 @@ +services: + fos_oauth_server.server: + class: OAuth2\OAuth2 + arguments: + - "@oauth_storage_ldap_wrapper" + - "%fos_oauth_server.server.options%" + oauth_storage_ldap_wrapper: + class: Wallabag\UserBundle\OAuthStorageLdapWrapper + parent: fos_oauth_server.storage + calls: + - [setLdapManager, ["@fr3d_ldap.ldap_manager"]] + + ldap_user_hydrator: + class: Wallabag\UserBundle\LdapHydrator + arguments: + - "@fos_user.user_manager" + - "@event_dispatcher" + - [ "%ldap_username_attribute%", "%ldap_email_attribute%", "%ldap_name_attribute%", "%ldap_enabled_attribute%" ] + - "%ldap_base%" + - "%ldap_admin_filter%" + - "@fr3d_ldap.ldap_driver" + -- cgit v1.2.3