Skip to content

Commit

Permalink
Add some extra tests
Browse files Browse the repository at this point in the history
  • Loading branch information
christeredvartsen committed Aug 26, 2021
1 parent 73b5fcf commit df3a486
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 61 deletions.
25 changes: 7 additions & 18 deletions src/Auth/AccessControl/Adapter/AbstractAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,22 @@ public function hasAccess(string $publicKey, string $resource, string $user = nu

// If a user is specified, ensure the public key has access to the user
$userAccess = !$user || $acl['users'] === '*' || in_array($user, $acl['users']);

if (!$userAccess) {
continue;
}

// Figure out which resources the public key has access to, based on group or
// explicit definition
$resources = isset($acl['resources']) ? $acl['resources'] : [];
$group = isset($acl['group']) ? $acl['group'] : false;
$resources = $acl['resources'] ?? [];
$group = $acl['group'] ?? false;

// If we the rule contains a group, get resource from it
if ($group) {
$resources = $this->getGroup($group);

// If the group has not been defined, throw an exception to help debug the problem
if ($resources === false) {
if ($resources === null) {
throw new InvalidArgumentException('Group "' . $group . '" is not defined', 500);
}
}
Expand All @@ -53,32 +54,20 @@ public function hasAccess(string $publicKey, string $resource, string $user = nu
}

public function getUsersForResource(string $publicKey, string $resource): array {
if (!$publicKey || !$resource) {
return [];
}

$accessList = $this->getAccessListForPublicKey($publicKey);
$userLists = array_filter(array_map(fn($acl) => $acl['users'] ?? false, $accessList));
$users = array_merge(...$userLists);

// Get all user lists
$userLists = array_filter(array_map(function($acl) {
return isset($acl['users']) ? $acl['users'] : false;
}, $accessList));

// Merge user lists
$users = call_user_func_array('array_merge', $userLists);

// Check if public key has access to user with same name
if ($this->hasAccess($publicKey, $resource, $publicKey)) {
$userList[] = $publicKey;
}

// Check for each user specified in acls
foreach ($users as $user) {
if ($this->hasAccess($publicKey, $resource, $user)) {
$userList[] = $user;
}
}

return $userList;
return array_values(array_unique($userList));
}
}
13 changes: 3 additions & 10 deletions src/Auth/AccessControl/Adapter/SimpleArrayAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,14 @@ public function __construct(array $accessList = []) {
parent::__construct($this->getExpandedAclList($accessList));
}

/**
* Returns whether the access control list is empty or not
*
* @return boolean True if list is empty, false otherwise
*/
public function isEmpty() {
return empty($this->accessList);
}

/**
* Converts public => private key pairs into the array format accepted by ArrayAdapter
*
* @param array $accessList
* @throws InvalidArgumentException
* @return array
*/
public function getExpandedAclList(array $accessList) {
private function getExpandedAclList(array $accessList): array {
$entries = [];

foreach ($accessList as $publicKey => $privateKey) {
Expand Down
139 changes: 137 additions & 2 deletions tests/Auth/AccessControl/Adapter/ArrayAdapterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ public function testReturnsCorrectListOfAllowedUsersForResource() : void {
'resources' => [Resource::IMAGES_GET],
'users' => ['user2', 'user3', '*'],
]]
],
[
'publicKey' => 'pubKey3',
'privateKey' => 'privateKey3',
'acl' => [[
'resources' => [Resource::IMAGES_GET],
'users' => ['user4', 'pubKey3'],
]]
]
]);

Expand All @@ -42,15 +50,21 @@ public function testReturnsCorrectListOfAllowedUsersForResource() : void {
);

$this->assertEquals(
['user1', 'user2'],
$accessControl->getUsersForResource('pubKey1', Resource::IMAGES_GET)
['user2', 'user3', '*'],
$accessControl->getUsersForResource('pubKey2', Resource::IMAGES_GET)
);

$this->assertEquals(
['pubKey3', 'user4'],
$accessControl->getUsersForResource('pubKey3', Resource::IMAGES_GET)
);
}

/**
* @covers ::__construct
* @covers ::validateAccessList
* @covers ::getPrivateKey
* @covers ::getKeysFromAcl
*/
public function testGetPrivateKey() : void {
$accessControl = new ArrayAdapter([
Expand Down Expand Up @@ -297,4 +311,125 @@ public function testGetAccessRule(array $acl, string $publicKey, int $ruleId, ?a
$adapter = new ArrayAdapter($acl);
$this->assertSame($rule, $adapter->getAccessRule($publicKey, $ruleId));
}

/**
* @testWith [[], "some-group", null]
* [{"foo": {"some": "data"}, "some-group": {"other": "data"}}, "some-group", {"other": "data"}]
* @covers ::getGroup
*/
public function testCanGetGroup(array $groups, string $group, $result): void {
$adapter = new ArrayAdapter([], $groups);
$this->assertSame($result, $adapter->getGroup($group));
}

public function getDataForAccessListTest(): array {
return [
'no acls' => [
'acl' => [],
'publicKey' => 'some-public-key',
'result' => [],
],
'no matching keys' => [
'acl' => [
[
'publicKey' => 'key',
'privateKey' => 'private1',
'acl' => [[
'foo' => 'bar',
]],
],
[
'publicKey' => 'other-key',
'privateKey' => 'private2',
'acl' => [[
'foo' => 'bar',
]],
],

],
'publicKey' => 'some-public-key',
'result' => [],
],
'match' => [
'acl' => [
[
'publicKey' => 'key',
'privateKey' => 'private1',
'acl' => [[
'foo' => 'bar',
]],
],
[
'publicKey' => 'other-key',
'privateKey' => 'private2',
'acl' => [[
'foo' => 'bar',
]],
],

],
'publicKey' => 'other-key',
'result' => [[
'id' => 1,
'foo' => 'bar',
]],
],
];
}

/**
* @dataProvider getDataForAccessListTest
* @covers ::getAccessListForPublicKey
*/
public function testCanGetAccessListForPublicKey(array $acl, string $publicKey, array $result): void {
$adapter = new ArrayAdapter($acl, []);
$this->assertSame($result, $adapter->getAccessListForPublicKey($publicKey));
}

/**
* @covers ::hasAccess
*/
public function testThrowsExceptionWhenMissingUsersFromAcl(): void {
$adapter = new ArrayAdapter([[
'publicKey' => 'public-key',
'privateKey' => 'some-private-key',
'acl' => [
['foo' => 'bar']
],
]]);

$this->expectExceptionObject(new InvalidArgumentException(
'Missing property "users" in access rule',
500,
));

$adapter->hasAccess('public-key', 'resource');
}

/**
* @covers ::hasAccess
*/
public function testThrowsExceptionWhenGroupIsNotDefined(): void {
$acl = [
[
'publicKey' => 'pubkey',
'privateKey' => 'privkey',
'acl' => [
[
'group' => 'user-stats',
'users' => ['user1']
]
]
]
];

$adapter = new ArrayAdapter($acl, []);

$this->expectExceptionObject(new InvalidArgumentException(
'Group "user-stats" is not defined',
500,
));

$this->assertFalse($adapter->hasAccess('pubkey', Resource::IMAGES_GET, 'user1'));
}
}
34 changes: 3 additions & 31 deletions tests/Auth/AccessControl/Adapter/SimpleArrayAdapterTest.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<?php declare(strict_types=1);
namespace Imbo\Auth\AccessControl\Adapter;

use Imbo\Auth\AccessControl\Adapter\ArrayAdapter;
use Imbo\Resource;
use Imbo\Exception\InvalidArgumentException;
use PHPUnit\Framework\TestCase;
Expand All @@ -23,18 +22,9 @@ public function getAuthConfig() : array {
];
}

/**
* @dataProvider getAuthConfig
* @covers ::getPrivateKey
*/
public function testCanSetKeys(array $users, string $publicKey, ?string $privateKey) : void {
$accessControl = new SimpleArrayAdapter($users);

$this->assertSame($privateKey, $accessControl->getPrivateKey($publicKey));
}

/**
* @covers ::__construct
* @covers ::getExpandedAclList
*/
public function testThrowsOnMultiplePrivateKeysPerPublicKey() : void {
$this->expectExceptionObject(new InvalidArgumentException(
Expand All @@ -47,7 +37,8 @@ public function testThrowsOnMultiplePrivateKeysPerPublicKey() : void {
}

/**
* @covers ::hasAccess
* @covers ::__construct
* @covers ::getExpandedAclList
*/
public function testLegacyConfigKeysHaveWriteAccess() : void {
$accessControl = new SimpleArrayAdapter([
Expand All @@ -62,23 +53,4 @@ public function testLegacyConfigKeysHaveWriteAccess() : void {
)
);
}

/**
* @covers ::__construct
*/
public function testExtendsArrayAdapter() : void {
$accessControl = new SimpleArrayAdapter(['publicKey' => 'key']);
$this->assertTrue($accessControl instanceof ArrayAdapter);
}

/**
* @covers ::isEmpty
*/
public function testIsEmpty() : void {
$accessControl = new SimpleArrayAdapter();
$this->assertTrue($accessControl->isEmpty());

$accessControl = new SimpleArrayAdapter(['foo' => 'bar']);
$this->assertFalse($accessControl->isEmpty());
}
}

0 comments on commit df3a486

Please sign in to comment.