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']);