From ba43a9c6ce500cfea0f18404891d7eccab8758a6 Mon Sep 17 00:00:00 2001 From: Armin Berger Date: Tue, 29 Oct 2024 22:47:02 +0100 Subject: [PATCH 1/8] feat: whitelist filter for group provisioning Signed-off-by: Armin Berger --- lib/Service/ProviderService.php | 6 +++++- lib/Service/ProvisioningService.php | 10 ++++++++++ src/components/SettingsForm.vue | 15 +++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/lib/Service/ProviderService.php b/lib/Service/ProviderService.php index c460ed88..7cc0da20 100644 --- a/lib/Service/ProviderService.php +++ b/lib/Service/ProviderService.php @@ -47,6 +47,8 @@ class ProviderService { public const SETTING_JWKS_CACHE_TIMESTAMP = 'jwksCacheTimestamp'; public const SETTING_PROVIDER_BASED_ID = 'providerBasedId'; public const SETTING_GROUP_PROVISIONING = 'groupProvisioning'; + public const SETTING_GROUP_WHITELIST_REGEX = 'groupWhitelistRegex'; + public const SETTING_RESTRICT_LOGIN_TO_GROUPS = 'restrictLoginToGroups'; public const BOOLEAN_SETTINGS_DEFAULT_VALUES = [ self::SETTING_GROUP_PROVISIONING => false, @@ -159,7 +161,9 @@ private function getSupportedSettings(): array { self::SETTING_BEARER_PROVISIONING, self::SETTING_EXTRA_CLAIMS, self::SETTING_PROVIDER_BASED_ID, - self::SETTING_GROUP_PROVISIONING + self::SETTING_GROUP_PROVISIONING, + self::SETTING_GROUP_WHITELIST_REGEX, + self::SETTING_RESTRICT_LOGIN_TO_GROUPS, ]; } diff --git a/lib/Service/ProvisioningService.php b/lib/Service/ProvisioningService.php index 02122a1d..d9f6ac9f 100644 --- a/lib/Service/ProvisioningService.php +++ b/lib/Service/ProvisioningService.php @@ -389,6 +389,8 @@ public function provisionUserGroups(IUser $user, int $providerId, object $idToke $groupsAttribute = $this->providerService->getSetting($providerId, ProviderService::SETTING_MAPPING_GROUPS, 'groups'); $groupsData = $idTokenPayload->{$groupsAttribute} ?? null; + $groupsWhitelistRegex = $this->providerService->getSetting($providerId, ProviderService::SETTING_GROUP_WHITELIST_REGEX, 'whitelist'); + $event = new AttributeMappedEvent(ProviderService::SETTING_MAPPING_GROUPS, $idTokenPayload, json_encode($groupsData)); $this->eventDispatcher->dispatchTyped($event); $this->logger->debug('Group mapping event dispatched'); @@ -413,6 +415,11 @@ public function provisionUserGroups(IUser $user, int $providerId, object $idToke continue; } + if ($groupsWhitelistRegex && !preg_match($groupsWhitelistRegex, $group->gid)) { + $this->logger->debug('Skipped group `' . $group->gid . '` for importing as not part of whitelist'); + continue; + } + $group->gid = $this->idService->getId($providerId, $group->gid); $syncGroups[] = $group; @@ -420,6 +427,9 @@ public function provisionUserGroups(IUser $user, int $providerId, object $idToke foreach ($userGroups as $group) { if (!in_array($group->getGID(), array_column($syncGroups, 'gid'))) { + if ($groupsWhitelistRegex && !preg_match($groupsWhitelistRegex, $group->getGID())) { + continue; + } $group->removeUser($user); } } diff --git a/src/components/SettingsForm.vue b/src/components/SettingsForm.vue index 81eee52b..3d9a78c3 100644 --- a/src/components/SettingsForm.vue +++ b/src/components/SettingsForm.vue @@ -240,6 +240,21 @@

{{ t('user_oidc', 'This will create and update the users groups depending on the groups claim in the id token. The Format of the groups claim value should be [{gid: "1", displayName: "group1"}, ...] or ["group1", "group2", ...]') }}

+

+ + +

+

+ {{ t('user_oidc', 'Only groups matching the whitelist regex will be created, updated and deleted by the group claim') }} +

+ + {{ t('user_oidc', 'Restrict login for users without whitelisted groups.') }} + +

+ {{ t('user_oidc', 'Users that are not part of a whitelisted group are not created and can not login') }} +

{{ t('user_oidc', 'Check Bearer token on API and WebDav requests') }} From 2a589455689e5ed13490599002ae6f4db99d3d20 Mon Sep 17 00:00:00 2001 From: Armin Berger Date: Tue, 29 Oct 2024 22:47:36 +0100 Subject: [PATCH 2/8] feat: restrict users from login if not in whitelisted group Signed-off-by: Armin Berger --- lib/Controller/LoginController.php | 12 ++++++++++++ lib/Service/ProvisioningService.php | 19 ++++++++++++++++--- tests/psalm-baseline.xml | 3 --- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/lib/Controller/LoginController.php b/lib/Controller/LoginController.php index 970ef16e..35c799f5 100644 --- a/lib/Controller/LoginController.php +++ b/lib/Controller/LoginController.php @@ -454,6 +454,18 @@ public function code(string $state = '', string $code = '', string $scope = '', return $this->build403TemplateResponse($message, Http::STATUS_BAD_REQUEST, ['reason' => 'failed to provision user']); } + // prevent login of users that are not in a whitelisted group (if activated) + $restrictLoginToGroups = $this->providerService->getSetting($providerId, ProviderService::SETTING_RESTRICT_LOGIN_TO_GROUPS, '0'); + if($restrictLoginToGroups === '1') { + $syncGroups = $this->provisioningService->getSyncGroupsOfToken($providerId, $idTokenPayload); + $this->logger->debug('Prevented user from login as user is not part of a whitelisted group'); + + if($syncGroups === null || count($syncGroups) === 0) { + $message = $this->l10n->t('You are not allowed to login'); + return $this->build403TemplateResponse($message, Http::STATUS_FORBIDDEN, ['reason' => 'user not allowed to login']); + } + } + $autoProvisionAllowed = (!isset($oidcSystemConfig['auto_provision']) || $oidcSystemConfig['auto_provision']); // in case user is provisioned by user_ldap, userManager->search() triggers an ldap search which syncs the results diff --git a/lib/Service/ProvisioningService.php b/lib/Service/ProvisioningService.php index d9f6ac9f..90532e4b 100644 --- a/lib/Service/ProvisioningService.php +++ b/lib/Service/ProvisioningService.php @@ -385,11 +385,11 @@ private function setUserAvatar(string $userId, string $avatarAttribute): void { } } - public function provisionUserGroups(IUser $user, int $providerId, object $idTokenPayload): void { + public function getSyncGroupsOfToken(int $providerId, object $idTokenPayload) { $groupsAttribute = $this->providerService->getSetting($providerId, ProviderService::SETTING_MAPPING_GROUPS, 'groups'); $groupsData = $idTokenPayload->{$groupsAttribute} ?? null; - $groupsWhitelistRegex = $this->providerService->getSetting($providerId, ProviderService::SETTING_GROUP_WHITELIST_REGEX, 'whitelist'); + $groupsWhitelistRegex = $this->providerService->getSetting($providerId, ProviderService::SETTING_GROUP_WHITELIST_REGEX, ''); $event = new AttributeMappedEvent(ProviderService::SETTING_MAPPING_GROUPS, $idTokenPayload, json_encode($groupsData)); $this->eventDispatcher->dispatchTyped($event); @@ -398,7 +398,6 @@ public function provisionUserGroups(IUser $user, int $providerId, object $idToke if ($event->hasValue() && $event->getValue() !== null) { // casted to null if empty value $groups = json_decode($event->getValue() ?? ''); - $userGroups = $this->groupManager->getUserGroups($user); $syncGroups = []; foreach ($groups as $k => $v) { @@ -425,6 +424,20 @@ public function provisionUserGroups(IUser $user, int $providerId, object $idToke $syncGroups[] = $group; } + return $syncGroups; + } + + return null; + } + + public function provisionUserGroups(IUser $user, int $providerId, object $idTokenPayload): void { + $groupsWhitelistRegex = $this->providerService->getSetting($providerId, ProviderService::SETTING_GROUP_WHITELIST_REGEX, ''); + + $syncGroups = $this->getSyncGroupsOfToken($providerId, $idTokenPayload); + + if($syncGroups !== null) { + + $userGroups = $this->groupManager->getUserGroups($user); foreach ($userGroups as $group) { if (!in_array($group->getGID(), array_column($syncGroups, 'gid'))) { if ($groupsWhitelistRegex && !preg_match($groupsWhitelistRegex, $group->getGID())) { diff --git a/tests/psalm-baseline.xml b/tests/psalm-baseline.xml index bee65b4a..6d291951 100644 --- a/tests/psalm-baseline.xml +++ b/tests/psalm-baseline.xml @@ -4,8 +4,5 @@ - - displayName)]]> - From 871ad68d019dd654d20c64b528229dc6c4cbbaa4 Mon Sep 17 00:00:00 2001 From: Armin Berger Date: Tue, 29 Oct 2024 22:48:08 +0100 Subject: [PATCH 3/8] test: fix existing tests Signed-off-by: Armin Berger --- lib/Service/ProviderService.php | 1 + tests/unit/Db/UserMapperTest.php | 3 +++ tests/unit/Service/ProviderServiceTest.php | 8 ++++++++ tests/unit/Service/ProvisioningServiceTest.php | 11 +++++++++-- 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/Service/ProviderService.php b/lib/Service/ProviderService.php index 7cc0da20..ff55bdb6 100644 --- a/lib/Service/ProviderService.php +++ b/lib/Service/ProviderService.php @@ -57,6 +57,7 @@ class ProviderService { self::SETTING_UNIQUE_UID => true, self::SETTING_CHECK_BEARER => false, self::SETTING_SEND_ID_TOKEN_HINT => false, + self::SETTING_RESTRICT_LOGIN_TO_GROUPS => false, ]; public function __construct( diff --git a/tests/unit/Db/UserMapperTest.php b/tests/unit/Db/UserMapperTest.php index b36af9bc..2812f312 100644 --- a/tests/unit/Db/UserMapperTest.php +++ b/tests/unit/Db/UserMapperTest.php @@ -20,6 +20,9 @@ class UserMapperTest extends TestCase { /** @var LocalIdService|MockObject */ private $idService; + /** @var IDBConnection|MockObject */ + private $db; + /** @var UserMapper|MockObject */ private $userMapper; diff --git a/tests/unit/Service/ProviderServiceTest.php b/tests/unit/Service/ProviderServiceTest.php index 2a7db068..7806028d 100644 --- a/tests/unit/Service/ProviderServiceTest.php +++ b/tests/unit/Service/ProviderServiceTest.php @@ -88,6 +88,8 @@ public function testGetProvidersWithSettings() { 'extraClaims' => '1', 'providerBasedId' => true, 'groupProvisioning' => true, + 'groupWhitelistRegex' => '1', + 'restrictLoginToGroups' => true, ], ], [ @@ -126,6 +128,8 @@ public function testGetProvidersWithSettings() { 'extraClaims' => '1', 'providerBasedId' => true, 'groupProvisioning' => true, + 'groupWhitelistRegex' => '1', + 'restrictLoginToGroups' => true, ], ], ], $this->providerService->getProvidersWithSettings()); @@ -161,6 +165,8 @@ public function testSetSettings() { 'mappingBiography' => 'biography', 'mappingPhonenumber' => 'phone', 'mappingGender' => 'gender', + 'groupWhitelistRegex' => '', + 'restrictLoginToGroups' => false, ]; $this->config->expects(self::any()) ->method('getAppValue') @@ -193,6 +199,8 @@ public function testSetSettings() { [Application::APP_ID, 'provider-1-' . ProviderService::SETTING_EXTRA_CLAIMS, '', 'claim1 claim2'], [Application::APP_ID, 'provider-1-' . ProviderService::SETTING_PROVIDER_BASED_ID, '', '0'], [Application::APP_ID, 'provider-1-' . ProviderService::SETTING_GROUP_PROVISIONING, '', '1'], + [Application::APP_ID, 'provider-1-' . ProviderService::SETTING_GROUP_WHITELIST_REGEX, '', ''], + [Application::APP_ID, 'provider-1-' . ProviderService::SETTING_RESTRICT_LOGIN_TO_GROUPS, '', '0'], ]); Assert::assertEquals( diff --git a/tests/unit/Service/ProvisioningServiceTest.php b/tests/unit/Service/ProvisioningServiceTest.php index c972a85e..6c981eae 100644 --- a/tests/unit/Service/ProvisioningServiceTest.php +++ b/tests/unit/Service/ProvisioningServiceTest.php @@ -34,6 +34,9 @@ class ProvisioningServiceTest extends TestCase { /** @var ProvisioningService | MockObject */ private $providerService; + /** @var LdapService | MockObject */ + private $ldapService; + /** @var UserMapper | MockObject */ private $userMapper; @@ -192,8 +195,12 @@ public function testProvisionUserGroups(string $gid, string $displayName, object $this->providerService ->method('getSetting') - ->with($providerId, ProviderService::SETTING_MAPPING_GROUPS, 'groups') - ->willReturn('groups'); + ->will($this->returnValueMap( + [ + [$providerId, ProviderService::SETTING_GROUP_WHITELIST_REGEX, '', ''], + [$providerId, ProviderService::SETTING_MAPPING_GROUPS, 'groups', 'groups'], + ] + )); $this->groupManager ->method('getUserGroups') From cde795392020c110f1565e13ddbbe655bd8738b9 Mon Sep 17 00:00:00 2001 From: Armin Berger Date: Mon, 17 Jun 2024 17:25:25 +0200 Subject: [PATCH 4/8] test: group provisioning with whitelist regex Signed-off-by: Armin Berger --- .../unit/Service/ProvisioningServiceTest.php | 53 +++++++++++++++++-- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/tests/unit/Service/ProvisioningServiceTest.php b/tests/unit/Service/ProvisioningServiceTest.php index 6c981eae..cdcd67b3 100644 --- a/tests/unit/Service/ProvisioningServiceTest.php +++ b/tests/unit/Service/ProvisioningServiceTest.php @@ -173,7 +173,9 @@ public function dataProvisionUserGroups() { 'displayName' => 'groupName1' ] ], - ] + ], + '', + true, ], [ '1', @@ -182,22 +184,55 @@ public function dataProvisionUserGroups() { 'groups' => [ 'group2' ], - ] + ], + '', + true, + ], + [ + '1_Group_Import', + 'Imported from OIDC', + (object)[ + 'groups' => [ + (object)[ + 'gid' => '1_Group_Import', + 'displayName' => 'Imported from OIDC', + ], + (object)[ + 'gid' => '10_Group_NoImport', + 'displayName' => 'Not Imported', + ] + ], + ], + '/^1_/', + false + ], + [ + '1', + 'users_nextcloud', + (object)[ + 'groups' => [ + 'users_nextcloud', + 'users', + ], + ], + '/nextcloud/', + false, ], ]; } /** @dataProvider dataProvisionUserGroups */ - public function testProvisionUserGroups(string $gid, string $displayName, object $payload): void { + public function testProvisionUserGroups(string $gid, string $displayName, object $payload, string $group_whitelist, bool $expect_delete_local_group): void { $user = $this->createMock(IUser::class); $group = $this->createMock(IGroup::class); + $local_group = $this->createMock(IGroup::class); $providerId = 421; $this->providerService ->method('getSetting') ->will($this->returnValueMap( [ - [$providerId, ProviderService::SETTING_GROUP_WHITELIST_REGEX, '', ''], + [$providerId, ProviderService::SETTING_GROUP_WHITELIST_REGEX, '', $group_whitelist], [$providerId, ProviderService::SETTING_MAPPING_GROUPS, 'groups', 'groups'], ] )); @@ -205,7 +240,15 @@ public function testProvisionUserGroups(string $gid, string $displayName, object $this->groupManager ->method('getUserGroups') ->with($user) - ->willReturn([]); + ->willReturn([$local_group]); + + $local_group + ->method('getGID') + ->willReturn('local_group'); + + $local_group->expects($expect_delete_local_group ? self::once() : self::never()) + ->method('removeUser') + ->with($user); $this->idService->method('getId') ->willReturn($gid); From 915ad84cd1e0d58442bdb9b85be1ea9f1c29f932 Mon Sep 17 00:00:00 2001 From: Armin Berger Date: Mon, 22 Jul 2024 15:59:42 +0200 Subject: [PATCH 5/8] chore: refine error message for restricted login Signed-off-by: Armin Berger --- lib/Controller/LoginController.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Controller/LoginController.php b/lib/Controller/LoginController.php index 35c799f5..aa529686 100644 --- a/lib/Controller/LoginController.php +++ b/lib/Controller/LoginController.php @@ -458,10 +458,10 @@ public function code(string $state = '', string $code = '', string $scope = '', $restrictLoginToGroups = $this->providerService->getSetting($providerId, ProviderService::SETTING_RESTRICT_LOGIN_TO_GROUPS, '0'); if($restrictLoginToGroups === '1') { $syncGroups = $this->provisioningService->getSyncGroupsOfToken($providerId, $idTokenPayload); - $this->logger->debug('Prevented user from login as user is not part of a whitelisted group'); if($syncGroups === null || count($syncGroups) === 0) { - $message = $this->l10n->t('You are not allowed to login'); + $this->logger->debug('Prevented user from login as user is not part of a whitelisted group'); + $message = $this->l10n->t('You do not have permission to log in to this instance. If you believe this is an error, please contact an Administrator.'); return $this->build403TemplateResponse($message, Http::STATUS_FORBIDDEN, ['reason' => 'user not allowed to login']); } } From 00f83fdac0484db04a7fc4199d3d89f99c4043ae Mon Sep 17 00:00:00 2001 From: Armin Berger Date: Sat, 2 Nov 2024 14:39:58 +0100 Subject: [PATCH 6/8] Apply suggestions from code review Co-authored-by: Julien Veyssier Signed-off-by: Armin Berger --- lib/Controller/LoginController.php | 4 ++-- src/components/SettingsForm.vue | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/Controller/LoginController.php b/lib/Controller/LoginController.php index aa529686..3071650a 100644 --- a/lib/Controller/LoginController.php +++ b/lib/Controller/LoginController.php @@ -461,8 +461,8 @@ public function code(string $state = '', string $code = '', string $scope = '', if($syncGroups === null || count($syncGroups) === 0) { $this->logger->debug('Prevented user from login as user is not part of a whitelisted group'); - $message = $this->l10n->t('You do not have permission to log in to this instance. If you believe this is an error, please contact an Administrator.'); - return $this->build403TemplateResponse($message, Http::STATUS_FORBIDDEN, ['reason' => 'user not allowed to login']); + $message = $this->l10n->t('You do not have permission to log in to this instance. If you think this is an error, please contact an administrator.'); + return $this->build403TemplateResponse($message, Http::STATUS_FORBIDDEN, ['reason' => 'user not in any whitelisted group']); } } diff --git a/src/components/SettingsForm.vue b/src/components/SettingsForm.vue index 3d9a78c3..3e369c5f 100644 --- a/src/components/SettingsForm.vue +++ b/src/components/SettingsForm.vue @@ -247,13 +247,13 @@ type="text">

- {{ t('user_oidc', 'Only groups matching the whitelist regex will be created, updated and deleted by the group claim') }} + {{ t('user_oidc', 'Only groups matching the whitelist regex will be created, updated and deleted by the group claim. For example: {regex} allows all groups which ID starts with {substr}', { regex: '/^blue/', substr: 'blue' }) }}

- {{ t('user_oidc', 'Restrict login for users without whitelisted groups.') }} + {{ t('user_oidc', 'Restrict login for users that are not in any whitelisted group') }}

- {{ t('user_oidc', 'Users that are not part of a whitelisted group are not created and can not login') }} + {{ t('user_oidc', 'Users that are not part of any whitelisted group are not created and can not login') }}

{{ t('user_oidc', 'Check Bearer token on API and WebDav requests') }} From 8492dd2aa62f899c6bb867c4e74e74226b1bd665 Mon Sep 17 00:00:00 2001 From: Armin Berger Date: Tue, 12 Nov 2024 21:41:59 +0100 Subject: [PATCH 7/8] feat: delimiter is optional for group whitelist regex Signed-off-by: Armin Berger --- lib/Service/ProvisioningService.php | 16 ++++++++++++++-- tests/unit/Service/ProvisioningServiceTest.php | 2 +- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/Service/ProvisioningService.php b/lib/Service/ProvisioningService.php index 90532e4b..4ec32b52 100644 --- a/lib/Service/ProvisioningService.php +++ b/lib/Service/ProvisioningService.php @@ -389,7 +389,7 @@ public function getSyncGroupsOfToken(int $providerId, object $idTokenPayload) { $groupsAttribute = $this->providerService->getSetting($providerId, ProviderService::SETTING_MAPPING_GROUPS, 'groups'); $groupsData = $idTokenPayload->{$groupsAttribute} ?? null; - $groupsWhitelistRegex = $this->providerService->getSetting($providerId, ProviderService::SETTING_GROUP_WHITELIST_REGEX, ''); + $groupsWhitelistRegex = $this->getGroupWhitelistRegex($providerId); $event = new AttributeMappedEvent(ProviderService::SETTING_MAPPING_GROUPS, $idTokenPayload, json_encode($groupsData)); $this->eventDispatcher->dispatchTyped($event); @@ -431,7 +431,7 @@ public function getSyncGroupsOfToken(int $providerId, object $idTokenPayload) { } public function provisionUserGroups(IUser $user, int $providerId, object $idTokenPayload): void { - $groupsWhitelistRegex = $this->providerService->getSetting($providerId, ProviderService::SETTING_GROUP_WHITELIST_REGEX, ''); + $groupsWhitelistRegex = $this->getGroupWhitelistRegex($providerId); $syncGroups = $this->getSyncGroupsOfToken($providerId, $idTokenPayload); @@ -460,4 +460,16 @@ public function provisionUserGroups(IUser $user, int $providerId, object $idToke } } } + + public function getGroupWhitelistRegex(int $providerId): string { + $regex = $this->providerService->getSetting($providerId, ProviderService::SETTING_GROUP_WHITELIST_REGEX, ''); + + // If regex does not start with '/', add '/' to the beginning and end + // Only check first character to allow for flags at the end of the regex + if ($regex && substr($regex, 0, 1) !== '/') { + $regex = '/' . $regex . '/'; + } + + return $regex; + } } diff --git a/tests/unit/Service/ProvisioningServiceTest.php b/tests/unit/Service/ProvisioningServiceTest.php index cdcd67b3..1c830434 100644 --- a/tests/unit/Service/ProvisioningServiceTest.php +++ b/tests/unit/Service/ProvisioningServiceTest.php @@ -215,7 +215,7 @@ public function dataProvisionUserGroups() { 'users', ], ], - '/nextcloud/', + 'nextcloud', false, ], ]; From c308b5833388f1f53bc51235fd45033390c9b4e9 Mon Sep 17 00:00:00 2001 From: Armin Berger Date: Wed, 13 Nov 2024 20:39:52 +0100 Subject: [PATCH 8/8] style: adapt style according to latest php-cs-fixer Signed-off-by: Armin Berger --- lib/Controller/LoginController.php | 4 ++-- lib/Service/ProvisioningService.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Controller/LoginController.php b/lib/Controller/LoginController.php index 3071650a..75c56fd3 100644 --- a/lib/Controller/LoginController.php +++ b/lib/Controller/LoginController.php @@ -456,10 +456,10 @@ public function code(string $state = '', string $code = '', string $scope = '', // prevent login of users that are not in a whitelisted group (if activated) $restrictLoginToGroups = $this->providerService->getSetting($providerId, ProviderService::SETTING_RESTRICT_LOGIN_TO_GROUPS, '0'); - if($restrictLoginToGroups === '1') { + if ($restrictLoginToGroups === '1') { $syncGroups = $this->provisioningService->getSyncGroupsOfToken($providerId, $idTokenPayload); - if($syncGroups === null || count($syncGroups) === 0) { + if ($syncGroups === null || count($syncGroups) === 0) { $this->logger->debug('Prevented user from login as user is not part of a whitelisted group'); $message = $this->l10n->t('You do not have permission to log in to this instance. If you think this is an error, please contact an administrator.'); return $this->build403TemplateResponse($message, Http::STATUS_FORBIDDEN, ['reason' => 'user not in any whitelisted group']); diff --git a/lib/Service/ProvisioningService.php b/lib/Service/ProvisioningService.php index 4ec32b52..342ef17c 100644 --- a/lib/Service/ProvisioningService.php +++ b/lib/Service/ProvisioningService.php @@ -435,7 +435,7 @@ public function provisionUserGroups(IUser $user, int $providerId, object $idToke $syncGroups = $this->getSyncGroupsOfToken($providerId, $idTokenPayload); - if($syncGroups !== null) { + if ($syncGroups !== null) { $userGroups = $this->groupManager->getUserGroups($user); foreach ($userGroups as $group) {