mirror of
https://github.com/nuxsmin/sysPass.git
synced 2026-03-03 15:14:08 +01:00
chore(tests): UT for LdapCheck service
Signed-off-by: Rubén D <nuxsmin@syspass.org>
This commit is contained in:
@@ -89,10 +89,10 @@ final class CheckController extends SimpleControllerBase
|
||||
$this->template->assign('header', __('Results'));
|
||||
|
||||
return $this->returnJsonResponseData(
|
||||
['template' => $this->template->render(), 'items' => $data['results']],
|
||||
['template' => $this->template->render(), 'items' => $data->getResults()],
|
||||
JsonMessage::JSON_SUCCESS,
|
||||
__u('LDAP connection OK'),
|
||||
[sprintf(__('Objects found: %d'), $data['count'])]
|
||||
[sprintf(__('Objects found: %d'), $data->count())]
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
processException($e);
|
||||
|
||||
@@ -93,13 +93,13 @@ final class CheckImportController extends SimpleControllerBase
|
||||
|
||||
$this->template->addTemplate('results', 'itemshow');
|
||||
$this->template->assign('header', __('Results'));
|
||||
$this->template->assign('results', $data);
|
||||
$this->template->assign('results', $data->getResults());
|
||||
|
||||
return $this->returnJsonResponseData(
|
||||
['template' => $this->template->render(), 'items' => $data['results']],
|
||||
['template' => $this->template->render(), 'items' => $data->getResults()],
|
||||
JsonMessage::JSON_SUCCESS,
|
||||
__u('LDAP connection OK'),
|
||||
[sprintf(__('Objects found: %d'), $data['count'])]
|
||||
[sprintf(__('Objects found: %d'), $data->count())]
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
processException($e);
|
||||
|
||||
55
lib/SP/Domain/Auth/Dtos/LdapCheckResults.php
Normal file
55
lib/SP/Domain/Auth/Dtos/LdapCheckResults.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/*
|
||||
* sysPass
|
||||
*
|
||||
* @author nuxsmin
|
||||
* @link https://syspass.org
|
||||
* @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org
|
||||
*
|
||||
* This file is part of sysPass.
|
||||
*
|
||||
* sysPass is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sysPass is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace SP\Domain\Auth\Dtos;
|
||||
|
||||
/**
|
||||
* Class LdapCheckResults
|
||||
*/
|
||||
final class LdapCheckResults
|
||||
{
|
||||
|
||||
private array $results = [];
|
||||
|
||||
public function __construct(array $items, ?string $type = null)
|
||||
{
|
||||
$this->addItems($items, $type);
|
||||
}
|
||||
|
||||
|
||||
public function addItems(array $items, ?string $type = null): void
|
||||
{
|
||||
$this->results[] = ['items' => $items, 'type' => $type];
|
||||
}
|
||||
|
||||
public function count(): int
|
||||
{
|
||||
return (int)array_sum(array_map(fn(array $result) => count($result['items']), $this->results));
|
||||
}
|
||||
|
||||
public function getResults(): array
|
||||
{
|
||||
return $this->results;
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@
|
||||
namespace SP\Domain\Auth\Ports;
|
||||
|
||||
|
||||
use SP\Domain\Auth\Dtos\LdapCheckResults;
|
||||
use SP\Providers\Auth\Ldap\LdapException;
|
||||
|
||||
/**
|
||||
@@ -37,10 +38,10 @@ interface LdapCheckService
|
||||
/**
|
||||
* @throws LdapException
|
||||
*/
|
||||
public function getObjects(bool $includeGroups = true): array;
|
||||
public function getObjects(bool $includeGroups = true): LdapCheckResults;
|
||||
|
||||
/**
|
||||
* @throws LdapException
|
||||
*/
|
||||
public function getObjectsByFilter(string $filter): array;
|
||||
public function getObjectsByFilter(string $filter): LdapCheckResults;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
namespace SP\Domain\Auth\Services;
|
||||
|
||||
use SP\Core\Application;
|
||||
use SP\Domain\Auth\Dtos\LdapCheckResults;
|
||||
use SP\Domain\Auth\Ports\LdapActionsService;
|
||||
use SP\Domain\Auth\Ports\LdapCheckService;
|
||||
use SP\Domain\Auth\Ports\LdapConnectionInterface;
|
||||
@@ -50,23 +51,87 @@ final class LdapCheck extends Service implements LdapCheckService
|
||||
/**
|
||||
* @throws LdapException
|
||||
*/
|
||||
public function getObjectsByFilter(string $filter, ?LdapParams $ldapParams = null): array
|
||||
public function getObjectsByFilter(string $filter, ?LdapParams $ldapParams = null): LdapCheckResults
|
||||
{
|
||||
return new LdapCheckResults(
|
||||
self::getObjectsWithAttributes($this->getLdap($ldapParams)->actions(), $filter, ['dn'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws LdapException
|
||||
*/
|
||||
private static function getObjectsWithAttributes(
|
||||
LdapActionsService $ldapActionsService,
|
||||
string $filter,
|
||||
array $attributes
|
||||
): array {
|
||||
return self::ldapResultsMapper(
|
||||
iterator_to_array($ldapActionsService->getObjects($filter, $attributes)->getIterator()),
|
||||
$attributes
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener los datos de una búsqueda de LDAP de un atributo
|
||||
*
|
||||
* @param array $data
|
||||
* @param string[] $attributes
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function ldapResultsMapper(array $data, array $attributes = ['dn']): array
|
||||
{
|
||||
$attributesKey = array_flip($attributes);
|
||||
|
||||
return array_map(
|
||||
static function (mixed $value) {
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $k => $v) {
|
||||
if ($k !== 'count') {
|
||||
return $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
},
|
||||
array_filter($data, static fn(mixed $d) => is_array($d) && array_intersect_key($d, $attributesKey))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws LdapException
|
||||
*/
|
||||
public function getObjects(bool $includeGroups = true, ?LdapParams $ldapParams = null): LdapCheckResults
|
||||
{
|
||||
$ldap = $this->getLdap($ldapParams);
|
||||
|
||||
$objects = $this->ldapResultsMapper(
|
||||
$ldap->actions()->getObjects($filter, ['dn'])
|
||||
$ldapActionsService = $ldap->actions();
|
||||
|
||||
$indirectFilterItems =
|
||||
self::getObjectsWithAttributes($ldapActionsService, $ldap->getGroupMembershipIndirectFilter(), ['dn']);
|
||||
|
||||
$directFilterItems = self::getObjectsWithAttributes(
|
||||
$ldapActionsService,
|
||||
$ldap->getGroupMembershipDirectFilter(),
|
||||
['member', 'memberUid', 'uniqueMember']
|
||||
);
|
||||
|
||||
return [
|
||||
'count' => count($objects),
|
||||
'results' => [
|
||||
[
|
||||
'icon' => '',
|
||||
'items' => $objects,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$ldapCheckResults = new LdapCheckResults(
|
||||
array_values(array_unique(array_merge($indirectFilterItems, $directFilterItems))),
|
||||
'person'
|
||||
);
|
||||
|
||||
if ($includeGroups) {
|
||||
$ldapCheckResults->addItems(
|
||||
self::getObjectsWithAttributes($ldapActionsService, $ldap->getGroupObjectFilter(), ['dn']),
|
||||
'group'
|
||||
);
|
||||
}
|
||||
|
||||
return $ldapCheckResults;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,88 +149,4 @@ final class LdapCheck extends Service implements LdapCheckService
|
||||
$ldapParams
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener los datos de una búsqueda de LDAP de un atributo
|
||||
*
|
||||
* @param array $data
|
||||
* @param string[] $attributes
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function ldapResultsMapper(
|
||||
array $data,
|
||||
array $attributes = ['dn']
|
||||
): array {
|
||||
$out = [];
|
||||
|
||||
foreach ($data as $result) {
|
||||
if (is_array($result)) {
|
||||
foreach ($result as $ldapAttribute => $value) {
|
||||
if (in_array(strtolower($ldapAttribute), $attributes, true)) {
|
||||
if (is_array($value)) {
|
||||
unset($value['count']);
|
||||
|
||||
$out = array_merge($out, $value);
|
||||
} else {
|
||||
$out[] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws LdapException
|
||||
*/
|
||||
public function getObjects(bool $includeGroups = true, ?LdapParams $ldapParams = null): array
|
||||
{
|
||||
$ldap = $this->getLdap($ldapParams);
|
||||
|
||||
$ldapActions = $ldap->actions();
|
||||
|
||||
$data = ['count' => 0, 'results' => []];
|
||||
|
||||
$indirectFilterItems = $this->ldapResultsMapper(
|
||||
$ldapActions->getObjects($ldap->getGroupMembershipIndirectFilter(), ['dn'])
|
||||
);
|
||||
|
||||
$directFilterItems = $this->ldapResultsMapper(
|
||||
$ldapActions->getObjects(
|
||||
$ldap->getGroupMembershipDirectFilter(),
|
||||
['member', 'memberUid', 'uniqueMember']
|
||||
),
|
||||
['member', 'memberUid', 'uniqueMember']
|
||||
);
|
||||
|
||||
$userItems = array_unique(array_merge($indirectFilterItems, $directFilterItems));
|
||||
|
||||
$data['results'][] = [
|
||||
'icon' => 'person',
|
||||
'items' => array_values($userItems),
|
||||
];
|
||||
|
||||
if ($includeGroups) {
|
||||
$groupItems = $this->ldapResultsMapper(
|
||||
$ldapActions->getObjects($ldap->getGroupObjectFilter(), ['dn'])
|
||||
);
|
||||
|
||||
$data['results'][] = [
|
||||
'icon' => 'group',
|
||||
'items' => $groupItems,
|
||||
];
|
||||
}
|
||||
|
||||
array_walk(
|
||||
$data['results'],
|
||||
static function ($value) use (&$data) {
|
||||
$data['count'] += count($value['items']);
|
||||
}
|
||||
);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,9 +29,9 @@ use Iterator;
|
||||
/**
|
||||
* Class LdapResults
|
||||
*/
|
||||
class LdapResults
|
||||
readonly class LdapResults
|
||||
{
|
||||
public function __construct(private readonly int $count, private readonly Iterator $iterator)
|
||||
public function __construct(private int $count, private Iterator $iterator)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
268
tests/SPT/Domain/Auth/Services/LdapCheckTest.php
Normal file
268
tests/SPT/Domain/Auth/Services/LdapCheckTest.php
Normal file
@@ -0,0 +1,268 @@
|
||||
<?php
|
||||
/*
|
||||
* sysPass
|
||||
*
|
||||
* @author nuxsmin
|
||||
* @link https://syspass.org
|
||||
* @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org
|
||||
*
|
||||
* This file is part of sysPass.
|
||||
*
|
||||
* sysPass is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sysPass is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace SPT\Domain\Auth\Services;
|
||||
|
||||
use ArrayIterator;
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use SP\Domain\Auth\Ports\LdapActionsService;
|
||||
use SP\Domain\Auth\Ports\LdapConnectionInterface;
|
||||
use SP\Domain\Auth\Services\LdapCheck;
|
||||
use SP\Providers\Auth\Ldap\LdapException;
|
||||
use SP\Providers\Auth\Ldap\LdapParams;
|
||||
use SP\Providers\Auth\Ldap\LdapResults;
|
||||
use SP\Providers\Auth\Ldap\LdapTypeEnum;
|
||||
use SPT\UnitaryTestCase;
|
||||
|
||||
/**
|
||||
* Class LdapCheckTest
|
||||
*/
|
||||
#[Group('unitary')]
|
||||
class LdapCheckTest extends UnitaryTestCase
|
||||
{
|
||||
|
||||
private LdapCheck $ldapCheck;
|
||||
private LdapConnectionInterface|MockObject $ldapConnection;
|
||||
private MockObject|LdapActionsService $ldapActionsService;
|
||||
|
||||
/**
|
||||
* @throws LdapException
|
||||
*/
|
||||
public function testGetObjectsByFilterWithParams()
|
||||
{
|
||||
$ldapParams = new LdapParams('a_server', LdapTypeEnum::STD, 'a_dn', 'a_pass');
|
||||
|
||||
$ldapData = $this->getLdapData();
|
||||
|
||||
$ldapResults = new LdapResults(10, new ArrayIterator($ldapData));
|
||||
|
||||
$this->ldapActionsService
|
||||
->expects($this->once())
|
||||
->method('getObjects')
|
||||
->with('a_filter', ['dn'])
|
||||
->willReturn($ldapResults);
|
||||
|
||||
$out = $this->ldapCheck->getObjectsByFilter('a_filter', $ldapParams);
|
||||
|
||||
$this->assertEquals(5, $out->count());
|
||||
|
||||
$results = $out->getResults();
|
||||
|
||||
foreach ($ldapData as $index => $data) {
|
||||
$this->assertEquals($data['dn'], $results[0]['items'][$index]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|array[]
|
||||
*/
|
||||
private function getLdapData(): array
|
||||
{
|
||||
return array_map(
|
||||
static fn() => [
|
||||
'count' => self::$faker->randomNumber(2),
|
||||
'dn' => self::$faker->userName(),
|
||||
'email' => [self::$faker->email(), self::$faker->email()],
|
||||
'member' => self::$faker->userName(),
|
||||
'memberUid' => self::$faker->uuid(),
|
||||
'uniqueMember' => self::$faker->uuid()
|
||||
],
|
||||
range(0, 4)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws LdapException
|
||||
*/
|
||||
public function testGetObjectsByFilterWithConnectionException()
|
||||
{
|
||||
$ldapParams = new LdapParams('a_server', LdapTypeEnum::STD, 'a_dn', 'a_pass');
|
||||
|
||||
$this->ldapActionsService
|
||||
->expects($this->never())
|
||||
->method('getObjects');
|
||||
|
||||
$this->ldapConnection
|
||||
->expects($this->once())
|
||||
->method('checkConnection')
|
||||
->willThrowException(LdapException::error('test'));
|
||||
|
||||
$this->expectException(LdapException::class);
|
||||
$this->expectExceptionMessage('test');
|
||||
|
||||
$this->ldapCheck->getObjectsByFilter('a_filter', $ldapParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws LdapException
|
||||
*/
|
||||
public function testGetObjectsByFilterWithObjectsException()
|
||||
{
|
||||
$ldapParams = new LdapParams('a_server', LdapTypeEnum::STD, 'a_dn', 'a_pass');
|
||||
|
||||
$this->ldapActionsService
|
||||
->expects($this->once())
|
||||
->method('getObjects')
|
||||
->willThrowException(LdapException::error('test'));
|
||||
|
||||
$this->expectException(LdapException::class);
|
||||
$this->expectExceptionMessage('test');
|
||||
|
||||
$this->ldapCheck->getObjectsByFilter('a_filter', $ldapParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws LdapException
|
||||
*/
|
||||
public function testGetObjectsWithParams()
|
||||
{
|
||||
$ldapParams = new LdapParams('a_server', LdapTypeEnum::STD, 'a_dn', 'a_pass');
|
||||
$ldapParams->setFilterUserObject('a_user_filter');
|
||||
$ldapParams->setFilterGroupObject('a_group_filter');
|
||||
|
||||
$ldapData = $this->getLdapData();
|
||||
|
||||
$ldapResults = new LdapResults(10, new ArrayIterator($ldapData));
|
||||
|
||||
$this->ldapActionsService
|
||||
->expects($this->exactly(3))
|
||||
->method('getObjects')
|
||||
->with(
|
||||
...
|
||||
self::withConsecutive(
|
||||
['a_user_filter', ['dn']],
|
||||
['a_user_filter', ['member', 'memberUid', 'uniqueMember']],
|
||||
['a_group_filter', ['dn']],
|
||||
)
|
||||
)
|
||||
->willReturn($ldapResults);
|
||||
|
||||
$out = $this->ldapCheck->getObjects(true, $ldapParams);
|
||||
|
||||
$this->assertEquals(10, $out->count());
|
||||
|
||||
$results = $out->getResults();
|
||||
|
||||
foreach ($ldapData as $index => $data) {
|
||||
$this->assertEquals($data['dn'], $results[0]['items'][$index]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws LdapException
|
||||
*/
|
||||
public function testGetObjectsWithNoParams()
|
||||
{
|
||||
$ldapParams = new LdapParams('a_server', LdapTypeEnum::STD, 'a_dn', 'a_pass');
|
||||
|
||||
$ldapDataUsers = $this->getLdapData();
|
||||
$ldapDataGroups = $this->getLdapData();
|
||||
|
||||
$ldapResultsUsers = new LdapResults(10, new ArrayIterator($ldapDataUsers));
|
||||
$ldapResultsGroups = new LdapResults(10, new ArrayIterator($ldapDataGroups));
|
||||
|
||||
$this->ldapActionsService
|
||||
->expects($this->exactly(3))
|
||||
->method('getObjects')
|
||||
->with(
|
||||
...
|
||||
self::withConsecutive(
|
||||
['(|(objectClass=inetOrgPerson)(objectClass=person)(objectClass=simpleSecurityObject))', ['dn']],
|
||||
[
|
||||
'(|(objectClass=inetOrgPerson)(objectClass=person)(objectClass=simpleSecurityObject))',
|
||||
['member', 'memberUid', 'uniqueMember']
|
||||
],
|
||||
['(|(objectClass=groupOfNames)(objectClass=groupOfUniqueNames)(objectClass=group))', ['dn']],
|
||||
)
|
||||
)
|
||||
->willReturn($ldapResultsUsers, $ldapResultsUsers, $ldapResultsGroups);
|
||||
|
||||
$out = $this->ldapCheck->getObjects(true, $ldapParams);
|
||||
|
||||
$this->assertEquals(10, $out->count());
|
||||
|
||||
$results = $out->getResults();
|
||||
|
||||
foreach ($ldapDataUsers as $index => $data) {
|
||||
$this->assertEquals($data['dn'], $results[0]['items'][$index]);
|
||||
}
|
||||
|
||||
foreach ($ldapResultsGroups as $index => $data) {
|
||||
$this->assertEquals($data['dn'], $results[1]['items'][$index]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws LdapException
|
||||
*/
|
||||
public function testGetObjectsWitConnectionException()
|
||||
{
|
||||
$ldapParams = new LdapParams('a_server', LdapTypeEnum::STD, 'a_dn', 'a_pass');
|
||||
|
||||
$this->ldapActionsService
|
||||
->expects($this->never())
|
||||
->method('getObjects');
|
||||
|
||||
$this->ldapConnection
|
||||
->expects($this->once())
|
||||
->method('checkConnection')
|
||||
->willThrowException(LdapException::error('test'));
|
||||
|
||||
$this->expectException(LdapException::class);
|
||||
$this->expectExceptionMessage('test');
|
||||
|
||||
$this->ldapCheck->getObjects(true, $ldapParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws LdapException
|
||||
*/
|
||||
public function testGetObjectsWitObjectsException()
|
||||
{
|
||||
$ldapParams = new LdapParams('a_server', LdapTypeEnum::STD, 'a_dn', 'a_pass');
|
||||
|
||||
$this->ldapActionsService
|
||||
->expects($this->once())
|
||||
->method('getObjects')
|
||||
->willThrowException(LdapException::error('test'));
|
||||
|
||||
$this->expectException(LdapException::class);
|
||||
$this->expectExceptionMessage('test');
|
||||
|
||||
$this->ldapCheck->getObjects(true, $ldapParams);
|
||||
}
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->ldapConnection = $this->createMock(LdapConnectionInterface::class);
|
||||
$this->ldapConnection->method('mutate')->willReturnSelf();
|
||||
$this->ldapActionsService = $this->createMock(LdapActionsService::class);
|
||||
$this->ldapActionsService->method('mutate')->willReturnSelf();
|
||||
|
||||
$this->ldapCheck = new LdapCheck($this->application, $this->ldapConnection, $this->ldapActionsService);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user