From b35aabac692079bcc3618307d76ba2fd00a3de52 Mon Sep 17 00:00:00 2001 From: Alessandro Pozzi Date: Wed, 21 Mar 2018 09:09:42 +0100 Subject: [PATCH] More flexible exclude option --- src/DependencyInjection/AlepLdapExtension.php | 18 ++++- src/DependencyInjection/Configuration.php | 10 ++- src/EventListener/LoginListener.php | 74 +++++++++++++++++-- src/Resources/config/pimcore/config.yml | 2 +- 4 files changed, 96 insertions(+), 8 deletions(-) diff --git a/src/DependencyInjection/AlepLdapExtension.php b/src/DependencyInjection/AlepLdapExtension.php index 573751a..e926597 100644 --- a/src/DependencyInjection/AlepLdapExtension.php +++ b/src/DependencyInjection/AlepLdapExtension.php @@ -41,6 +41,22 @@ public function load(array $configs, ContainerBuilder $container) if(!$config['enabled']) { $container->removeDefinition('Alep\LdapBundle\EventListener\LoginListener'); } else { + + //Support for deprecated exclude configuration + if(isset($config['exclude']) && is_array($config['exclude']) && !empty($config['exclude'])) { + if(isset($config['exclude_rules']) && is_array($config['exclude_rules'])) { + if(isset($config['exclude_rules']['users']) && is_array($config['exclude_rules']['users'])) { + $config['exclude_rules']['users'] = array_merge($config['exclude_rules']['users'], $config['exclude']); + } else { + $config['exclude_rules']['users'] = $config['exclude']; + } + } else { + $config['exclude_rules'] = array( + 'users' => $config['exclude'] + ); + } + } + $loginListenerDefinition = $container->getDefinition('Alep\LdapBundle\EventListener\LoginListener'); $loginListenerDefinition->setArguments(array( new Reference($config['service']), @@ -50,7 +66,7 @@ public function load(array $configs, ContainerBuilder $container) $config['default_roles'], $config['uid_key'], $config['filter'], - $config['exclude'], + $config['exclude_rules'], new Reference($config['mapper']) )); } diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index ead7cf9..dae5c41 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -71,10 +71,18 @@ public function getConfigTreeBuilder() ->cannotBeEmpty() ->defaultValue('({uid_key}={username})') ->end() - ->arrayNode('exclude') + ->arrayNode('exclude') ->info('This is a list of usernames to exclude from LDAP authentication.') + ->setDeprecated('The "%node%" option is deprecated. Use "exclude_rules" instead.') ->scalarPrototype()->end() ->end() + ->arrayNode('exclude_rules') + ->info('This is a list of usernames/roles to exclude from LDAP authentication (supports regular expressions).') + ->children() + ->arrayNode('users')->scalarPrototype()->end()->end() + ->arrayNode('roles')->scalarPrototype()->end()->end() + ->end() + ->end() ->scalarNode('mapper') ->info('This is the data mapper service used to map ldap user data to Pimcore user.') ->cannotBeEmpty() diff --git a/src/EventListener/LoginListener.php b/src/EventListener/LoginListener.php index 8c3fc08..d6414e3 100644 --- a/src/EventListener/LoginListener.php +++ b/src/EventListener/LoginListener.php @@ -79,10 +79,10 @@ class LoginListener * @param string[] $default_roles * @param string $uid_key * @param string $filter - * @param string[] $exclude + * @param array $exclude_rules * @param LdapUserMapperInterface $mapper */ - public function __construct(Ldap $ldap, $base_dn, $search_dn, $search_password, $default_roles, $uid_key, $filter, $exclude, LdapUserMapperInterface $mapper) + public function __construct(Ldap $ldap, $base_dn, $search_dn, $search_password, $default_roles, $uid_key, $filter, $exclude_rules, LdapUserMapperInterface $mapper) { $this->ldap = $ldap; $this->base_dn = $base_dn; @@ -91,7 +91,7 @@ public function __construct(Ldap $ldap, $base_dn, $search_dn, $search_password, $this->default_roles = (is_array($default_roles)) ? $default_roles : array(); $this->uid_key = $uid_key; $this->filter = str_replace('{uid_key}', $uid_key, $filter); - $this->exclude = (is_array($exclude)) ? $exclude : array(); + $this->exclude_rules = (is_array($exclude_rules)) ? $exclude_rules : array(); $this->mapper = $mapper; $this->ldap->bind($search_dn, $search_password); @@ -108,7 +108,7 @@ public function onAdminLoginCredentials(LoginCredentialsEvent $event) $password = $credentials['password']; //Check if this user has to be excluded - if(in_array($username, $this->exclude)) return; + if($this->isExcluded($username)) return; //Authenticate via ldap $ldap_user = $this->authenticate($username, $password); @@ -127,7 +127,7 @@ public function onAdminLoginFailed(LoginFailedEvent $event) $password = $event->getCredential('password'); //Check if this user has to be excluded - if(in_array($username, $this->exclude)) return; + if($this->isExcluded($username)) return; //authenticate via ldap $ldap_user = $this->authenticate($username, $password); @@ -139,6 +139,67 @@ public function onAdminLoginFailed(LoginFailedEvent $event) $event->setUser($pimcore_user); } + /** + * @param string $username + * @return bool + */ + private function isExcluded($username) { + + //Check users excluding rules + if(isset($this->exclude_rules['users'])) { + foreach ($this->exclude_rules['users'] as $userExcludeRule) { + if (@preg_match($userExcludeRule, null) !== false) { //Check as regex (@ sign in front of the regex function is to prevent warnings on the valid regex test) + if (preg_match($userExcludeRule, $username)) { + return true; + } + } elseif ($username == $userExcludeRule) { //Check as string + return true; + } + } + } + + //Check roles excluding rules + if(isset($this->exclude_rules['roles'])) { + $roles = $this->getUserRoleNames($username); + if(!empty($roles)) { + foreach ($this->exclude_rules['roles'] as $roleExcludeRule) { + if (@preg_match($roleExcludeRule, null) !== false) { //Check as regex (@ sign in front of the regex function is to prevent warnings on the valid regex test) + if (preg_grep($roleExcludeRule, $roles)) { + return true; + } + } elseif (in_array($roleExcludeRule, $roles)) { //Check as string + return true; + } + } + } + } + + return false; + } + + /** + * @param string $username + * @return string[] + */ + private function getUserRoleNames($username) { + $roles = array(); + + //Get user + $user = User::getByName($username); + if($user instanceof User) { + //If the user is an admin add the role ROLE_PIMCORE_ADMIN automatically + if($user->isAdmin()) $roles[] = 'ROLE_PIMCORE_ADMIN'; + + //Get user's roles + foreach($user->getRoles() as $roleId) { + $role = User\Role::getById($roleId); + $roles[] = $role->getName(); + } + } + + return $roles; + } + /** * @param string $username * @param string $password @@ -231,6 +292,9 @@ private function updatePimcoreUser($username, $password, $ldap_user) } } + /** + * @return interger[] + */ private function getDefaultRolesIds() { $default_roles_ids = array(); diff --git a/src/Resources/config/pimcore/config.yml b/src/Resources/config/pimcore/config.yml index 2bc2f7f..cd2c0f1 100644 --- a/src/Resources/config/pimcore/config.yml +++ b/src/Resources/config/pimcore/config.yml @@ -7,5 +7,5 @@ alep_ldap: default_roles: ~ uid_key: 'sAMAccountName' filter: '({uid_key}={username})' - exclude: ~ + exclude_rules: ~ mapper: 'Alep\LdapBundle\DataMapper\DefaultLdapUserMapper' \ No newline at end of file