J. King
6 years ago
29 changed files with 608 additions and 1764 deletions
@ -1,65 +0,0 @@ |
|||||
<?php |
|
||||
/** @license MIT |
|
||||
* Copyright 2017 J. King, Dustin Wilson et al. |
|
||||
* See LICENSE and AUTHORS files for details */ |
|
||||
|
|
||||
declare(strict_types=1); |
|
||||
namespace JKingWeb\Arsse\User\Internal; |
|
||||
|
|
||||
use JKingWeb\Arsse\Arsse; |
|
||||
use JKingWeb\Arsse\User\Exception; |
|
||||
|
|
||||
trait InternalFunctions { |
|
||||
protected $actor = []; |
|
||||
|
|
||||
public function __construct() { |
|
||||
} |
|
||||
|
|
||||
public function auth(string $user, string $password): bool { |
|
||||
try { |
|
||||
$hash = Arsse::$db->userPasswordGet($user); |
|
||||
} catch (Exception $e) { |
|
||||
return false; |
|
||||
} |
|
||||
if ($password==="" && $hash==="") { |
|
||||
return true; |
|
||||
} |
|
||||
return password_verify($password, $hash); |
|
||||
} |
|
||||
|
|
||||
public function userExists(string $user): bool { |
|
||||
return Arsse::$db->userExists($user); |
|
||||
} |
|
||||
|
|
||||
public function userAdd(string $user, string $password = null): string { |
|
||||
return Arsse::$db->userAdd($user, $password); |
|
||||
} |
|
||||
|
|
||||
public function userRemove(string $user): bool { |
|
||||
return Arsse::$db->userRemove($user); |
|
||||
} |
|
||||
|
|
||||
public function userList(string $domain = null): array { |
|
||||
return Arsse::$db->userList($domain); |
|
||||
} |
|
||||
|
|
||||
public function userPasswordSet(string $user, string $newPassword = null, string $oldPassword = null): string { |
|
||||
return Arsse::$db->userPasswordSet($user, $newPassword); |
|
||||
} |
|
||||
|
|
||||
public function userPropertiesGet(string $user): array { |
|
||||
return Arsse::$db->userPropertiesGet($user); |
|
||||
} |
|
||||
|
|
||||
public function userPropertiesSet(string $user, array $properties): array { |
|
||||
return Arsse::$db->userPropertiesSet($user, $properties); |
|
||||
} |
|
||||
|
|
||||
public function userRightsGet(string $user): int { |
|
||||
return Arsse::$db->userRightsGet($user); |
|
||||
} |
|
||||
|
|
||||
public function userRightsSet(string $user, int $level): bool { |
|
||||
return Arsse::$db->userRightsSet($user, $level); |
|
||||
} |
|
||||
} |
|
@ -1,338 +0,0 @@ |
|||||
<?php |
|
||||
/** @license MIT |
|
||||
* Copyright 2017 J. King, Dustin Wilson et al. |
|
||||
* See LICENSE and AUTHORS files for details */ |
|
||||
|
|
||||
declare(strict_types=1); |
|
||||
namespace JKingWeb\Arsse\TestCase\User; |
|
||||
|
|
||||
use JKingWeb\Arsse\Arsse; |
|
||||
use JKingWeb\Arsse\Conf; |
|
||||
use JKingWeb\Arsse\User; |
|
||||
use JKingWeb\Arsse\User\Driver; |
|
||||
use Phake; |
|
||||
|
|
||||
/** @covers \JKingWeb\Arsse\User */ |
|
||||
class TestAuthorization extends \JKingWeb\Arsse\Test\AbstractTest { |
|
||||
const USERS = [ |
|
||||
'user@example.com' => Driver::RIGHTS_NONE, |
|
||||
'user@example.org' => Driver::RIGHTS_NONE, |
|
||||
'dman@example.com' => Driver::RIGHTS_DOMAIN_MANAGER, |
|
||||
'dman@example.org' => Driver::RIGHTS_DOMAIN_MANAGER, |
|
||||
'dadm@example.com' => Driver::RIGHTS_DOMAIN_ADMIN, |
|
||||
'dadm@example.org' => Driver::RIGHTS_DOMAIN_ADMIN, |
|
||||
'gman@example.com' => Driver::RIGHTS_GLOBAL_MANAGER, |
|
||||
'gman@example.org' => Driver::RIGHTS_GLOBAL_MANAGER, |
|
||||
'gadm@example.com' => Driver::RIGHTS_GLOBAL_ADMIN, |
|
||||
'gadm@example.org' => Driver::RIGHTS_GLOBAL_ADMIN, |
|
||||
// invalid rights levels |
|
||||
'bad1@example.com' => Driver::RIGHTS_NONE+1, |
|
||||
'bad1@example.org' => Driver::RIGHTS_NONE+1, |
|
||||
'bad2@example.com' => Driver::RIGHTS_DOMAIN_MANAGER+1, |
|
||||
'bad2@example.org' => Driver::RIGHTS_DOMAIN_MANAGER+1, |
|
||||
'bad3@example.com' => Driver::RIGHTS_DOMAIN_ADMIN+1, |
|
||||
'bad3@example.org' => Driver::RIGHTS_DOMAIN_ADMIN+1, |
|
||||
'bad4@example.com' => Driver::RIGHTS_GLOBAL_MANAGER+1, |
|
||||
'bad4@example.org' => Driver::RIGHTS_GLOBAL_MANAGER+1, |
|
||||
'bad5@example.com' => Driver::RIGHTS_GLOBAL_ADMIN+1, |
|
||||
'bad5@example.org' => Driver::RIGHTS_GLOBAL_ADMIN+1, |
|
||||
|
|
||||
]; |
|
||||
const LEVELS = [ |
|
||||
Driver::RIGHTS_NONE, |
|
||||
Driver::RIGHTS_DOMAIN_MANAGER, |
|
||||
Driver::RIGHTS_DOMAIN_ADMIN, |
|
||||
Driver::RIGHTS_GLOBAL_MANAGER, |
|
||||
Driver::RIGHTS_GLOBAL_ADMIN, |
|
||||
]; |
|
||||
const DOMAINS = [ |
|
||||
'@example.com', |
|
||||
'@example.org', |
|
||||
"", |
|
||||
]; |
|
||||
|
|
||||
protected $data; |
|
||||
|
|
||||
public function setUp(string $drv = \JkingWeb\Arsse\Test\User\DriverInternalMock::class, string $db = null) { |
|
||||
$this->clearData(); |
|
||||
$conf = new Conf(); |
|
||||
$conf->userDriver = $drv; |
|
||||
$conf->userPreAuth = false; |
|
||||
Arsse::$conf = $conf; |
|
||||
if ($db !== null) { |
|
||||
Arsse::$db = new $db(); |
|
||||
} |
|
||||
Arsse::$user = Phake::partialMock(User::class); |
|
||||
Phake::when(Arsse::$user)->authorize->thenReturn(true); |
|
||||
foreach (self::USERS as $user => $level) { |
|
||||
Arsse::$user->add($user, ""); |
|
||||
Arsse::$user->rightsSet($user, $level); |
|
||||
} |
|
||||
Phake::reset(Arsse::$user); |
|
||||
} |
|
||||
|
|
||||
public function tearDown() { |
|
||||
$this->clearData(); |
|
||||
} |
|
||||
|
|
||||
public function testToggleLogic() { |
|
||||
$this->assertTrue(Arsse::$user->authorizationEnabled()); |
|
||||
$this->assertTrue(Arsse::$user->authorizationEnabled(true)); |
|
||||
$this->assertFalse(Arsse::$user->authorizationEnabled(false)); |
|
||||
$this->assertFalse(Arsse::$user->authorizationEnabled(false)); |
|
||||
$this->assertFalse(Arsse::$user->authorizationEnabled(true)); |
|
||||
$this->assertTrue(Arsse::$user->authorizationEnabled(true)); |
|
||||
} |
|
||||
|
|
||||
public function testSelfActionLogic() { |
|
||||
foreach (array_keys(self::USERS) as $user) { |
|
||||
Arsse::$user->auth($user, ""); |
|
||||
// users should be able to do basic actions for themselves |
|
||||
$this->assertTrue(Arsse::$user->authorize($user, "userExists"), "User $user could not act for themselves."); |
|
||||
$this->assertTrue(Arsse::$user->authorize($user, "userRemove"), "User $user could not act for themselves."); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public function testRegularUserLogic() { |
|
||||
foreach (self::USERS as $actor => $rights) { |
|
||||
if ($rights != Driver::RIGHTS_NONE) { |
|
||||
continue; |
|
||||
} |
|
||||
Arsse::$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(Arsse::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied."); |
|
||||
$this->assertTrue(Arsse::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied."); |
|
||||
} else { |
|
||||
$this->assertFalse(Arsse::$user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed."); |
|
||||
$this->assertFalse(Arsse::$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(Arsse::$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(Arsse::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed."); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public function testDomainManagerLogic() { |
|
||||
foreach (self::USERS as $actor => $actorRights) { |
|
||||
if ($actorRights != Driver::RIGHTS_DOMAIN_MANAGER) { |
|
||||
continue; |
|
||||
} |
|
||||
$actorDomain = substr($actor, strrpos($actor, "@")+1); |
|
||||
Arsse::$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(Arsse::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied."); |
|
||||
} else { |
|
||||
$this->assertFalse(Arsse::$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(Arsse::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied."); |
|
||||
} else { |
|
||||
$this->assertFalse(Arsse::$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, Driver::RIGHTS_DOMAIN_MANAGER])) { |
|
||||
$this->assertTrue(Arsse::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied."); |
|
||||
} else { |
|
||||
$this->assertFalse(Arsse::$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(Arsse::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied."); |
|
||||
} else { |
|
||||
$this->assertFalse(Arsse::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed."); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public function testDomainAdministratorLogic() { |
|
||||
foreach (self::USERS as $actor => $actorRights) { |
|
||||
if ($actorRights != Driver::RIGHTS_DOMAIN_ADMIN) { |
|
||||
continue; |
|
||||
} |
|
||||
$actorDomain = substr($actor, strrpos($actor, "@")+1); |
|
||||
Arsse::$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(Arsse::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied."); |
|
||||
} else { |
|
||||
$this->assertFalse(Arsse::$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(Arsse::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied."); |
|
||||
} else { |
|
||||
$this->assertFalse(Arsse::$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(Arsse::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied."); |
|
||||
} else { |
|
||||
$this->assertFalse(Arsse::$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(Arsse::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied."); |
|
||||
} else { |
|
||||
$this->assertFalse(Arsse::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed."); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public function testGlobalManagerLogic() { |
|
||||
foreach (self::USERS as $actor => $actorRights) { |
|
||||
if ($actorRights != Driver::RIGHTS_GLOBAL_MANAGER) { |
|
||||
continue; |
|
||||
} |
|
||||
$actorDomain = substr($actor, strrpos($actor, "@")+1); |
|
||||
Arsse::$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(Arsse::$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(Arsse::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied."); |
|
||||
} else { |
|
||||
$this->assertFalse(Arsse::$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, Driver::RIGHTS_GLOBAL_MANAGER])) { |
|
||||
$this->assertTrue(Arsse::$user->authorize($affected, "userRightsSet", $level), "User $actor acted properly for $affected settings rights level $level, but the action was denied."); |
|
||||
} else { |
|
||||
$this->assertFalse(Arsse::$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(Arsse::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied."); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public function testGlobalAdministratorLogic() { |
|
||||
foreach (self::USERS as $actor => $actorRights) { |
|
||||
if ($actorRights != Driver::RIGHTS_GLOBAL_ADMIN) { |
|
||||
continue; |
|
||||
} |
|
||||
Arsse::$user->auth($actor, ""); |
|
||||
// global admins can do anything |
|
||||
foreach (self::USERS as $affected => $affectedRights) { |
|
||||
$this->assertTrue(Arsse::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied."); |
|
||||
$this->assertTrue(Arsse::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied."); |
|
||||
foreach (self::LEVELS as $level) { |
|
||||
$this->assertTrue(Arsse::$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(Arsse::$user->authorize($domain, "userList"), "User $actor properly checked user list for domain '$domain', but the action was denied."); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public function testInvalidLevelLogic() { |
|
||||
foreach (self::USERS as $actor => $rights) { |
|
||||
if (in_array($rights, self::LEVELS)) { |
|
||||
continue; |
|
||||
} |
|
||||
Arsse::$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(Arsse::$user->authorize($affected, "userExists"), "User $actor acted properly for $affected, but the action was denied."); |
|
||||
$this->assertTrue(Arsse::$user->authorize($affected, "userRemove"), "User $actor acted properly for $affected, but the action was denied."); |
|
||||
} else { |
|
||||
$this->assertFalse(Arsse::$user->authorize($affected, "userExists"), "User $actor acted improperly for $affected, but the action was allowed."); |
|
||||
$this->assertFalse(Arsse::$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(Arsse::$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(Arsse::$user->authorize($domain, "userList"), "User $actor improperly checked user list for domain '$domain', but the action was allowed."); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public function testInternalExceptionLogic() { |
|
||||
$tests = [ |
|
||||
// methods of User class to test, with parameters besides affected user |
|
||||
'exists' => [], |
|
||||
'remove' => [], |
|
||||
'add' => [''], |
|
||||
'passwordSet' => [''], |
|
||||
'propertiesGet' => [], |
|
||||
'propertiesSet' => [[]], |
|
||||
'rightsGet' => [], |
|
||||
'rightsSet' => [User\Driver::RIGHTS_GLOBAL_ADMIN], |
|
||||
'list' => [], |
|
||||
]; |
|
||||
// try first with a global admin (there should be no exception) |
|
||||
Arsse::$user->auth("gadm@example.com", ""); |
|
||||
$this->assertCount(0, $this->checkExceptions("user@example.org", $tests)); |
|
||||
// next try with a regular user acting on another user (everything should fail) |
|
||||
Arsse::$user->auth("user@example.com", ""); |
|
||||
$this->assertCount(sizeof($tests), $this->checkExceptions("user@example.org", $tests)); |
|
||||
} |
|
||||
|
|
||||
public function testExternalExceptionLogic() { |
|
||||
// set up the test for an external driver |
|
||||
$this->setUp(\JKingWeb\Arsse\Test\User\DriverExternalMock::class, \JKingWeb\Arsse\Test\User\Database::class); |
|
||||
// run the previous test with the external driver set up |
|
||||
$this->testInternalExceptionLogic(); |
|
||||
} |
|
||||
|
|
||||
// meat of testInternalExceptionLogic and testExternalExceptionLogic |
|
||||
// calls each requested function with supplied arguments, catches authorization exceptions, and returns an array of caught failed calls |
|
||||
protected function checkExceptions(string $user, $tests): array { |
|
||||
$err = []; |
|
||||
foreach ($tests as $func => $args) { |
|
||||
// list method does not take an affected user, so do not unshift for that one |
|
||||
if ($func != "list") { |
|
||||
array_unshift($args, $user); |
|
||||
} |
|
||||
try { |
|
||||
call_user_func_array(array(Arsse::$user, $func), $args); |
|
||||
} catch (\JKingWeb\Arsse\User\ExceptionAuthz $e) { |
|
||||
$err[] = $func; |
|
||||
} |
|
||||
} |
|
||||
return $err; |
|
||||
} |
|
||||
|
|
||||
public function testMissingUserLogic() { |
|
||||
Arsse::$user->auth("gadm@example.com", ""); |
|
||||
$this->assertTrue(Arsse::$user->authorize("user@example.com", "someFunction")); |
|
||||
$this->assertException("doesNotExist", "User"); |
|
||||
Arsse::$user->authorize("this_user_does_not_exist@example.org", "someFunction"); |
|
||||
} |
|
||||
} |
|
@ -0,0 +1,137 @@ |
|||||
|
<?php |
||||
|
/** @license MIT |
||||
|
* Copyright 2017 J. King, Dustin Wilson et al. |
||||
|
* See LICENSE and AUTHORS files for details */ |
||||
|
|
||||
|
declare(strict_types=1); |
||||
|
namespace JKingWeb\Arsse\TestCase\User; |
||||
|
|
||||
|
use JKingWeb\Arsse\Arsse; |
||||
|
use JKingWeb\Arsse\Conf; |
||||
|
use JKingWeb\Arsse\Database; |
||||
|
use JKingWeb\Arsse\User; |
||||
|
use JKingWeb\Arsse\AbstractException as Exception; |
||||
|
use JKingWeb\Arsse\User\Driver as DriverInterface; |
||||
|
use JKingWeb\Arsse\User\Internal\Driver; |
||||
|
use Phake; |
||||
|
|
||||
|
/** @covers \JKingWeb\Arsse\User\Internal\Driver */ |
||||
|
class TestInternal extends \JKingWeb\Arsse\Test\AbstractTest { |
||||
|
|
||||
|
public function setUp() { |
||||
|
$this->clearData(); |
||||
|
$this->setConf(); |
||||
|
// create a mock database interface |
||||
|
Arsse::$db = Phake::mock(Database::class); |
||||
|
Phake::when(Arsse::$db)->begin->thenReturn(Phake::mock(\JKingWeb\Arsse\Db\Transaction::class)); |
||||
|
} |
||||
|
|
||||
|
public function testConstruct() { |
||||
|
$this->assertInstanceOf(DriverInterface::class, new Driver); |
||||
|
} |
||||
|
|
||||
|
public function testFetchDriverName() { |
||||
|
$this->assertTrue(strlen(Driver::driverName()) > 0); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @dataProvider provideAuthentication |
||||
|
* @group slow |
||||
|
*/ |
||||
|
public function testAuthenticateAUser(bool $authorized, string $user, string $password, bool $exp) { |
||||
|
if ($authorized) { |
||||
|
Phake::when(Arsse::$db)->userPasswordGet("john.doe@example.com")->thenReturn('$2y$10$1zbqRJhxM8uUjeSBPp4IhO90xrqK0XjEh9Z16iIYEFRV4U.zeAFom'); // hash of "secret" |
||||
|
Phake::when(Arsse::$db)->userPasswordGet("jane.doe@example.com")->thenReturn('$2y$10$bK1ljXfTSyc2D.NYvT.Eq..OpehLRXVbglW.23ihVuyhgwJCd.7Im'); // hash of "superman" |
||||
|
Phake::when(Arsse::$db)->userPasswordGet("owen.hardy@example.com")->thenReturn(""); |
||||
|
Phake::when(Arsse::$db)->userPasswordGet("kira.nerys@example.com")->thenThrow(new \JKingWeb\Arsse\User\Exception("doesNotExist")); |
||||
|
} else { |
||||
|
Phake::when(Arsse::$db)->userPasswordGet->thenThrow(new \JKingWeb\Arsse\User\ExceptionAuthz("notAuthorized")); |
||||
|
} |
||||
|
$this->assertSame($exp, (new Driver)->auth($user, $password)); |
||||
|
} |
||||
|
|
||||
|
public function provideAuthentication() { |
||||
|
$john = "john.doe@example.com"; |
||||
|
$jane = "jane.doe@example.com"; |
||||
|
$owen = "owen.hardy@example.com"; |
||||
|
$kira = "kira.nerys@example.com"; |
||||
|
return [ |
||||
|
[false, $john, "secret", false], |
||||
|
[false, $jane, "superman", false], |
||||
|
[false, $owen, "", false], |
||||
|
[false, $kira, "ashalla", false], |
||||
|
[true, $john, "secret", true], |
||||
|
[true, $jane, "superman", true], |
||||
|
[true, $owen, "", true], |
||||
|
[true, $kira, "ashalla", false], |
||||
|
[true, $john, "top secret", false], |
||||
|
[true, $jane, "clark kent", false], |
||||
|
[true, $owen, "watchmaker", false], |
||||
|
[true, $kira, "singha", false], |
||||
|
[true, $john, "", false], |
||||
|
[true, $jane, "", false], |
||||
|
[true, $kira, "", false], |
||||
|
]; |
||||
|
} |
||||
|
|
||||
|
public function testAuthorizeAnAction() { |
||||
|
Phake::verifyNoFurtherInteraction(Arsse::$db); |
||||
|
$this->assertTrue((new Driver)->authorize("someone", "something")); |
||||
|
} |
||||
|
|
||||
|
public function testListUsers() { |
||||
|
$john = "john.doe@example.com"; |
||||
|
$jane = "jane.doe@example.com"; |
||||
|
Phake::when(Arsse::$db)->userList->thenReturn([$john, $jane])->thenReturn([$jane, $john]); |
||||
|
$driver = new Driver; |
||||
|
$this->assertSame([$john, $jane], $driver->userList()); |
||||
|
$this->assertSame([$jane, $john], $driver->userList()); |
||||
|
Phake::verify(Arsse::$db, Phake::times(2))->userList; |
||||
|
} |
||||
|
|
||||
|
public function testCheckThatAUserExists() { |
||||
|
$john = "john.doe@example.com"; |
||||
|
$jane = "jane.doe@example.com"; |
||||
|
Phake::when(Arsse::$db)->userExists($john)->thenReturn(true); |
||||
|
Phake::when(Arsse::$db)->userExists($jane)->thenReturn(false); |
||||
|
$driver = new Driver; |
||||
|
$this->assertTrue($driver->userExists($john)); |
||||
|
Phake::verify(Arsse::$db)->userExists($john); |
||||
|
$this->assertFalse($driver->userExists($jane)); |
||||
|
Phake::verify(Arsse::$db)->userExists($jane); |
||||
|
} |
||||
|
|
||||
|
public function testAddAUser() { |
||||
|
$john = "john.doe@example.com"; |
||||
|
Phake::when(Arsse::$db)->userAdd->thenReturnCallback(function($user, $pass) { |
||||
|
return $pass; |
||||
|
}); |
||||
|
$driver = new Driver; |
||||
|
$this->assertNull($driver->userAdd($john)); |
||||
|
$this->assertNull($driver->userAdd($john, null)); |
||||
|
$this->assertSame("secret", $driver->userAdd($john, "secret")); |
||||
|
Phake::verify(Arsse::$db)->userAdd($john, "secret"); |
||||
|
Phake::verify(Arsse::$db)->userAdd; |
||||
|
} |
||||
|
|
||||
|
public function testRemoveAUser() { |
||||
|
$john = "john.doe@example.com"; |
||||
|
Phake::when(Arsse::$db)->userRemove->thenReturn(true)->thenThrow(new \JKingWeb\Arsse\User\Exception("doesNotExist")); |
||||
|
$driver = new Driver; |
||||
|
$this->assertTrue($driver->userRemove($john)); |
||||
|
Phake::verify(Arsse::$db, Phake::times(1))->userRemove($john); |
||||
|
$this->assertException("doesNotExist", "User"); |
||||
|
try { |
||||
|
$this->assertFalse($driver->userRemove($john)); |
||||
|
} finally { |
||||
|
Phake::verify(Arsse::$db, Phake::times(2))->userRemove($john); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public function testSetAPassword() { |
||||
|
$john = "john.doe@example.com"; |
||||
|
Phake::verifyNoFurtherInteraction(Arsse::$db); |
||||
|
$this->assertSame("superman", (new Driver)->userPasswordSet($john, "superman")); |
||||
|
$this->assertSame(null, (new Driver)->userPasswordSet($john, null)); |
||||
|
} |
||||
|
} |
@ -1,17 +0,0 @@ |
|||||
<?php |
|
||||
/** @license MIT |
|
||||
* Copyright 2017 J. King, Dustin Wilson et al. |
|
||||
* See LICENSE and AUTHORS files for details */ |
|
||||
|
|
||||
declare(strict_types=1); |
|
||||
namespace JKingWeb\Arsse\TestCase\User; |
|
||||
|
|
||||
/** @covers \JKingWeb\Arsse\User */ |
|
||||
class TestMockExternal extends \JKingWeb\Arsse\Test\AbstractTest { |
|
||||
use \JKingWeb\Arsse\Test\User\CommonTests; |
|
||||
|
|
||||
const USER1 = "john.doe@example.com"; |
|
||||
const USER2 = "jane.doe@example.com"; |
|
||||
|
|
||||
public $drv = \JKingWeb\Arsse\Test\User\DriverExternalMock::class; |
|
||||
} |
|
@ -1,23 +0,0 @@ |
|||||
<?php |
|
||||
/** @license MIT |
|
||||
* Copyright 2017 J. King, Dustin Wilson et al. |
|
||||
* See LICENSE and AUTHORS files for details */ |
|
||||
|
|
||||
declare(strict_types=1); |
|
||||
namespace JKingWeb\Arsse\TestCase\User; |
|
||||
|
|
||||
use JKingWeb\Arsse\Arsse; |
|
||||
|
|
||||
/** @covers \JKingWeb\Arsse\User */ |
|
||||
class TestMockInternal extends \JKingWeb\Arsse\Test\AbstractTest { |
|
||||
use \JKingWeb\Arsse\Test\User\CommonTests; |
|
||||
|
|
||||
const USER1 = "john.doe@example.com"; |
|
||||
const USER2 = "jane.doe@example.com"; |
|
||||
|
|
||||
public $drv = \JKingWeb\Arsse\Test\User\DriverInternalMock::class; |
|
||||
|
|
||||
public function setUpSeries() { |
|
||||
Arsse::$db = null; |
|
||||
} |
|
||||
} |
|
@ -0,0 +1,301 @@ |
|||||
|
<?php |
||||
|
/** @license MIT |
||||
|
* Copyright 2017 J. King, Dustin Wilson et al. |
||||
|
* See LICENSE and AUTHORS files for details */ |
||||
|
|
||||
|
declare(strict_types=1); |
||||
|
namespace JKingWeb\Arsse\TestCase\User; |
||||
|
|
||||
|
use JKingWeb\Arsse\Arsse; |
||||
|
use JKingWeb\Arsse\Conf; |
||||
|
use JKingWeb\Arsse\Database; |
||||
|
use JKingWeb\Arsse\User; |
||||
|
use JKingWeb\Arsse\AbstractException as Exception; |
||||
|
use JKingWeb\Arsse\User\Driver; |
||||
|
use JKingWeb\Arsse\User\Internal\Driver as InternalDriver; |
||||
|
use Phake; |
||||
|
|
||||
|
/** @covers \JKingWeb\Arsse\User */ |
||||
|
class TestUser extends \JKingWeb\Arsse\Test\AbstractTest { |
||||
|
|
||||
|
public function setUp() { |
||||
|
$this->clearData(); |
||||
|
$this->setConf(); |
||||
|
// create a mock database interface |
||||
|
Arsse::$db = Phake::mock(Database::class); |
||||
|
Phake::when(Arsse::$db)->begin->thenReturn(Phake::mock(\JKingWeb\Arsse\Db\Transaction::class)); |
||||
|
// create a mock user driver |
||||
|
$this->drv = Phake::mock(Driver::class); |
||||
|
} |
||||
|
|
||||
|
public function testListDrivers() { |
||||
|
$exp = [ |
||||
|
'JKingWeb\\Arsse\\User\\Internal\\Driver' => Arsse::$lang->msg("Driver.User.Internal.Name"), |
||||
|
]; |
||||
|
$this->assertArraySubset($exp, User::driverList()); |
||||
|
} |
||||
|
|
||||
|
public function testConstruct() { |
||||
|
$this->assertInstanceOf(User::class, new User($this->drv)); |
||||
|
$this->assertInstanceOf(User::class, new User); |
||||
|
} |
||||
|
|
||||
|
public function testConversionToString() { |
||||
|
$u = new User; |
||||
|
$u->id = "john.doe@example.com"; |
||||
|
$this->assertSame("john.doe@example.com", (string) $u); |
||||
|
$u->id = null; |
||||
|
$this->assertSame("", (string) $u); |
||||
|
} |
||||
|
|
||||
|
/** @dataProvider provideAuthentication */ |
||||
|
public function testAuthenticateAUser(bool $preAuth, string $user, string $password, bool $exp) { |
||||
|
Arsse::$conf->userPreAuth = $preAuth; |
||||
|
Phake::when($this->drv)->auth->thenReturn(false); |
||||
|
Phake::when($this->drv)->auth("john.doe@example.com", "secret")->thenReturn(true); |
||||
|
Phake::when($this->drv)->auth("jane.doe@example.com", "superman")->thenReturn(true); |
||||
|
Phake::when(Arsse::$db)->userExists("john.doe@example.com")->thenReturn(true); |
||||
|
Phake::when(Arsse::$db)->userExists("jane.doe@example.com")->thenReturn(false); |
||||
|
Phake::when(Arsse::$db)->userAdd->thenReturn(""); |
||||
|
$u = new User($this->drv); |
||||
|
$this->assertSame($exp, $u->auth($user, $password)); |
||||
|
$this->assertNull($u->id); |
||||
|
Phake::verify(Arsse::$db, Phake::times($exp ? 1 : 0))->userExists($user); |
||||
|
Phake::verify(Arsse::$db, Phake::times($exp && $user == "jane.doe@example.com" ? 1 : 0))->userAdd($user, $password); |
||||
|
} |
||||
|
|
||||
|
public function provideAuthentication() { |
||||
|
$john = "john.doe@example.com"; |
||||
|
$jane = "jane.doe@example.com"; |
||||
|
return [ |
||||
|
[false, $john, "secret", true], |
||||
|
[false, $john, "superman", false], |
||||
|
[false, $jane, "secret", false], |
||||
|
[false, $jane, "superman", true], |
||||
|
[true, $john, "secret", true], |
||||
|
[true, $john, "superman", true], |
||||
|
[true, $jane, "secret", true], |
||||
|
[true, $jane, "superman", true], |
||||
|
]; |
||||
|
} |
||||
|
|
||||
|
/** @dataProvider provideUserList */ |
||||
|
public function testListUsers(bool $authorized, $exp) { |
||||
|
$u = new User($this->drv); |
||||
|
Phake::when($this->drv)->authorize->thenReturn($authorized); |
||||
|
Phake::when($this->drv)->userList->thenReturn(["john.doe@example.com", "jane.doe@example.com"]); |
||||
|
if ($exp instanceof Exception) { |
||||
|
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); |
||||
|
} |
||||
|
$this->assertSame($exp, $u->list()); |
||||
|
} |
||||
|
|
||||
|
public function provideUserList() { |
||||
|
$john = "john.doe@example.com"; |
||||
|
$jane = "jane.doe@example.com"; |
||||
|
return [ |
||||
|
[false, new \JKingWeb\Arsse\User\ExceptionAuthz("notAuthorized")], |
||||
|
[true, [$john, $jane]], |
||||
|
]; |
||||
|
} |
||||
|
|
||||
|
/** @dataProvider provideExistence */ |
||||
|
public function testCheckThatAUserExists(bool $authorized, string $user, $exp) { |
||||
|
$u = new User($this->drv); |
||||
|
Phake::when($this->drv)->authorize->thenReturn($authorized); |
||||
|
Phake::when($this->drv)->userExists("john.doe@example.com")->thenReturn(true); |
||||
|
Phake::when($this->drv)->userExists("jane.doe@example.com")->thenReturn(false); |
||||
|
if ($exp instanceof Exception) { |
||||
|
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); |
||||
|
} |
||||
|
$this->assertSame($exp, $u->exists($user)); |
||||
|
} |
||||
|
|
||||
|
public function provideExistence() { |
||||
|
$john = "john.doe@example.com"; |
||||
|
$jane = "jane.doe@example.com"; |
||||
|
return [ |
||||
|
[false, $john, new \JKingWeb\Arsse\User\ExceptionAuthz("notAuthorized")], |
||||
|
[false, $jane, new \JKingWeb\Arsse\User\ExceptionAuthz("notAuthorized")], |
||||
|
[true, $john, true], |
||||
|
[true, $jane, false], |
||||
|
]; |
||||
|
} |
||||
|
|
||||
|
/** @dataProvider provideAdditions */ |
||||
|
public function testAddAUser(bool $authorized, string $user, $password, $exp) { |
||||
|
$u = new User($this->drv); |
||||
|
Phake::when($this->drv)->authorize->thenReturn($authorized); |
||||
|
Phake::when($this->drv)->userAdd("john.doe@example.com", $this->anything())->thenThrow(new \JKingWeb\Arsse\User\Exception("alreadyExists")); |
||||
|
Phake::when($this->drv)->userAdd("jane.doe@example.com", $this->anything())->thenReturnCallback(function($user, $pass) { |
||||
|
return $pass ?? "random password"; |
||||
|
}); |
||||
|
if ($exp instanceof Exception) { |
||||
|
if ($exp instanceof \JKingWeb\Arsse\User\ExceptionAuthz) { |
||||
|
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); |
||||
|
} else { |
||||
|
$this->assertException("alreadyExists", "User"); |
||||
|
} |
||||
|
} |
||||
|
$this->assertSame($exp, $u->add($user, $password)); |
||||
|
} |
||||
|
|
||||
|
/** @dataProvider provideAdditions */ |
||||
|
public function testAddAUserWithARandomPassword(bool $authorized, string $user, $password, $exp) { |
||||
|
$u = Phake::partialMock(User::class, $this->drv); |
||||
|
Phake::when($this->drv)->authorize->thenReturn($authorized); |
||||
|
Phake::when($this->drv)->userAdd($this->anything(), $this->isNull())->thenReturn(null); |
||||
|
Phake::when($this->drv)->userAdd("john.doe@example.com", $this->logicalNot($this->isNull()))->thenThrow(new \JKingWeb\Arsse\User\Exception("alreadyExists")); |
||||
|
Phake::when($this->drv)->userAdd("jane.doe@example.com", $this->logicalNot($this->isNull()))->thenReturnCallback(function($user, $pass) { |
||||
|
return $pass; |
||||
|
}); |
||||
|
if ($exp instanceof Exception) { |
||||
|
if ($exp instanceof \JKingWeb\Arsse\User\ExceptionAuthz) { |
||||
|
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); |
||||
|
$calls = 0; |
||||
|
} else { |
||||
|
$this->assertException("alreadyExists", "User"); |
||||
|
$calls = 2; |
||||
|
} |
||||
|
} else { |
||||
|
$calls = 4; |
||||
|
} |
||||
|
try { |
||||
|
$pass1 = $u->add($user, null); |
||||
|
$pass2 = $u->add($user, null); |
||||
|
$this->assertNotEquals($pass1, $pass2); |
||||
|
} finally { |
||||
|
Phake::verify($this->drv, Phake::times($calls))->userAdd; |
||||
|
Phake::verify($u, Phake::times($calls / 2))->generatePassword; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public function provideAdditions() { |
||||
|
$john = "john.doe@example.com"; |
||||
|
$jane = "jane.doe@example.com"; |
||||
|
return [ |
||||
|
[false, $john, "secret", new \JKingWeb\Arsse\User\ExceptionAuthz("notAuthorized")], |
||||
|
[false, $jane, "superman", new \JKingWeb\Arsse\User\ExceptionAuthz("notAuthorized")], |
||||
|
[true, $john, "secret", new \JKingWeb\Arsse\User\Exception("alreadyExists")], |
||||
|
[true, $jane, "superman", "superman"], |
||||
|
[true, $jane, null, "random password"], |
||||
|
]; |
||||
|
} |
||||
|
|
||||
|
/** @dataProvider provideRemovals */ |
||||
|
public function testRemoveAUser(bool $authorized, string $user, bool $exists, $exp) { |
||||
|
$u = new User($this->drv); |
||||
|
Phake::when($this->drv)->authorize->thenReturn($authorized); |
||||
|
Phake::when($this->drv)->userRemove("john.doe@example.com")->thenReturn(true); |
||||
|
Phake::when($this->drv)->userRemove("jane.doe@example.com")->thenThrow(new \JKingWeb\Arsse\User\Exception("doesNotExist")); |
||||
|
Phake::when(Arsse::$db)->userExists->thenReturn($exists); |
||||
|
Phake::when(Arsse::$db)->userRemove->thenReturn(true); |
||||
|
if ($exp instanceof Exception) { |
||||
|
if ($exp instanceof \JKingWeb\Arsse\User\ExceptionAuthz) { |
||||
|
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); |
||||
|
} else { |
||||
|
$this->assertException("doesNotExist", "User"); |
||||
|
} |
||||
|
} |
||||
|
try { |
||||
|
$this->assertSame($exp, $u->remove($user)); |
||||
|
} finally { |
||||
|
Phake::verify(Arsse::$db, Phake::times((int) $authorized))->userExists($user); |
||||
|
Phake::verify(Arsse::$db, Phake::times((int) ($authorized && $exists)))->userRemove($user); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public function provideRemovals() { |
||||
|
$john = "john.doe@example.com"; |
||||
|
$jane = "jane.doe@example.com"; |
||||
|
return [ |
||||
|
[false, $john, true, new \JKingWeb\Arsse\User\ExceptionAuthz("notAuthorized")], |
||||
|
[false, $john, false, new \JKingWeb\Arsse\User\ExceptionAuthz("notAuthorized")], |
||||
|
[false, $jane, true, new \JKingWeb\Arsse\User\ExceptionAuthz("notAuthorized")], |
||||
|
[false, $jane, false, new \JKingWeb\Arsse\User\ExceptionAuthz("notAuthorized")], |
||||
|
[true, $john, true, true], |
||||
|
[true, $john, false, true], |
||||
|
[true, $jane, true, new \JKingWeb\Arsse\User\Exception("doesNotExist")], |
||||
|
[true, $jane, false, new \JKingWeb\Arsse\User\Exception("doesNotExist")], |
||||
|
]; |
||||
|
} |
||||
|
|
||||
|
/** @dataProvider providePasswordChanges */ |
||||
|
public function testChangeAPassword(bool $authorized, string $user, $password, bool $exists, $exp) { |
||||
|
$u = new User($this->drv); |
||||
|
Phake::when($this->drv)->authorize->thenReturn($authorized); |
||||
|
Phake::when($this->drv)->userPasswordSet("john.doe@example.com", $this->anything(), $this->anything())->thenReturnCallback(function($user, $pass, $old) { |
||||
|
return $pass ?? "random password"; |
||||
|
}); |
||||
|
Phake::when($this->drv)->userPasswordSet("jane.doe@example.com", $this->anything(), $this->anything())->thenThrow(new \JKingWeb\Arsse\User\Exception("doesNotExist")); |
||||
|
Phake::when(Arsse::$db)->userExists->thenReturn($exists); |
||||
|
if ($exp instanceof Exception) { |
||||
|
if ($exp instanceof \JKingWeb\Arsse\User\ExceptionAuthz) { |
||||
|
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); |
||||
|
} else { |
||||
|
$this->assertException("doesNotExist", "User"); |
||||
|
} |
||||
|
$calls = 0; |
||||
|
} else{ |
||||
|
$calls = 1; |
||||
|
} |
||||
|
try { |
||||
|
$this->assertSame($exp, $u->passwordSet($user, $password)); |
||||
|
} finally { |
||||
|
Phake::verify(Arsse::$db, Phake::times($calls))->userExists($user); |
||||
|
Phake::verify(Arsse::$db, Phake::times($exists ? $calls : 0))->userPasswordSet($user, $password ?? "random password", null); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** @dataProvider providePasswordChanges */ |
||||
|
public function testChangeAPasswordToARandomPassword(bool $authorized, string $user, $password, bool $exists, $exp) { |
||||
|
$u = Phake::partialMock(User::class, $this->drv); |
||||
|
Phake::when($this->drv)->authorize->thenReturn($authorized); |
||||
|
Phake::when($this->drv)->userPasswordSet($this->anything(), $this->isNull(), $this->anything())->thenReturn(null); |
||||
|
Phake::when($this->drv)->userPasswordSet("john.doe@example.com", $this->logicalNot($this->isNull()), $this->anything())->thenReturnCallback(function($user, $pass, $old) { |
||||
|
return $pass ?? "random password"; |
||||
|
}); |
||||
|
Phake::when($this->drv)->userPasswordSet("jane.doe@example.com", $this->logicalNot($this->isNull()), $this->anything())->thenThrow(new \JKingWeb\Arsse\User\Exception("doesNotExist")); |
||||
|
Phake::when(Arsse::$db)->userExists->thenReturn($exists); |
||||
|
if ($exp instanceof Exception) { |
||||
|
if ($exp instanceof \JKingWeb\Arsse\User\ExceptionAuthz) { |
||||
|
$this->assertException("notAuthorized", "User", "ExceptionAuthz"); |
||||
|
$calls = 0; |
||||
|
} else { |
||||
|
$this->assertException("doesNotExist", "User"); |
||||
|
$calls = 2; |
||||
|
} |
||||
|
} else { |
||||
|
$calls = 4; |
||||
|
} |
||||
|
try { |
||||
|
$pass1 = $u->passwordSet($user, null); |
||||
|
$pass2 = $u->passwordSet($user, null); |
||||
|
$this->assertNotEquals($pass1, $pass2); |
||||
|
} finally { |
||||
|
Phake::verify($this->drv, Phake::times($calls))->userPasswordSet; |
||||
|
Phake::verify($u, Phake::times($calls / 2))->generatePassword; |
||||
|
Phake::verify(Arsse::$db, Phake::times($calls==4 ? 2 : 0))->userExists($user); |
||||
|
if ($calls == 4) { |
||||
|
Phake::verify(Arsse::$db, Phake::times($exists ? 1 : 0))->userPasswordSet($user, $pass1, null); |
||||
|
Phake::verify(Arsse::$db, Phake::times($exists ? 1 : 0))->userPasswordSet($user, $pass2, null); |
||||
|
} else { |
||||
|
Phake::verify(Arsse::$db, Phake::times(0))->userPasswordSet; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public function providePasswordChanges() { |
||||
|
$john = "john.doe@example.com"; |
||||
|
$jane = "jane.doe@example.com"; |
||||
|
return [ |
||||
|
[false, $john, "secret", true, new \JKingWeb\Arsse\User\ExceptionAuthz("notAuthorized")], |
||||
|
[false, $jane, "superman", false, new \JKingWeb\Arsse\User\ExceptionAuthz("notAuthorized")], |
||||
|
[true, $john, "superman", true, "superman"], |
||||
|
[true, $john, null, true, "random password"], |
||||
|
[true, $john, "superman", false, "superman"], |
||||
|
[true, $john, null, false, "random password"], |
||||
|
[true, $jane, "secret", true, new \JKingWeb\Arsse\User\Exception("doesNotExist")], |
||||
|
]; |
||||
|
} |
||||
|
} |
@ -1,20 +0,0 @@ |
|||||
<?php |
|
||||
/** @license MIT |
|
||||
* Copyright 2017 J. King, Dustin Wilson et al. |
|
||||
* See LICENSE and AUTHORS files for details */ |
|
||||
|
|
||||
declare(strict_types=1); |
|
||||
namespace JKingWeb\Arsse\TestCase\User; |
|
||||
|
|
||||
/** |
|
||||
* @covers \JKingWeb\Arsse\User |
|
||||
* @covers \JKingWeb\Arsse\User\Internal\Driver |
|
||||
* @covers \JKingWeb\Arsse\User\Internal\InternalFunctions */ |
|
||||
class TestInternal extends \JKingWeb\Arsse\Test\AbstractTest { |
|
||||
use \JKingWeb\Arsse\Test\User\CommonTests; |
|
||||
|
|
||||
const USER1 = "john.doe@example.com"; |
|
||||
const USER2 = "jane.doe@example.com"; |
|
||||
|
|
||||
public $drv = \JKingWeb\Arsse\User\Internal\Driver::class; |
|
||||
} |
|
@ -1,154 +0,0 @@ |
|||||
<?php |
|
||||
/** @license MIT |
|
||||
* Copyright 2017 J. King, Dustin Wilson et al. |
|
||||
* See LICENSE and AUTHORS files for details */ |
|
||||
|
|
||||
declare(strict_types=1); |
|
||||
namespace JKingWeb\Arsse\Test\User; |
|
||||
|
|
||||
use JKingWeb\Arsse\Arsse; |
|
||||
use JKingWeb\Arsse\Conf; |
|
||||
use JKingWeb\Arsse\User; |
|
||||
use JKingWeb\Arsse\User\Driver; |
|
||||
use Phake; |
|
||||
|
|
||||
trait CommonTests { |
|
||||
public function setUp() { |
|
||||
$this->clearData(); |
|
||||
$conf = new Conf(); |
|
||||
$conf->userDriver = $this->drv; |
|
||||
$conf->userPreAuth = false; |
|
||||
Arsse::$conf = $conf; |
|
||||
Arsse::$db = new Database(); |
|
||||
Arsse::$user = Phake::partialMock(User::class); |
|
||||
Phake::when(Arsse::$user)->authorize->thenReturn(true); |
|
||||
$_SERVER['PHP_AUTH_USER'] = self::USER1; |
|
||||
$_SERVER['PHP_AUTH_PW'] = "secret"; |
|
||||
// call the additional setup method if it exists |
|
||||
if (method_exists($this, "setUpSeries")) { |
|
||||
$this->setUpSeries(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public function tearDown() { |
|
||||
$this->clearData(); |
|
||||
// call the additional teardiwn method if it exists |
|
||||
if (method_exists($this, "tearDownSeries")) { |
|
||||
$this->tearDownSeries(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public function testListUsers() { |
|
||||
$this->assertCount(0, Arsse::$user->list()); |
|
||||
} |
|
||||
|
|
||||
public function testCheckIfAUserDoesNotExist() { |
|
||||
$this->assertFalse(Arsse::$user->exists(self::USER1)); |
|
||||
} |
|
||||
|
|
||||
public function testAddAUser() { |
|
||||
Arsse::$user->add(self::USER1, ""); |
|
||||
$this->assertCount(1, Arsse::$user->list()); |
|
||||
} |
|
||||
|
|
||||
public function testCheckIfAUserDoesExist() { |
|
||||
Arsse::$user->add(self::USER1, ""); |
|
||||
$this->assertTrue(Arsse::$user->exists(self::USER1)); |
|
||||
} |
|
||||
|
|
||||
public function testAddADuplicateUser() { |
|
||||
Arsse::$user->add(self::USER1, ""); |
|
||||
$this->assertException("alreadyExists", "User"); |
|
||||
Arsse::$user->add(self::USER1, ""); |
|
||||
} |
|
||||
|
|
||||
public function testAddMultipleUsers() { |
|
||||
Arsse::$user->add(self::USER1, ""); |
|
||||
Arsse::$user->add(self::USER2, ""); |
|
||||
$this->assertCount(2, Arsse::$user->list()); |
|
||||
} |
|
||||
|
|
||||
public function testRemoveAUser() { |
|
||||
Arsse::$user->add(self::USER1, ""); |
|
||||
$this->assertCount(1, Arsse::$user->list()); |
|
||||
Arsse::$user->remove(self::USER1); |
|
||||
$this->assertCount(0, Arsse::$user->list()); |
|
||||
} |
|
||||
|
|
||||
public function testRemoveAMissingUser() { |
|
||||
$this->assertException("doesNotExist", "User"); |
|
||||
Arsse::$user->remove(self::USER1); |
|
||||
} |
|
||||
|
|
||||
/** @group slow */ |
|
||||
public function testAuthenticateAUser() { |
|
||||
$_SERVER['PHP_AUTH_USER'] = self::USER1; |
|
||||
$_SERVER['PHP_AUTH_PW'] = "secret"; |
|
||||
Arsse::$user->add(self::USER1, "secret"); |
|
||||
Arsse::$user->add(self::USER2, ""); |
|
||||
$this->assertTrue(Arsse::$user->auth()); |
|
||||
$this->assertTrue(Arsse::$user->auth(self::USER1, "secret")); |
|
||||
$this->assertFalse(Arsse::$user->auth(self::USER1, "superman")); |
|
||||
$this->assertTrue(Arsse::$user->auth(self::USER2, "")); |
|
||||
} |
|
||||
|
|
||||
/** @group slow */ |
|
||||
public function testChangeAPassword() { |
|
||||
Arsse::$user->add(self::USER1, "secret"); |
|
||||
$this->assertEquals("superman", Arsse::$user->passwordSet(self::USER1, "superman")); |
|
||||
$this->assertTrue(Arsse::$user->auth(self::USER1, "superman")); |
|
||||
$this->assertFalse(Arsse::$user->auth(self::USER1, "secret")); |
|
||||
$this->assertEquals("", Arsse::$user->passwordSet(self::USER1, "")); |
|
||||
$this->assertTrue(Arsse::$user->auth(self::USER1, "")); |
|
||||
$this->assertEquals(Arsse::$conf->userTempPasswordLength, strlen(Arsse::$user->passwordSet(self::USER1))); |
|
||||
} |
|
||||
|
|
||||
public function testChangeAPasswordForAMissingUser() { |
|
||||
$this->assertException("doesNotExist", "User"); |
|
||||
Arsse::$user->passwordSet(self::USER1, "superman"); |
|
||||
} |
|
||||
|
|
||||
public function testGetThePropertiesOfAUser() { |
|
||||
Arsse::$user->add(self::USER1, "secret"); |
|
||||
$p = Arsse::$user->propertiesGet(self::USER1); |
|
||||
$this->assertArrayHasKey('id', $p); |
|
||||
$this->assertArrayHasKey('name', $p); |
|
||||
$this->assertArrayHasKey('domain', $p); |
|
||||
$this->assertArrayHasKey('rights', $p); |
|
||||
$this->assertArrayNotHasKey('password', $p); |
|
||||
$this->assertEquals(self::USER1, $p['name']); |
|
||||
} |
|
||||
|
|
||||
public function testSetThePropertiesOfAUser() { |
|
||||
$pSet = [ |
|
||||
'name' => 'John Doe', |
|
||||
'id' => 'invalid', |
|
||||
'domain' => 'localhost', |
|
||||
'rights' => Driver::RIGHTS_GLOBAL_ADMIN, |
|
||||
'password' => 'superman', |
|
||||
]; |
|
||||
$pGet = [ |
|
||||
'name' => 'John Doe', |
|
||||
'id' => self::USER1, |
|
||||
'domain' => 'example.com', |
|
||||
'rights' => Driver::RIGHTS_NONE, |
|
||||
]; |
|
||||
Arsse::$user->add(self::USER1, "secret"); |
|
||||
Arsse::$user->propertiesSet(self::USER1, $pSet); |
|
||||
$p = Arsse::$user->propertiesGet(self::USER1); |
|
||||
$this->assertArraySubset($pGet, $p); |
|
||||
$this->assertArrayNotHasKey('password', $p); |
|
||||
$this->assertFalse(Arsse::$user->auth(self::USER1, "superman")); |
|
||||
} |
|
||||
|
|
||||
public function testGetTheRightsOfAUser() { |
|
||||
Arsse::$user->add(self::USER1, ""); |
|
||||
$this->assertEquals(Driver::RIGHTS_NONE, Arsse::$user->rightsGet(self::USER1)); |
|
||||
} |
|
||||
|
|
||||
public function testSetTheRightsOfAUser() { |
|
||||
Arsse::$user->add(self::USER1, ""); |
|
||||
Arsse::$user->rightsSet(self::USER1, Driver::RIGHTS_GLOBAL_ADMIN); |
|
||||
$this->assertEquals(Driver::RIGHTS_GLOBAL_ADMIN, Arsse::$user->rightsGet(self::USER1)); |
|
||||
} |
|
||||
} |
|
@ -1,133 +0,0 @@ |
|||||
<?php |
|
||||
/** @license MIT |
|
||||
* Copyright 2017 J. King, Dustin Wilson et al. |
|
||||
* See LICENSE and AUTHORS files for details */ |
|
||||
|
|
||||
declare(strict_types=1); |
|
||||
namespace JKingWeb\Arsse\Test\User; |
|
||||
|
|
||||
use JKingWeb\Arsse\Arsse; |
|
||||
use JKingWeb\Arsse\User\Driver; |
|
||||
use JKingWeb\Arsse\User\Exception; |
|
||||
use JKingWeb\Arsse\User\ExceptionAuthz; |
|
||||
use PasswordGenerator\Generator as PassGen; |
|
||||
|
|
||||
class Database extends DriverSkeleton { |
|
||||
public $db = []; |
|
||||
|
|
||||
public function __construct() { |
|
||||
} |
|
||||
|
|
||||
public function userExists(string $user): bool { |
|
||||
if (!Arsse::$user->authorize($user, __FUNCTION__)) { |
|
||||
throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); |
|
||||
} |
|
||||
return parent::userExists($user); |
|
||||
} |
|
||||
|
|
||||
public function userAdd(string $user, string $password = null): string { |
|
||||
if (!Arsse::$user->authorize($user, __FUNCTION__)) { |
|
||||
throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); |
|
||||
} |
|
||||
if ($this->userExists($user)) { |
|
||||
throw new Exception("alreadyExists", ["action" => __FUNCTION__, "user" => $user]); |
|
||||
} |
|
||||
if ($password===null) { |
|
||||
$password = (new PassGen)->length(Arsse::$conf->userTempPasswordLength)->get(); |
|
||||
} |
|
||||
return parent::userAdd($user, $password); |
|
||||
} |
|
||||
|
|
||||
public function userRemove(string $user): bool { |
|
||||
if (!Arsse::$user->authorize($user, __FUNCTION__)) { |
|
||||
throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); |
|
||||
} |
|
||||
if (!$this->userExists($user)) { |
|
||||
throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); |
|
||||
} |
|
||||
return parent::userRemove($user); |
|
||||
} |
|
||||
|
|
||||
public function userList(string $domain = null): array { |
|
||||
if ($domain===null) { |
|
||||
if (!Arsse::$user->authorize("", __FUNCTION__)) { |
|
||||
throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => "global"]); |
|
||||
} |
|
||||
return parent::userList(); |
|
||||
} else { |
|
||||
$suffix = '@'.$domain; |
|
||||
if (!Arsse::$user->authorize($suffix, __FUNCTION__)) { |
|
||||
throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $domain]); |
|
||||
} |
|
||||
return parent::userList($domain); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public function userPasswordSet(string $user, string $newPassword = null, string $oldPassword = null): string { |
|
||||
if (!Arsse::$user->authorize($user, __FUNCTION__)) { |
|
||||
throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); |
|
||||
} |
|
||||
if (!$this->userExists($user)) { |
|
||||
throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); |
|
||||
} |
|
||||
if ($newPassword===null) { |
|
||||
$newPassword = (new PassGen)->length(Arsse::$conf->userTempPasswordLength)->get(); |
|
||||
} |
|
||||
return parent::userPasswordSet($user, $newPassword); |
|
||||
} |
|
||||
|
|
||||
public function userPropertiesGet(string $user): array { |
|
||||
if (!Arsse::$user->authorize($user, __FUNCTION__)) { |
|
||||
throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); |
|
||||
} |
|
||||
if (!$this->userExists($user)) { |
|
||||
throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); |
|
||||
} |
|
||||
$out = parent::userPropertiesGet($user); |
|
||||
unset($out['password']); |
|
||||
return $out; |
|
||||
} |
|
||||
|
|
||||
public function userPropertiesSet(string $user, array $properties): array { |
|
||||
if (!Arsse::$user->authorize($user, __FUNCTION__)) { |
|
||||
throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); |
|
||||
} |
|
||||
if (!$this->userExists($user)) { |
|
||||
throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); |
|
||||
} |
|
||||
parent::userPropertiesSet($user, $properties); |
|
||||
return $this->userPropertiesGet($user); |
|
||||
} |
|
||||
|
|
||||
public function userRightsGet(string $user): int { |
|
||||
if (!Arsse::$user->authorize($user, __FUNCTION__)) { |
|
||||
throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); |
|
||||
} |
|
||||
if (!$this->userExists($user)) { |
|
||||
throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); |
|
||||
} |
|
||||
return parent::userRightsGet($user); |
|
||||
} |
|
||||
|
|
||||
public function userRightsSet(string $user, int $level): bool { |
|
||||
if (!Arsse::$user->authorize($user, __FUNCTION__)) { |
|
||||
throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); |
|
||||
} |
|
||||
if (!$this->userExists($user)) { |
|
||||
throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); |
|
||||
} |
|
||||
return parent::userRightsSet($user, $level); |
|
||||
} |
|
||||
|
|
||||
// specific to mock database |
|
||||
|
|
||||
public function userPasswordGet(string $user): string { |
|
||||
if (!Arsse::$user->authorize($user, __FUNCTION__)) { |
|
||||
throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); |
|
||||
} |
|
||||
if (!$this->userExists($user)) { |
|
||||
throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); |
|
||||
} |
|
||||
return $this->db[$user]['password']; |
|
||||
} |
|
||||
} |
|
@ -1,127 +0,0 @@ |
|||||
<?php |
|
||||
/** @license MIT |
|
||||
* Copyright 2017 J. King, Dustin Wilson et al. |
|
||||
* See LICENSE and AUTHORS files for details */ |
|
||||
|
|
||||
declare(strict_types=1); |
|
||||
namespace JKingWeb\Arsse\Test\User; |
|
||||
|
|
||||
use JKingWeb\Arsse\Arsse; |
|
||||
use JKingWeb\Arsse\User\Driver; |
|
||||
use JKingWeb\Arsse\User\Exception; |
|
||||
use PasswordGenerator\Generator as PassGen; |
|
||||
|
|
||||
class DriverExternalMock extends DriverSkeleton implements Driver { |
|
||||
public $db = []; |
|
||||
protected $functions = [ |
|
||||
"auth" => Driver::FUNC_EXTERNAL, |
|
||||
"userList" => Driver::FUNC_EXTERNAL, |
|
||||
"userExists" => Driver::FUNC_EXTERNAL, |
|
||||
"userAdd" => Driver::FUNC_EXTERNAL, |
|
||||
"userRemove" => Driver::FUNC_EXTERNAL, |
|
||||
"userPasswordSet" => Driver::FUNC_EXTERNAL, |
|
||||
"userPropertiesGet" => Driver::FUNC_EXTERNAL, |
|
||||
"userPropertiesSet" => Driver::FUNC_EXTERNAL, |
|
||||
"userRightsGet" => Driver::FUNC_EXTERNAL, |
|
||||
"userRightsSet" => Driver::FUNC_EXTERNAL, |
|
||||
]; |
|
||||
|
|
||||
public static function driverName(): string { |
|
||||
return "Mock External Driver"; |
|
||||
} |
|
||||
|
|
||||
public function driverFunctions(string $function = null) { |
|
||||
if ($function===null) { |
|
||||
return $this->functions; |
|
||||
} |
|
||||
if (array_key_exists($function, $this->functions)) { |
|
||||
return $this->functions[$function]; |
|
||||
} else { |
|
||||
return Driver::FUNC_NOT_IMPLEMENTED; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public function __construct() { |
|
||||
} |
|
||||
|
|
||||
public function auth(string $user, string $password): bool { |
|
||||
if (!$this->userExists($user)) { |
|
||||
return false; |
|
||||
} |
|
||||
if ($password==="" && $this->db[$user]['password']==="") { |
|
||||
return true; |
|
||||
} |
|
||||
if (password_verify($password, $this->db[$user]['password'])) { |
|
||||
return true; |
|
||||
} |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
public function userExists(string $user): bool { |
|
||||
return parent::userExists($user); |
|
||||
} |
|
||||
|
|
||||
public function userAdd(string $user, string $password = null): string { |
|
||||
if ($this->userExists($user)) { |
|
||||
throw new Exception("alreadyExists", ["action" => __FUNCTION__, "user" => $user]); |
|
||||
} |
|
||||
if ($password===null) { |
|
||||
$password = (new PassGen)->length(Arsse::$conf->userTempPasswordLength)->get(); |
|
||||
} |
|
||||
return parent::userAdd($user, $password); |
|
||||
} |
|
||||
|
|
||||
public function userRemove(string $user): bool { |
|
||||
if (!$this->userExists($user)) { |
|
||||
throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); |
|
||||
} |
|
||||
return parent::userRemove($user); |
|
||||
} |
|
||||
|
|
||||
public function userList(string $domain = null): array { |
|
||||
if ($domain===null) { |
|
||||
return parent::userList(); |
|
||||
} else { |
|
||||
return parent::userList($domain); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public function userPasswordSet(string $user, string $newPassword = null, string $oldPassword = null): string { |
|
||||
if (!$this->userExists($user)) { |
|
||||
throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); |
|
||||
} |
|
||||
if ($newPassword===null) { |
|
||||
$newPassword = (new PassGen)->length(Arsse::$conf->userTempPasswordLength)->get(); |
|
||||
} |
|
||||
return parent::userPasswordSet($user, $newPassword); |
|
||||
} |
|
||||
|
|
||||
public function userPropertiesGet(string $user): array { |
|
||||
if (!$this->userExists($user)) { |
|
||||
throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); |
|
||||
} |
|
||||
return parent::userPropertiesGet($user); |
|
||||
} |
|
||||
|
|
||||
public function userPropertiesSet(string $user, array $properties): array { |
|
||||
if (!$this->userExists($user)) { |
|
||||
throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); |
|
||||
} |
|
||||
parent::userPropertiesSet($user, $properties); |
|
||||
return $this->userPropertiesGet($user); |
|
||||
} |
|
||||
|
|
||||
public function userRightsGet(string $user): int { |
|
||||
if (!$this->userExists($user)) { |
|
||||
throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); |
|
||||
} |
|
||||
return parent::userRightsGet($user); |
|
||||
} |
|
||||
|
|
||||
public function userRightsSet(string $user, int $level): bool { |
|
||||
if (!$this->userExists($user)) { |
|
||||
throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); |
|
||||
} |
|
||||
return parent::userRightsSet($user, $level); |
|
||||
} |
|
||||
} |
|
@ -1,56 +0,0 @@ |
|||||
<?php |
|
||||
/** @license MIT |
|
||||
* Copyright 2017 J. King, Dustin Wilson et al. |
|
||||
* See LICENSE and AUTHORS files for details */ |
|
||||
|
|
||||
declare(strict_types=1); |
|
||||
namespace JKingWeb\Arsse\Test\User; |
|
||||
|
|
||||
use JKingWeb\Arsse\User\Driver; |
|
||||
|
|
||||
class DriverInternalMock extends Database implements Driver { |
|
||||
public $db = []; |
|
||||
protected $functions = [ |
|
||||
"auth" => Driver::FUNC_INTERNAL, |
|
||||
"userList" => Driver::FUNC_INTERNAL, |
|
||||
"userExists" => Driver::FUNC_INTERNAL, |
|
||||
"userAdd" => Driver::FUNC_INTERNAL, |
|
||||
"userRemove" => Driver::FUNC_INTERNAL, |
|
||||
"userPasswordSet" => Driver::FUNC_INTERNAL, |
|
||||
"userPropertiesGet" => Driver::FUNC_INTERNAL, |
|
||||
"userPropertiesSet" => Driver::FUNC_INTERNAL, |
|
||||
"userRightsGet" => Driver::FUNC_INTERNAL, |
|
||||
"userRightsSet" => Driver::FUNC_INTERNAL, |
|
||||
]; |
|
||||
|
|
||||
public static function driverName(): string { |
|
||||
return "Mock Internal Driver"; |
|
||||
} |
|
||||
|
|
||||
public function driverFunctions(string $function = null) { |
|
||||
if ($function===null) { |
|
||||
return $this->functions; |
|
||||
} |
|
||||
if (array_key_exists($function, $this->functions)) { |
|
||||
return $this->functions[$function]; |
|
||||
} else { |
|
||||
return Driver::FUNC_NOT_IMPLEMENTED; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public function __construct() { |
|
||||
} |
|
||||
|
|
||||
public function auth(string $user, string $password): bool { |
|
||||
if (!$this->userExists($user)) { |
|
||||
return false; |
|
||||
} |
|
||||
if ($password==="" && $this->db[$user]['password']==="") { |
|
||||
return true; |
|
||||
} |
|
||||
if (password_verify($password, $this->db[$user]['password'])) { |
|
||||
return true; |
|
||||
} |
|
||||
return false; |
|
||||
} |
|
||||
} |
|
@ -1,72 +0,0 @@ |
|||||
<?php |
|
||||
/** @license MIT |
|
||||
* Copyright 2017 J. King, Dustin Wilson et al. |
|
||||
* See LICENSE and AUTHORS files for details */ |
|
||||
|
|
||||
declare(strict_types=1); |
|
||||
namespace JKingWeb\Arsse\Test\User; |
|
||||
|
|
||||
use JKingWeb\Arsse\Lang; |
|
||||
use JKingWeb\Arsse\User\Driver; |
|
||||
use JKingWeb\Arsse\User\Exception; |
|
||||
use JKingWeb\Arsse\User\ExceptionAuthz; |
|
||||
use PasswordGenerator\Generator as PassGen; |
|
||||
|
|
||||
abstract class DriverSkeleton { |
|
||||
protected $db = []; |
|
||||
|
|
||||
public function userExists(string $user): bool { |
|
||||
return array_key_exists($user, $this->db); |
|
||||
} |
|
||||
|
|
||||
public function userAdd(string $user, string $password = null): string { |
|
||||
$u = [ |
|
||||
'password' => $password ? password_hash($password, \PASSWORD_DEFAULT) : "", |
|
||||
'rights' => Driver::RIGHTS_NONE, |
|
||||
]; |
|
||||
$this->db[$user] = $u; |
|
||||
return $password; |
|
||||
} |
|
||||
|
|
||||
public function userRemove(string $user): bool { |
|
||||
unset($this->db[$user]); |
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
public function userList(string $domain = null): array { |
|
||||
$list = array_keys($this->db); |
|
||||
if ($domain===null) { |
|
||||
return $list; |
|
||||
} else { |
|
||||
$suffix = '@'.$domain; |
|
||||
$len = -1 * strlen($suffix); |
|
||||
return array_filter($list, function ($user) use ($suffix, $len) { |
|
||||
return substr_compare($user, $suffix, $len); |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public function userPasswordSet(string $user, string $newPassword = null, string $oldPassword = null): string { |
|
||||
$this->db[$user]['password'] = password_hash($newPassword, \PASSWORD_DEFAULT); |
|
||||
return $newPassword; |
|
||||
} |
|
||||
|
|
||||
public function userPropertiesGet(string $user): array { |
|
||||
$out = $this->db[$user]; |
|
||||
return $out; |
|
||||
} |
|
||||
|
|
||||
public function userPropertiesSet(string $user, array $properties): array { |
|
||||
$this->db[$user] = array_merge($this->db[$user], $properties); |
|
||||
return $this->userPropertiesGet($user); |
|
||||
} |
|
||||
|
|
||||
public function userRightsGet(string $user): int { |
|
||||
return $this->db[$user]['rights']; |
|
||||
} |
|
||||
|
|
||||
public function userRightsSet(string $user, int $level): bool { |
|
||||
$this->db[$user]['rights'] = $level; |
|
||||
return true; |
|
||||
} |
|
||||
} |
|
Loading…
Reference in new issue