From ca32e13288747ff58d113b9975d84fa29704dfbf Mon Sep 17 00:00:00 2001 From: Angel Fernando Quiroz Campos <1697880+AngelFQC@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:25:38 -0500 Subject: [PATCH] Plugin: Azure: Refactor to get paginated results when syncing users - refs BT#21930 --- .../src/AzureActiveDirectory.php | 2 + .../src/AzureCommand.php | 23 ++++ .../src/AzureSyncUsersCommand.php | 116 ++++++++++++++++++ .../src/scripts/sync_users.php | 85 +------------ 4 files changed, 147 insertions(+), 79 deletions(-) create mode 100644 plugin/azure_active_directory/src/AzureCommand.php create mode 100644 plugin/azure_active_directory/src/AzureSyncUsersCommand.php diff --git a/plugin/azure_active_directory/src/AzureActiveDirectory.php b/plugin/azure_active_directory/src/AzureActiveDirectory.php index 454150986e..4bc55054a4 100644 --- a/plugin/azure_active_directory/src/AzureActiveDirectory.php +++ b/plugin/azure_active_directory/src/AzureActiveDirectory.php @@ -36,6 +36,8 @@ class AzureActiveDirectory extends Plugin public const EXTRA_FIELD_AZURE_ID = 'azure_id'; public const EXTRA_FIELD_AZURE_UID = 'azure_uid'; + public const API_PAGE_SIZE = 100; + /** * AzureActiveDirectory constructor. */ diff --git a/plugin/azure_active_directory/src/AzureCommand.php b/plugin/azure_active_directory/src/AzureCommand.php new file mode 100644 index 0000000000..60e6f44f97 --- /dev/null +++ b/plugin/azure_active_directory/src/AzureCommand.php @@ -0,0 +1,23 @@ +plugin = AzureActiveDirectory::create(); + $this->provider = $this->plugin->getProviderForApiGraph(); + } +} diff --git a/plugin/azure_active_directory/src/AzureSyncUsersCommand.php b/plugin/azure_active_directory/src/AzureSyncUsersCommand.php new file mode 100644 index 0000000000..826c22eb3b --- /dev/null +++ b/plugin/azure_active_directory/src/AzureSyncUsersCommand.php @@ -0,0 +1,116 @@ + + * @throws Exception + */ + public function __invoke(): Generator + { + yield 'Synchronizing users from Azure.'; + + $token = $this->provider->getAccessToken( + 'client_credentials', + ['resource' => $this->provider->resource] + ); + + $existingUsers = []; + + foreach ($this->getAzureUsers($token) as $azureUserInfo) { + try { + $userId = $this->plugin->registerUser( + $token, + $this->provider, + $azureUserInfo, + 'users/' . $azureUserInfo['id'] . '/memberOf', + 'id', + 'id' + ); + } catch (Exception $e) { + yield $e->getMessage(); + + continue; + } + + $existingUsers[] = $userId; + + $userInfo = api_get_user_info($userId); + + yield sprintf('User info: %s', serialize($userInfo)); + } + + if ('true' === $this->plugin->get(AzureActiveDirectory::SETTING_DEACTIVATE_NONEXISTING_USERS)) { + yield '----------------'; + + yield 'Trying deactivate non-existing users in Azure'; + + $users = UserManager::getRepository()->findByAuthSource('azure'); + $userIdList = array_map( + function ($user) { + return $user->getId(); + }, + $users + ); + + $nonExistingUsers = array_diff($userIdList, $existingUsers); + + UserManager::deactivate_users($nonExistingUsers); + + yield sprintf( + 'Deactivated users IDs: %s', + implode(', ', $nonExistingUsers) + ); + } + } + + /** + * @return Generator> + * @throws Exception + */ + private function getAzureUsers(AccessTokenInterface $token): Generator + { + $userFields = [ + 'givenName', + 'surname', + 'mail', + 'userPrincipalName', + 'businessPhones', + 'mobilePhone', + 'accountEnabled', + 'mailNickname', + 'id' + ]; + + $query = sprintf( + '$top=%d&$select=%s', + AzureActiveDirectory::API_PAGE_SIZE, + implode(',', $userFields) + ); + + do { + try { + $azureUsersRequest = $this->provider->request('get', "users?$query", $token); + } catch (Exception $e) { + throw new Exception('Exception when requesting users from Azure: '.$e->getMessage()); + } + + $azureUsersInfo = $azureUsersRequest['value'] ?? []; + + foreach ($azureUsersInfo as $azureUserInfo) { + yield $azureUserInfo; + } + + $hasNextLink = false; + + if (!empty($azureUsersRequest['@odata.nextLink'])) { + $hasNextLink = true; + $query = parse_url($azureUsersRequest['@odata.nextLink'], PHP_URL_QUERY); + } + } while ($hasNextLink); + } +} diff --git a/plugin/azure_active_directory/src/scripts/sync_users.php b/plugin/azure_active_directory/src/scripts/sync_users.php index 82d9de6c93..350848b004 100644 --- a/plugin/azure_active_directory/src/scripts/sync_users.php +++ b/plugin/azure_active_directory/src/scripts/sync_users.php @@ -1,91 +1,18 @@ getProviderForApiGraph(); - -echo 'Synchronizing users from Azure.'.PHP_EOL; +$command = new AzureSyncUsersCommand(); try { - $token = $provider->getAccessToken( - 'client_credentials', - ['resource' => $provider->resource] - ); - - $userFields = [ - 'givenName', - 'surname', - 'mail', - 'userPrincipalName', - 'businessPhones', - 'mobilePhone', - 'accountEnabled', - 'mailNickname', - 'id' - ]; - - $azureUsersInfo = $provider->get( - 'users?$select='.implode(',', $userFields), - $token - ); -} catch (Exception $e) { - printf("%s - %s".PHP_EOL, time(), $e->getMessage()); - die; -} - -printf("%s - Number of users obtained %d".PHP_EOL, time(), count($azureUsersInfo)); - -$existingUsers = []; - -/** @var array $user */ -foreach ($azureUsersInfo as $azureUserInfo) { - try { - $userId = $plugin->registerUser( - $token, - $provider, - $azureUserInfo, - 'users/' . $azureUserInfo['id'] . '/memberOf', - 'id', - 'id' - ); - - $existingUsers[] = $userId; - - $userInfo = api_get_user_info($userId); - - printf("%s - UserInfo %s".PHP_EOL, time(), serialize($userInfo)); - } catch (Exception $e) { - printf("%s - %s".PHP_EOL, time(), $e->getMessage()); - - continue; + foreach ($command() as $str) { + printf("%d - %s".PHP_EOL, time(), $str); } -} - -if ('true' === $plugin->get(AzureActiveDirectory::SETTING_DEACTIVATE_NONEXISTING_USERS)) { - echo '----------------'.PHP_EOL; - printf('Trying deactivate non-existing users in Azure.'.PHP_EOL, time()); - - $users = UserManager::getRepository()->findByAuthSource('azure'); - $userIdList = array_map( - function ($user) { - return $user->getId(); - }, - $users - ); - - $nonExistingUsers = array_diff($userIdList, $existingUsers); - - UserManager::deactivate_users($nonExistingUsers); - printf( - "%d - Deactivated users IDs: %s".PHP_EOL, - time(), - implode(', ', $nonExistingUsers) - ); +} catch (Exception $e) { + printf('%s - Exception: %s'.PHP_EOL, time(), $e->getMessage()); }