From 0284cdbdae189414b6f352233bbaf332524b2ddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Thu, 6 Jan 2022 16:33:18 +0100 Subject: [PATCH 1/5] Add FirstLoginListener to accept shares upon first ldap user login MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- apps/user_ldap/lib/AppInfo/Application.php | 17 ++- apps/user_ldap/lib/FirstLoginListener.php | 140 +++++++++++++++++++++ 2 files changed, 155 insertions(+), 2 deletions(-) create mode 100644 apps/user_ldap/lib/FirstLoginListener.php diff --git a/apps/user_ldap/lib/AppInfo/Application.php b/apps/user_ldap/lib/AppInfo/Application.php index 79998a580e540..64ff3385fe3bc 100644 --- a/apps/user_ldap/lib/AppInfo/Application.php +++ b/apps/user_ldap/lib/AppInfo/Application.php @@ -31,15 +31,16 @@ use OCA\User_LDAP\Controller\RenewPasswordController; use OCA\User_LDAP\Events\GroupBackendRegistered; use OCA\User_LDAP\Events\UserBackendRegistered; -use OCA\User_LDAP\Group_Proxy; +use OCA\User_LDAP\FirstLoginListener; use OCA\User_LDAP\GroupPluginManager; +use OCA\User_LDAP\Group_Proxy; use OCA\User_LDAP\Handler\ExtStorageConfigHandler; use OCA\User_LDAP\Helper; use OCA\User_LDAP\ILDAPWrapper; use OCA\User_LDAP\LDAP; use OCA\User_LDAP\Notification\Notifier; -use OCA\User_LDAP\User_Proxy; use OCA\User_LDAP\UserPluginManager; +use OCA\User_LDAP\User_Proxy; use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IBootContext; use OCP\AppFramework\Bootstrap\IBootstrap; @@ -50,6 +51,7 @@ use OCP\IL10N; use OCP\IServerContainer; use OCP\Notification\IManager as INotificationManager; +use OCP\User\Events\PostLoginEvent; use Symfony\Component\EventDispatcher\EventDispatcherInterface; class Application extends App implements IBootstrap { @@ -117,6 +119,7 @@ public function boot(IBootContext $context): void { }); $context->injectFn(Closure::fromCallable([$this, 'registerBackendDependents'])); + $context->injectFn(Closure::fromCallable([$this, 'registerFirstLoginListener'])); \OCP\Util::connectHook( '\OCA\Files_Sharing\API\Server2Server', @@ -137,4 +140,14 @@ function () use ($appContainer) { } ); } + + private function registerFirstLoginListener(IEventDispatcher $dispatcher) { + $dispatcher->addServiceListener(PostLoginEvent::class, FirstLoginListener::class); + \OCP\Util::connectHook( + '\OC\User', + 'assignedUserId', + FirstLoginListener::class, + 'onAssignedId' + ); + } } diff --git a/apps/user_ldap/lib/FirstLoginListener.php b/apps/user_ldap/lib/FirstLoginListener.php new file mode 100644 index 0000000000000..2bfe4a46c16db --- /dev/null +++ b/apps/user_ldap/lib/FirstLoginListener.php @@ -0,0 +1,140 @@ + + * + * @author Côme Chilliet + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OCA\User_LDAP; + +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\EventDispatcher\IEventListener; +use OCP\Group\Events\UserAddedEvent; +use OCP\IDBConnection; +use OCP\IGroupManager; +use OCP\IUser; +use OCP\IUserManager; +use OCP\User\Events\PostLoginEvent; +use Psr\Log\LoggerInterface; + +class FirstLoginListener implements IEventListener { + protected $somekindofstatefulhandler; + + /** @var Group_Proxy */ + private $groupBackend; + /** @var IEventDispatcher */ + private $dispatcher; + /** @var IGroupManager */ + private $groupManager; + /** @var IUserManager */ + private $userManager; + /** @var LoggerInterface */ + private $logger; + /** @var IDBConnection */ + private $dbc; + + public function __construct( + Group_Proxy $groupBackend, + IEventDispatcher $dispatcher, + IGroupManager $groupManager, + IUserManager $userManager, + LoggerInterface $logger, + IDBConnection $dbc + ) { + $this->groupBackend = $groupBackend; + $this->dispatcher = $dispatcher; + $this->groupManager = $groupManager; + $this->userManager = $userManager; + $this->logger = $logger; + $this->dbc = $dbc; + } + + public function handle(Event $event): void { + if ($event instanceof PostLoginEvent) { + $this->onPostLogin($event->getUser()->getUID()); + } + } + + public function onAssignedId(string $username): void { + $this->somekindofstatefulhandler[$username]['id'] = 1; + $this->triggerUpdateGroups($username); + } + + public function onPostLogin(string $username): void { + $this->somekindofstatefulhandler[$username]['login'] = 1; + $this->triggerUpdateGroups($username); + } + + private function triggerUpdateGroups(string $username): void { + if (array_sum($this->somekindofstatefulhandler[$username] ?? []) >= 2) { + $this->updateGroups($username); + } + } + + private function updateGroups(string $username): void { + $groups = $this->groupBackend->getUserGroups($username); + + $qb = $this->dbc->getQueryBuilder(); + $qb->select(['owncloudusers']) + ->from('ldap_group_members') + ->where($qb->expr()->eq('owncloudname', $qb->createParameter('groupId'))); + + $qbUpdate = $this->dbc->getQueryBuilder(); + $qbUpdate->update('ldap_group_members') + ->set('owncloudusers', $qb->createParameter('members')) + ->where($qb->expr()->eq('owncloudname', $qb->createParameter('groupId'))); + + foreach ($groups as $group) { + $qb->setParameters([ + 'groupId' => $group + ]); + + $qResult = $qb->execute(); + $data = $qResult->fetchOne(); + $qResult->closeCursor(); + + $knownUsers = unserialize($data['owncloudusers']); + $hasChanged = false; + + $groupObject = $this->groupManager->get($group); + if (!in_array($username, $knownUsers)) { + $userObject = $this->userManager->get($username); + if ($userObject instanceof IUser) { + $this->dispatcher->dispatchTyped(new UserAddedEvent($groupObject, $userObject)); + $this->logger->info( + __CLASS__ . ' – {user} added to {group}', + [ + 'app' => 'user_ldap', + 'user' => $username, + 'group' => $group + ] + ); + $qbUpdate->setParameters([ + 'members' => serialize(array_merge($knownUsers, [$username])), + 'groupId' => $group + ]); + $qbUpdate->execute(); + } + } + } + } +} From ddb4bb7f1424e3292b8da346fef7d6d12ecf9642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Thu, 10 Feb 2022 13:11:50 +0100 Subject: [PATCH 2/5] Use a standard array for the stateful cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- apps/user_ldap/lib/FirstLoginListener.php | 24 +++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/apps/user_ldap/lib/FirstLoginListener.php b/apps/user_ldap/lib/FirstLoginListener.php index 2bfe4a46c16db..997573121ca81 100644 --- a/apps/user_ldap/lib/FirstLoginListener.php +++ b/apps/user_ldap/lib/FirstLoginListener.php @@ -37,7 +37,8 @@ use Psr\Log\LoggerInterface; class FirstLoginListener implements IEventListener { - protected $somekindofstatefulhandler; + /** @var array> */ + private $eventHappened = []; /** @var Group_Proxy */ private $groupBackend; @@ -75,17 +76,17 @@ public function handle(Event $event): void { } public function onAssignedId(string $username): void { - $this->somekindofstatefulhandler[$username]['id'] = 1; + $this->eventHappened[$username]['id'] = 1; $this->triggerUpdateGroups($username); } public function onPostLogin(string $username): void { - $this->somekindofstatefulhandler[$username]['login'] = 1; + $this->eventHappened[$username]['login'] = 1; $this->triggerUpdateGroups($username); } private function triggerUpdateGroups(string $username): void { - if (array_sum($this->somekindofstatefulhandler[$username] ?? []) >= 2) { + if (array_sum($this->eventHappened[$username] ?? []) >= 2) { $this->updateGroups($username); } } @@ -108,7 +109,7 @@ private function updateGroups(string $username): void { 'groupId' => $group ]); - $qResult = $qb->execute(); + $qResult = $qb->executeQuery(); $data = $qResult->fetchOne(); $qResult->closeCursor(); @@ -116,6 +117,17 @@ private function updateGroups(string $username): void { $hasChanged = false; $groupObject = $this->groupManager->get($group); + if ($groupObject === null) { + $this->logger->error( + __CLASS__ . ' – group {group} could not be found (user {user})', + [ + 'app' => 'user_ldap', + 'user' => $username, + 'group' => $group + ] + ); + continue; + } if (!in_array($username, $knownUsers)) { $userObject = $this->userManager->get($username); if ($userObject instanceof IUser) { @@ -132,7 +144,7 @@ private function updateGroups(string $username): void { 'members' => serialize(array_merge($knownUsers, [$username])), 'groupId' => $group ]); - $qbUpdate->execute(); + $qbUpdate->executeStatement(); } } } From ea2afb2f9458fd17e8b474c4d7a283fdd8e5880d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Thu, 10 Feb 2022 14:43:48 +0100 Subject: [PATCH 3/5] Move event listener registration to register() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- apps/user_ldap/lib/AppInfo/Application.php | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/apps/user_ldap/lib/AppInfo/Application.php b/apps/user_ldap/lib/AppInfo/Application.php index 64ff3385fe3bc..eb1f3f037afd5 100644 --- a/apps/user_ldap/lib/AppInfo/Application.php +++ b/apps/user_ldap/lib/AppInfo/Application.php @@ -89,6 +89,7 @@ public function __construct() { public function register(IRegistrationContext $context): void { $context->registerNotifierService(Notifier::class); + $context->registerEventListener(PostLoginEvent::class, FirstLoginListener::class); } public function boot(IBootContext $context): void { @@ -119,7 +120,6 @@ public function boot(IBootContext $context): void { }); $context->injectFn(Closure::fromCallable([$this, 'registerBackendDependents'])); - $context->injectFn(Closure::fromCallable([$this, 'registerFirstLoginListener'])); \OCP\Util::connectHook( '\OCA\Files_Sharing\API\Server2Server', @@ -127,9 +127,15 @@ public function boot(IBootContext $context): void { '\OCA\User_LDAP\Helper', 'loginName2UserName' ); + \OCP\Util::connectHook( + '\OC\User', + 'assignedUserId', + FirstLoginListener::class, + 'onAssignedId' + ); } - private function registerBackendDependents(IAppContainer $appContainer, EventDispatcherInterface $dispatcher) { + private function registerBackendDependents(IAppContainer $appContainer, EventDispatcherInterface $dispatcher): void { $dispatcher->addListener( 'OCA\\Files_External::loadAdditionalBackends', function () use ($appContainer) { @@ -140,14 +146,4 @@ function () use ($appContainer) { } ); } - - private function registerFirstLoginListener(IEventDispatcher $dispatcher) { - $dispatcher->addServiceListener(PostLoginEvent::class, FirstLoginListener::class); - \OCP\Util::connectHook( - '\OC\User', - 'assignedUserId', - FirstLoginListener::class, - 'onAssignedId' - ); - } } From 1a6f82963d5abb8478f7a3450a71dfba159acf13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Mon, 14 Feb 2022 12:35:01 +0100 Subject: [PATCH 4/5] Add logging to be able to debug FirstLoginListener MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- apps/user_ldap/lib/FirstLoginListener.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/apps/user_ldap/lib/FirstLoginListener.php b/apps/user_ldap/lib/FirstLoginListener.php index 997573121ca81..357cc42fc6df0 100644 --- a/apps/user_ldap/lib/FirstLoginListener.php +++ b/apps/user_ldap/lib/FirstLoginListener.php @@ -76,11 +76,25 @@ public function handle(Event $event): void { } public function onAssignedId(string $username): void { + $this->logger->info( + __CLASS__ . ' – {user} assignedId', + [ + 'app' => 'user_ldap', + 'user' => $username, + ] + ); $this->eventHappened[$username]['id'] = 1; $this->triggerUpdateGroups($username); } public function onPostLogin(string $username): void { + $this->logger->info( + __CLASS__ . ' – {user} postLogin', + [ + 'app' => 'user_ldap', + 'user' => $username, + ] + ); $this->eventHappened[$username]['login'] = 1; $this->triggerUpdateGroups($username); } @@ -92,6 +106,13 @@ private function triggerUpdateGroups(string $username): void { } private function updateGroups(string $username): void { + $this->logger->info( + __CLASS__ . ' – {user} updateGroups', + [ + 'app' => 'user_ldap', + 'user' => $username, + ] + ); $groups = $this->groupBackend->getUserGroups($username); $qb = $this->dbc->getQueryBuilder(); From 1035e07efda55c1776258cf25c583b74be8119bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Mon, 14 Feb 2022 12:35:28 +0100 Subject: [PATCH 5/5] Update autoload for user_ldap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- apps/user_ldap/composer/composer/autoload_classmap.php | 1 + apps/user_ldap/composer/composer/autoload_static.php | 1 + apps/user_ldap/composer/composer/installed.php | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/user_ldap/composer/composer/autoload_classmap.php b/apps/user_ldap/composer/composer/autoload_classmap.php index cffb2aaa9feef..18c1d294d4e52 100644 --- a/apps/user_ldap/composer/composer/autoload_classmap.php +++ b/apps/user_ldap/composer/composer/autoload_classmap.php @@ -33,6 +33,7 @@ 'OCA\\User_LDAP\\Exceptions\\NoMoreResults' => $baseDir . '/../lib/Exceptions/NoMoreResults.php', 'OCA\\User_LDAP\\Exceptions\\NotOnLDAP' => $baseDir . '/../lib/Exceptions/NotOnLDAP.php', 'OCA\\User_LDAP\\FilesystemHelper' => $baseDir . '/../lib/FilesystemHelper.php', + 'OCA\\User_LDAP\\FirstLoginListener' => $baseDir . '/../lib/FirstLoginListener.php', 'OCA\\User_LDAP\\GroupPluginManager' => $baseDir . '/../lib/GroupPluginManager.php', 'OCA\\User_LDAP\\Group_LDAP' => $baseDir . '/../lib/Group_LDAP.php', 'OCA\\User_LDAP\\Group_Proxy' => $baseDir . '/../lib/Group_Proxy.php', diff --git a/apps/user_ldap/composer/composer/autoload_static.php b/apps/user_ldap/composer/composer/autoload_static.php index 5928ff78ef03b..70d7e447e2560 100644 --- a/apps/user_ldap/composer/composer/autoload_static.php +++ b/apps/user_ldap/composer/composer/autoload_static.php @@ -48,6 +48,7 @@ class ComposerStaticInitUser_LDAP 'OCA\\User_LDAP\\Exceptions\\NoMoreResults' => __DIR__ . '/..' . '/../lib/Exceptions/NoMoreResults.php', 'OCA\\User_LDAP\\Exceptions\\NotOnLDAP' => __DIR__ . '/..' . '/../lib/Exceptions/NotOnLDAP.php', 'OCA\\User_LDAP\\FilesystemHelper' => __DIR__ . '/..' . '/../lib/FilesystemHelper.php', + 'OCA\\User_LDAP\\FirstLoginListener' => __DIR__ . '/..' . '/../lib/FirstLoginListener.php', 'OCA\\User_LDAP\\GroupPluginManager' => __DIR__ . '/..' . '/../lib/GroupPluginManager.php', 'OCA\\User_LDAP\\Group_LDAP' => __DIR__ . '/..' . '/../lib/Group_LDAP.php', 'OCA\\User_LDAP\\Group_Proxy' => __DIR__ . '/..' . '/../lib/Group_Proxy.php', diff --git a/apps/user_ldap/composer/composer/installed.php b/apps/user_ldap/composer/composer/installed.php index 5e9420644858b..700becd526567 100644 --- a/apps/user_ldap/composer/composer/installed.php +++ b/apps/user_ldap/composer/composer/installed.php @@ -5,7 +5,7 @@ 'type' => 'library', 'install_path' => __DIR__ . '/../', 'aliases' => array(), - 'reference' => '9915dc6785d1660068a51604f9379e8b1dc1418c', + 'reference' => 'ea2afb2f9458fd17e8b474c4d7a283fdd8e5880d', 'name' => '__root__', 'dev' => false, ), @@ -16,7 +16,7 @@ 'type' => 'library', 'install_path' => __DIR__ . '/../', 'aliases' => array(), - 'reference' => '9915dc6785d1660068a51604f9379e8b1dc1418c', + 'reference' => 'ea2afb2f9458fd17e8b474c4d7a283fdd8e5880d', 'dev_requirement' => false, ), ),