From 8594f4258417e0e7a4a59c17d006d87dc84e9f3a Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Wed, 23 Mar 2022 16:34:23 +0000 Subject: [PATCH] Added LDAP group debugging env option Closes #3345 --- app/Auth/Access/Guards/LdapSessionGuard.php | 12 +++-- app/Auth/Access/LdapService.php | 28 ++++++++--- app/Config/services.php | 1 + phpunit.xml | 2 + tests/Auth/LdapTest.php | 56 +++++++++++++++++++++ 5 files changed, 88 insertions(+), 11 deletions(-) diff --git a/app/Auth/Access/Guards/LdapSessionGuard.php b/app/Auth/Access/Guards/LdapSessionGuard.php index 5a902af76..18d4c289d 100644 --- a/app/Auth/Access/Guards/LdapSessionGuard.php +++ b/app/Auth/Access/Guards/LdapSessionGuard.php @@ -5,6 +5,7 @@ namespace BookStack\Auth\Access\Guards; use BookStack\Auth\Access\LdapService; use BookStack\Auth\Access\RegistrationService; use BookStack\Auth\User; +use BookStack\Exceptions\JsonDebugException; use BookStack\Exceptions\LdapException; use BookStack\Exceptions\LoginAttemptEmailNeededException; use BookStack\Exceptions\LoginAttemptException; @@ -15,7 +16,7 @@ use Illuminate\Support\Str; class LdapSessionGuard extends ExternalBaseSessionGuard { - protected $ldapService; + protected LdapService $ldapService; /** * LdapSessionGuard constructor. @@ -57,12 +58,13 @@ class LdapSessionGuard extends ExternalBaseSessionGuard * Attempt to authenticate a user using the given credentials. * * @param array $credentials - * @param bool $remember - * - * @throws LoginAttemptException - * @throws LdapException + * @param bool $remember * * @return bool + * @throws LdapException*@throws \BookStack\Exceptions\JsonDebugException + * + * @throws LoginAttemptException + * @throws JsonDebugException */ public function attempt(array $credentials = [], $remember = false) { diff --git a/app/Auth/Access/LdapService.php b/app/Auth/Access/LdapService.php index e529b80fd..f5d64dab3 100644 --- a/app/Auth/Access/LdapService.php +++ b/app/Auth/Access/LdapService.php @@ -15,12 +15,17 @@ use Illuminate\Support\Facades\Log; */ class LdapService { - protected $ldap; - protected $groupSyncService; + protected Ldap $ldap; + protected GroupSyncService $groupSyncService; + protected UserAvatars $userAvatars; + + /** + * @var resource + */ protected $ldapConnection; - protected $userAvatars; - protected $config; - protected $enabled; + + protected array $config; + protected bool $enabled; /** * LdapService constructor. @@ -274,6 +279,7 @@ class LdapService * Get the groups a user is a part of on ldap. * * @throws LdapException + * @throws JsonDebugException */ public function getUserGroups(string $userName): array { @@ -285,8 +291,17 @@ class LdapService } $userGroups = $this->groupFilter($user); + $allGroups = $this->getGroupsRecursive($userGroups, []); - return $this->getGroupsRecursive($userGroups, []); + if ($this->config['dump_user_groups']) { + throw new JsonDebugException([ + 'details_from_ldap' => $user, + 'parsed_direct_user_groups' => $userGroups, + 'parsed_recursive_user_groups' => $allGroups, + ]); + } + + return $allGroups; } /** @@ -369,6 +384,7 @@ class LdapService * Sync the LDAP groups to the user roles for the current user. * * @throws LdapException + * @throws JsonDebugException */ public function syncGroups(User $user, string $username) { diff --git a/app/Config/services.php b/app/Config/services.php index 2d7253fb8..a035f1056 100644 --- a/app/Config/services.php +++ b/app/Config/services.php @@ -119,6 +119,7 @@ return [ 'ldap' => [ 'server' => env('LDAP_SERVER', false), 'dump_user_details' => env('LDAP_DUMP_USER_DETAILS', false), + 'dump_user_groups' => env('LDAP_DUMP_USER_GROUPS', false), 'dn' => env('LDAP_DN', false), 'pass' => env('LDAP_PASS', false), 'base_dn' => env('LDAP_BASE_DN', false), diff --git a/phpunit.xml b/phpunit.xml index 960f4c4c3..90320ff41 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -34,6 +34,8 @@ + + diff --git a/tests/Auth/LdapTest.php b/tests/Auth/LdapTest.php index d00e8cf15..c59685ef5 100644 --- a/tests/Auth/LdapTest.php +++ b/tests/Auth/LdapTest.php @@ -348,6 +348,62 @@ class LdapTest extends TestCase ]); } + public function test_dump_user_groups_shows_group_related_details_as_json() + { + app('config')->set([ + 'services.ldap.user_to_groups' => true, + 'services.ldap.group_attribute' => 'memberOf', + 'services.ldap.remove_from_groups' => true, + 'services.ldap.dump_user_groups' => true, + ]); + + $userResp = ['count' => 1, 0 => [ + 'uid' => [$this->mockUser->name], + 'cn' => [$this->mockUser->name], + 'dn' => 'dc=test,' . config('services.ldap.base_dn'), + 'mail' => [$this->mockUser->email], + ]]; + $this->commonLdapMocks(1, 1, 4, 5, 4, 2); + $this->mockLdap->shouldReceive('searchAndGetEntries')->times(4) + ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array')) + ->andReturn($userResp, ['count' => 1, + 0 => [ + 'dn' => 'dc=test,' . config('services.ldap.base_dn'), + 'memberof' => [ + 'count' => 1, + 0 => 'cn=ldaptester,ou=groups,dc=example,dc=com', + ], + ], + ], [ + 'count' => 1, + 0 => [ + 'dn' => 'cn=ldaptester,ou=groups,dc=example,dc=com', + 'memberof' => [ + 'count' => 1, + 0 => 'cn=monsters,ou=groups,dc=example,dc=com', + ], + ] + ], ['count' => 0]); + + $resp = $this->mockUserLogin(); + $resp->assertJson([ + 'details_from_ldap' => [ + 'dn' => 'dc=test,' . config('services.ldap.base_dn'), + 'memberof' => [ + 0 => 'cn=ldaptester,ou=groups,dc=example,dc=com', + 'count' => 1, + ] + ], + 'parsed_direct_user_groups' => [ + 'ldaptester', + ], + 'parsed_recursive_user_groups' => [ + 'ldaptester', + 'monsters', + ], + ]); + } + public function test_external_auth_id_visible_in_roles_page_when_ldap_active() { $role = Role::factory()->create(['display_name' => 'ldaptester', 'external_auth_id' => 'ex-auth-a, test-second-param']);