/**
* Set LDAP method mocks for things we commonly call without altering.
*/
- protected function commonLdapMocks(int $connects = 1, int $versions = 1, int $options = 2, int $binds = 4, int $escapes = 2, int $explodes = 0)
+ protected function commonLdapMocks(int $connects = 1, int $versions = 1, int $options = 2, int $binds = 4, int $escapes = 2, int $explodes = 0, int $groups = 0)
{
$this->mockLdap->shouldReceive('connect')->times($connects)->andReturn($this->resourceId);
$this->mockLdap->shouldReceive('setVersion')->times($versions);
$this->mockLdap->shouldReceive('bind')->times($binds)->andReturn(true);
$this->mockEscapes($escapes);
$this->mockExplodes($explodes);
+ $this->mockGroupLookups($groups);
+ }
+
+ protected function mockGroupLookups(int $times = 1): void
+ {
+ $this->mockLdap->shouldReceive('read')->times($times)->andReturn(['count' => 0]);
+ $this->mockLdap->shouldReceive('getEntries')->times($times)->andReturn(['count' => 0]);
}
public function test_login()
$this->assertDatabaseHas('users', ['email' => $this->mockUser->email, 'email_confirmed' => false, 'external_auth_id' => $ldapDn]);
}
+ public function test_login_works_when_ldap_server_does_not_provide_a_cn_value()
+ {
+ $ldapDn = 'cn=test-user,dc=test' . config('services.ldap.base_dn');
+
+ $this->commonLdapMocks(1, 1, 1, 2, 1);
+ $this->mockLdap->shouldReceive('searchAndGetEntries')->times(1)
+ ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array'))
+ ->andReturn(['count' => 1, 0 => [
+ 'dn' => $ldapDn,
+ 'mail' => [$this->mockUser->email],
+ ]]);
+
+ $resp = $this->mockUserLogin();
+ $resp->assertRedirect('/');
+ $this->assertDatabaseHas('users', [
+ 'name' => 'test-user',
+ 'email' => $this->mockUser->email,
+ ]);
+ }
+
public function test_a_custom_uid_attribute_can_be_specified_and_is_used_properly()
{
config()->set(['services.ldap.id_attribute' => 'my_custom_id']);
'services.ldap.remove_from_groups' => false,
]);
- $this->commonLdapMocks(1, 1, 4, 5, 4, 6);
- $this->mockLdap->shouldReceive('searchAndGetEntries')->times(4)
+ $this->commonLdapMocks(1, 1, 4, 5, 2, 2, 2);
+ $this->mockLdap->shouldReceive('searchAndGetEntries')->times(2)
->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array'))
->andReturn(['count' => 1, 0 => [
'uid' => [$this->mockUser->name],
'services.ldap.remove_from_groups' => true,
]);
- $this->commonLdapMocks(1, 1, 3, 4, 3, 2);
- $this->mockLdap->shouldReceive('searchAndGetEntries')->times(3)
+ $this->commonLdapMocks(1, 1, 3, 4, 2, 1, 1);
+ $this->mockLdap->shouldReceive('searchAndGetEntries')->times(2)
->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array'))
->andReturn(['count' => 1, 0 => [
'uid' => [$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)
+ $this->commonLdapMocks(1, 1, 4, 5, 2, 2, 0);
+ $this->mockLdap->shouldReceive('searchAndGetEntries')->times(2)
->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'),
+ 0 => [
+ 'dn' => 'dc=test,' . config('services.ldap.base_dn'),
'memberof' => [
'count' => 1,
- 0 => 'cn=ldaptester,ou=groups,dc=example,dc=com',
+ 0 => 'cn=ldaptester,ou=groups,dc=example,dc=com',
],
],
- ], [
+ ]);
+
+ $this->mockLdap->shouldReceive('read')->times(2);
+ $this->mockLdap->shouldReceive('getEntries')->times(2)
+ ->andReturn([
'count' => 1,
- 0 => [
- 'dn' => 'cn=ldaptester,ou=groups,dc=example,dc=com',
- 'memberof' => [
+ 0 => [
+ 'dn' => 'cn=ldaptester,ou=groups,dc=example,dc=com',
+ 'memberof' => [
'count' => 1,
0 => 'cn=monsters,ou=groups,dc=example,dc=com',
],
],
],
'parsed_direct_user_groups' => [
- 'ldaptester',
+ 'cn=ldaptester,ou=groups,dc=example,dc=com',
],
'parsed_recursive_user_groups' => [
+ 'cn=ldaptester,ou=groups,dc=example,dc=com',
+ 'cn=monsters,ou=groups,dc=example,dc=com',
+ ],
+ 'parsed_resulting_group_names' => [
'ldaptester',
'monsters',
],
]);
}
+ public function test_recursive_group_search_queries_via_full_dn()
+ {
+ app('config')->set([
+ 'services.ldap.user_to_groups' => true,
+ 'services.ldap.group_attribute' => 'memberOf',
+ ]);
+
+ $userResp = ['count' => 1, 0 => [
+ 'uid' => [$this->mockUser->name],
+ 'cn' => [$this->mockUser->name],
+ 'dn' => 'dc=test,' . config('services.ldap.base_dn'),
+ 'mail' => [$this->mockUser->email],
+ ]];
+ $groupResp = ['count' => 1,
+ 0 => [
+ 'dn' => 'dc=test,' . config('services.ldap.base_dn'),
+ 'memberof' => [
+ 'count' => 1,
+ 0 => 'cn=ldaptester,ou=groups,dc=example,dc=com',
+ ],
+ ],
+ ];
+
+ $this->commonLdapMocks(1, 1, 3, 4, 2, 1);
+
+ $escapedName = ldap_escape($this->mockUser->name);
+ $this->mockLdap->shouldReceive('searchAndGetEntries')->twice()
+ ->with($this->resourceId, config('services.ldap.base_dn'), "(&(uid={$escapedName}))", \Mockery::type('array'))
+ ->andReturn($userResp, $groupResp);
+
+ $this->mockLdap->shouldReceive('read')->times(1)
+ ->with($this->resourceId, 'cn=ldaptester,ou=groups,dc=example,dc=com', '(objectClass=*)', ['memberof'])
+ ->andReturn(['count' => 0]);
+ $this->mockLdap->shouldReceive('getEntries')->times(1)
+ ->with($this->resourceId, ['count' => 0])
+ ->andReturn(['count' => 0]);
+
+ $resp = $this->mockUserLogin();
+ $resp->assertRedirect('/');
+ }
+
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']);
'services.ldap.remove_from_groups' => true,
]);
- $this->commonLdapMocks(1, 1, 3, 4, 3, 2);
- $this->mockLdap->shouldReceive('searchAndGetEntries')->times(3)
+ $this->commonLdapMocks(1, 1, 3, 4, 2, 1, 1);
+ $this->mockLdap->shouldReceive('searchAndGetEntries')->times(2)
->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array'))
->andReturn(['count' => 1, 0 => [
'uid' => [$this->mockUser->name],
'services.ldap.remove_from_groups' => true,
]);
- $this->commonLdapMocks(1, 1, 4, 5, 4, 6);
- $this->mockLdap->shouldReceive('searchAndGetEntries')->times(4)
+ $this->commonLdapMocks(1, 1, 4, 5, 2, 2, 2);
+ $this->mockLdap->shouldReceive('searchAndGetEntries')->times(2)
->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array'))
->andReturn(['count' => 1, 0 => [
'uid' => [$this->mockUser->name],
$this->assertDatabaseHas('users', ['email' => $this->mockUser->email, 'email_confirmed' => false, 'external_auth_id' => $this->mockUser->name, 'name' => 'displayNameAttribute']);
}
+ public function test_login_uses_multiple_display_properties_if_defined()
+ {
+ app('config')->set([
+ 'services.ldap.display_name_attribute' => 'firstname|middlename|noname|lastname',
+ ]);
+
+ $this->commonLdapMocks(1, 1, 1, 2, 1);
+ $this->mockLdap->shouldReceive('searchAndGetEntries')->times(1)
+ ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array'))
+ ->andReturn(['count' => 1, 0 => [
+ 'uid' => [$this->mockUser->name],
+ 'cn' => [$this->mockUser->name],
+ 'dn' => 'dc=test' . config('services.ldap.base_dn'),
+ 'firstname' => ['Barry'],
+ 'middlename' => ['Elliott'],
+ 'lastname' => ['Chuckle'],
+ 'mail' => [$this->mockUser->email],
+ ]]);
+
+ $this->mockUserLogin();
+
+ $this->assertDatabaseHas('users', [
+ 'email' => $this->mockUser->email,
+ 'name' => 'Barry Elliott Chuckle',
+ ]);
+ }
+
public function test_login_uses_default_display_name_attribute_if_specified_not_present()
{
app('config')->set([
'services.ldap.remove_from_groups' => true,
]);
- $this->commonLdapMocks(1, 1, 6, 8, 6, 4);
+ $this->commonLdapMocks(1, 1, 6, 8, 4, 2, 2);
$this->mockLdap->shouldReceive('searchAndGetEntries')
- ->times(6)
+ ->times(4)
->andReturn(['count' => 1, 0 => [
'uid' => [$user->name],
'cn' => [$user->name],