1
1
Fork 0
mirror of https://code.mensbeam.com/MensBeam/Arsse.git synced 2024-12-22 21:22:40 +00:00
Arsse/tests/User/TestAuthorization.php
J. King 2c9f6bd5a7 Cover authorization exceptions
Check each of the current User class features and ensure they trigger an exception when they should and do not when they shouldn't.  Tests check against both an internal and external mock driver
2017-02-28 12:37:45 -05:00

334 lines
No EOL
16 KiB
PHP

<?php
declare(strict_types=1);
namespace JKingWeb\NewsSync;
class TestAuthorization extends \PHPUnit\Framework\TestCase {
use Test\Tools;
const USERS = [
'user@example.com' => User\Driver::RIGHTS_NONE,
'user@example.org' => User\Driver::RIGHTS_NONE,
'dman@example.com' => User\Driver::RIGHTS_DOMAIN_MANAGER,
'dman@example.org' => User\Driver::RIGHTS_DOMAIN_MANAGER,
'dadm@example.com' => User\Driver::RIGHTS_DOMAIN_ADMIN,
'dadm@example.org' => User\Driver::RIGHTS_DOMAIN_ADMIN,
'gman@example.com' => User\Driver::RIGHTS_GLOBAL_MANAGER,
'gman@example.org' => User\Driver::RIGHTS_GLOBAL_MANAGER,
'gadm@example.com' => User\Driver::RIGHTS_GLOBAL_ADMIN,
'gadm@example.org' => User\Driver::RIGHTS_GLOBAL_ADMIN,
// invalid rights levels
'bad1@example.com' => User\Driver::RIGHTS_NONE+1,
'bad1@example.org' => User\Driver::RIGHTS_NONE+1,
'bad2@example.com' => User\Driver::RIGHTS_DOMAIN_MANAGER+1,
'bad2@example.org' => User\Driver::RIGHTS_DOMAIN_MANAGER+1,
'bad3@example.com' => User\Driver::RIGHTS_DOMAIN_ADMIN+1,
'bad3@example.org' => User\Driver::RIGHTS_DOMAIN_ADMIN+1,
'bad4@example.com' => User\Driver::RIGHTS_GLOBAL_MANAGER+1,
'bad4@example.org' => User\Driver::RIGHTS_GLOBAL_MANAGER+1,
'bad5@example.com' => User\Driver::RIGHTS_GLOBAL_ADMIN+1,
'bad5@example.org' => User\Driver::RIGHTS_GLOBAL_ADMIN+1,
];
const LEVELS = [
User\Driver::RIGHTS_NONE,
User\Driver::RIGHTS_DOMAIN_MANAGER,
User\Driver::RIGHTS_DOMAIN_ADMIN,
User\Driver::RIGHTS_GLOBAL_MANAGER,
User\Driver::RIGHTS_GLOBAL_ADMIN,
];
const DOMAINS = [
'@example.com',
'@example.org',
"",
];
protected $data;
function setUp(string $drv = Test\User\DriverInternalMock::class, string $db = null) {
$conf = new Conf();
$conf->userDriver = $drv;
$conf->userAuthPreferHTTP = true;
$conf->userComposeNames = true;
$this->data = new Test\RuntimeData($conf);
if($db !== null) {
$this->data->db = new $db($this->data);
}
$this->data->user = new User($this->data);
$this->data->user->authorizationEnabled(false);
foreach(self::USERS as $user => $level) {
$this->data->user->add($user, "");
$this->data->user->rightsSet($user, $level);
}
$this->data->user->authorizationEnabled(true);
}
function testSelfActionLogic() {
foreach(array_keys(self::USERS) as $user) {
$this->data->user->auth($user, "");
// users should be able to do basic actions for themselves
$this->assertTrue($this->data->user->authorize($user, "userExists"), "User $user could not act for themselves.");
$this->assertTrue($this->data->user->authorize($user, "userRemove"), "User $user could not act for themselves.");
}
}
function testRegularUserLogic() {
foreach(self::USERS as $actor => $rights) {
if($rights != User\Driver::RIGHTS_NONE) continue;
$this->data->user->auth($actor, "");
foreach(array_keys(self::USERS) as $affected) {
// regular users should only be able to act for themselves
if($actor==$affected) {
$this->assertTrue($this->data->user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied.");
$this->assertTrue($this->data->user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied.");
} else {
$this->assertFalse($this->data->user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed.");
$this->assertFalse($this->data->user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed.");
}
// they should never be able to set rights
foreach(self::LEVELS as $level) {
$this->assertFalse($this->data->user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed.");
}
}
// they should not be able to list users
foreach(self::DOMAINS as $domain) {
$this->assertFalse($this->data->user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed.");
}
}
}
function testDomainManagerLogic() {
foreach(self::USERS as $actor => $actorRights) {
if($actorRights != User\Driver::RIGHTS_DOMAIN_MANAGER) continue;
$actorDomain = substr($actor,strrpos($actor,"@")+1);
$this->data->user->auth($actor, "");
foreach(self::USERS as $affected => $affectedRights) {
$affectedDomain = substr($affected,strrpos($affected,"@")+1);
// domain managers should be able to check any user on the same domain
if($actorDomain==$affectedDomain) {
$this->assertTrue($this->data->user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied.");
} else {
$this->assertFalse($this->data->user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed.");
}
// they should only be able to act for regular users on the same domain
if($actor==$affected || ($actorDomain==$affectedDomain && $affectedRights==User\Driver::RIGHTS_NONE)) {
$this->assertTrue($this->data->user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied.");
} else {
$this->assertFalse($this->data->user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed.");
}
// and they should only be able to set their own rights to regular user
foreach(self::LEVELS as $level) {
if($actor==$affected && in_array($level, [User\Driver::RIGHTS_NONE, User\Driver::RIGHTS_DOMAIN_MANAGER])) {
$this->assertTrue($this->data->user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied.");
} else {
$this->assertFalse($this->data->user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed.");
}
}
}
// they should also be able to list all users on their own domain
foreach(self::DOMAINS as $domain) {
if($domain=="@".$actorDomain) {
$this->assertTrue($this->data->user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied.");
} else {
$this->assertFalse($this->data->user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed.");
}
}
}
}
function testDomainAdministratorLogic() {
foreach(self::USERS as $actor => $actorRights) {
if($actorRights != User\Driver::RIGHTS_DOMAIN_ADMIN) continue;
$actorDomain = substr($actor,strrpos($actor,"@")+1);
$this->data->user->auth($actor, "");
$allowed = [User\Driver::RIGHTS_NONE,User\Driver::RIGHTS_DOMAIN_MANAGER,User\Driver::RIGHTS_DOMAIN_ADMIN];
foreach(self::USERS as $affected => $affectedRights) {
$affectedDomain = substr($affected,strrpos($affected,"@")+1);
// domain admins should be able to check any user on the same domain
if($actorDomain==$affectedDomain) {
$this->assertTrue($this->data->user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied.");
} else {
$this->assertFalse($this->data->user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed.");
}
// they should be able to act for any user on the same domain who is not a global manager or admin
if($actorDomain==$affectedDomain && in_array($affectedRights, $allowed)) {
$this->assertTrue($this->data->user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied.");
} else {
$this->assertFalse($this->data->user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed.");
}
// they should be able to set rights for any user on their domain who is not a global manager or admin, up to domain admin level
foreach(self::LEVELS as $level) {
if($actorDomain==$affectedDomain && in_array($affectedRights, $allowed) && in_array($level, $allowed)) {
$this->assertTrue($this->data->user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied.");
} else {
$this->assertFalse($this->data->user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed.");
}
}
}
// they should also be able to list all users on their own domain
foreach(self::DOMAINS as $domain) {
if($domain=="@".$actorDomain) {
$this->assertTrue($this->data->user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied.");
} else {
$this->assertFalse($this->data->user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed.");
}
}
}
}
function testGlobalManagerLogic() {
foreach(self::USERS as $actor => $actorRights) {
if($actorRights != User\Driver::RIGHTS_GLOBAL_MANAGER) continue;
$actorDomain = substr($actor,strrpos($actor,"@")+1);
$this->data->user->auth($actor, "");
foreach(self::USERS as $affected => $affectedRights) {
$affectedDomain = substr($affected,strrpos($affected,"@")+1);
// global managers should be able to check any user
$this->assertTrue($this->data->user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied.");
// they should only be able to act for regular users
if($actor==$affected || $affectedRights==User\Driver::RIGHTS_NONE) {
$this->assertTrue($this->data->user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied.");
} else {
$this->assertFalse($this->data->user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed.");
}
// and they should only be able to set their own rights to regular user
foreach(self::LEVELS as $level) {
if($actor==$affected && in_array($level, [User\Driver::RIGHTS_NONE, User\Driver::RIGHTS_GLOBAL_MANAGER])) {
$this->assertTrue($this->data->user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied.");
} else {
$this->assertFalse($this->data->user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed.");
}
}
}
// they should also be able to list all users
foreach(self::DOMAINS as $domain) {
$this->assertTrue($this->data->user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied.");
}
}
}
function testGlobalAdministratorLogic() {
foreach(self::USERS as $actor => $actorRights) {
if($actorRights != User\Driver::RIGHTS_GLOBAL_ADMIN) continue;
$this->data->user->auth($actor, "");
// global admins can do anything
foreach(self::USERS as $affected => $affectedRights) {
$this->assertTrue($this->data->user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied.");
$this->assertTrue($this->data->user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied.");
foreach(self::LEVELS as $level) {
$this->assertTrue($this->data->user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied.");
}
}
foreach(self::DOMAINS as $domain) {
$this->assertTrue($this->data->user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied.");
}
}
}
function testInvalidLevelLogic() {
foreach(self::USERS as $actor => $rights) {
if(in_array($rights, self::LEVELS)) continue;
$this->data->user->auth($actor, "");
foreach(array_keys(self::USERS) as $affected) {
// users with unknown/invalid rights should be treated just like regular users and only be able to act for themselves
if($actor==$affected) {
$this->assertTrue($this->data->user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied.");
$this->assertTrue($this->data->user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied.");
} else {
$this->assertFalse($this->data->user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed.");
$this->assertFalse($this->data->user->authorize($affected, "userRemove"), "User $actor acted improperly for $affected, but the action was allowed.");
}
// they should never be able to set rights
foreach(self::LEVELS as $level) {
$this->assertFalse($this->data->user->authorize($affected, "userRightsSet", $level), "User $actor acted improperly for $affected settings rights level $level, but the action was allowed.");
}
}
// they should not be able to list users
foreach(self::DOMAINS as $domain) {
$this->assertFalse($this->data->user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed.");
}
}
}
function testInternalExceptionLogic() {
$failTest = [
'userExists',
'userRemove',
'userAdd',
'userPasswordSet',
'userPropertiesGet',
'userPropertiesSet',
'userRightsGet',
'userRightsSet',
'userList',
];
$passTest = [
'userRightsSet',
'userList'
];
sort($failTest);
sort($passTest);
$actor = "user@example.com";
$this->data->user->auth($actor, "");
$this->assertEquals($passTest, $this->checkExceptions($actor));
$this->assertEquals($failTest, $this->checkExceptions("user@example.org"));
}
function testExternalExceptionLogic() {
// set up the test for an external driver
$this->setUp(Test\User\DriverExternalMock::class, Test\User\Database::class);
// run the previous test with the external driver set up
$this->testInternalExceptionLogic();
}
protected function checkExceptions(string $user): array {
$err = [];
try {
$this->data->user->exists($user);
} catch(User\ExceptionAuthz $e) {
$err[] = "userExists";
}
try {
$this->data->user->remove($user);
} catch(User\ExceptionAuthz $e) {
$err[] = "userRemove";
}
try {
$this->data->user->add($user, "");
} catch(User\ExceptionAuthz $e) {
$err[] = "userAdd";
}
try {
$this->data->user->passwordSet($user, "");
} catch(User\ExceptionAuthz $e) {
$err[] = "userPasswordSet";
}
try {
$this->data->user->propertiesGet($user);
} catch(User\ExceptionAuthz $e) {
$err[] = "userPropertiesGet";
}
try {
$this->data->user->propertiesSet($user, []);
} catch(User\ExceptionAuthz $e) {
$err[] = "userPropertiesSet";
}
try {
$this->data->user->rightsGet($user);
} catch(User\ExceptionAuthz $e) {
$err[] = "userRightsGet";
}
try {
$this->data->user->rightsSet($user, 10000);
} catch(User\ExceptionAuthz $e) {
$err[] = "userRightsSet";
}
try {
$this->data->user->list();
} catch(User\ExceptionAuthz $e) {
$err[] = "userList";
}
sort($err);
return $err;
}
}