diff --git a/lib/User.php b/lib/User.php index 2b3daa4b..b5fa3dcf 100644 --- a/lib/User.php +++ b/lib/User.php @@ -170,7 +170,7 @@ class User { // we handle authorization checks for external drivers if(!$this->authorize($user, $func)) throw new User\ExceptionAuthz("notAuthorized", ["action" => $func, "user" => $user]); $out = $this->u->userExists($user); - if($out && !$this->data->db->userExist($user)) $this->autoProvision($user, ""); + if($out && !$this->data->db->userExists($user)) $this->autoProvision($user, ""); return $out; case User\Driver::FUNC_INTERNAL: // internal functions handle their own authorization @@ -285,7 +285,7 @@ class User { $out = $this->u->userPropertiesSet($user, $properties); if($this->data->db->userExists($user)) { // if the property change was successful and the user exists, set the internal properties to the same values - $this->data->db->userPpropertiesSet($user, $out); + $this->data->db->userPropertiesSet($user, $out); } else { // if the user does not exists in the internal database, create it $this->autoProvision($user, "", $out); diff --git a/tests/User/TestUserExternal.php b/tests/User/TestUserExternal.php new file mode 100644 index 00000000..de9f2186 --- /dev/null +++ b/tests/User/TestUserExternal.php @@ -0,0 +1,131 @@ +userDriver = $drv; + $conf->userAuthPreferHTTP = true; + $this->data = new Test\RuntimeData($conf); + $this->data->db = new Test\User\Database($this->data); + $this->data->user = new User($this->data); + $this->data->user->authorizationEnabled(false); + $_SERVER['PHP_AUTH_USER'] = self::USER1; + $_SERVER['PHP_AUTH_PW'] = "secret"; + } + + function testListUsers() { + $this->assertCount(0,$this->data->user->list()); + } + + function testCheckIfAUserDoesNotExist() { + $this->assertFalse($this->data->user->exists(self::USER1)); + } + + function testAddAUser() { + $this->data->user->add(self::USER1, "secret"); + $this->assertCount(1,$this->data->user->list()); + } + + function testCheckIfAUserDoesExist() { + $this->data->user->add(self::USER1, "secret"); + $this->assertTrue($this->data->user->exists(self::USER1)); + } + + function testAddADuplicateUser() { + $this->data->user->add(self::USER1, "secret"); + $this->assertException("alreadyExists", "User"); + $this->data->user->add(self::USER1, "secret"); + } + + function testAddMultipleUsers() { + $this->data->user->add(self::USER1, "secret"); + $this->data->user->add(self::USER2, "secret"); + $this->assertCount(2,$this->data->user->list()); + } + + function testRemoveAUser() { + $this->data->user->add(self::USER1, "secret"); + $this->assertCount(1,$this->data->user->list()); + $this->data->user->remove(self::USER1); + $this->assertCount(0,$this->data->user->list()); + } + + function testRemoveAMissingUser() { + $this->assertException("doesNotExist", "User"); + $this->data->user->remove(self::USER1); + } + + function testAuthenticateAUser() { + $this->data->user->add(self::USER1, "secret"); + $this->assertTrue($this->data->user->auth(self::USER1, "secret")); + $this->assertFalse($this->data->user->auth(self::USER1, "superman")); + } + + function testChangeAPassword() { + $this->data->user->add(self::USER1, "secret"); + $this->assertEquals("superman", $this->data->user->passwordSet(self::USER1, "superman")); + $this->assertTrue($this->data->user->auth(self::USER1, "superman")); + $this->assertFalse($this->data->user->auth(self::USER1, "secret")); + $this->assertEquals($this->data->conf->userTempPasswordLength, strlen($this->data->user->passwordSet(self::USER1))); + } + + function testChangeAPasswordForAMissingUser() { + $this->assertException("doesNotExist", "User"); + $this->data->user->passwordSet(self::USER1, "superman"); + } + + function testGetThePropertiesOfAUser() { + $this->data->user->add(self::USER1, "secret"); + $p = $this->data->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']); + } + + function testSetThePropertiesOfAUser() { + $pSet = [ + 'name' => 'John Doe', + 'id' => 'invalid', + 'domain' => 'localhost', + 'rights' => User\Driver::RIGHTS_GLOBAL_ADMIN, + 'password' => 'superman', + ]; + $pGet = [ + 'name' => 'John Doe', + 'id' => self::USER1, + 'domain' => 'example.com', + 'rights' => User\Driver::RIGHTS_NONE, + ]; + $this->data->user->add(self::USER1, "secret"); + $this->data->user->propertiesSet(self::USER1, $pSet); + $p = $this->data->user->propertiesGet(self::USER1); + $this->assertArraySubset($pGet, $p); + $this->assertArrayNotHasKey('password', $p); + $this->assertFalse($this->data->user->auth(self::USER1, "superman")); + } + + function testGetTheRightsOfAUser() { + $this->data->user->add(self::USER1, "secret"); + $this->assertEquals(User\Driver::RIGHTS_NONE, $this->data->user->rightsGet(self::USER1)); + } + + function testSetTheRightsOfAUser() { + $this->data->user->add(self::USER1, "secret"); + $this->data->user->rightsSet(self::USER1, User\Driver::RIGHTS_GLOBAL_ADMIN); + $this->assertEquals(User\Driver::RIGHTS_GLOBAL_ADMIN, $this->data->user->rightsGet(self::USER1)); + } +} \ No newline at end of file diff --git a/tests/lib/User/Database.php b/tests/lib/User/Database.php index 36c786ec..c86341a4 100644 --- a/tests/lib/User/Database.php +++ b/tests/lib/User/Database.php @@ -7,6 +7,10 @@ use JKingWeb\NewsSync\User\ExceptionAuthz; use PasswordGenerator\Generator as PassGen; class Database extends DriverSkeleton { + + public function __construct(\JKingWeb\NewsSync\RuntimeData $data) { + $this->data = $data; + } function userExists(string $user): bool { if(!$this->data->user->authorize($user, __FUNCTION__)) throw new ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]); diff --git a/tests/lib/User/DriverExternalMock.php b/tests/lib/User/DriverExternalMock.php new file mode 100644 index 00000000..c5428ce1 --- /dev/null +++ b/tests/lib/User/DriverExternalMock.php @@ -0,0 +1,101 @@ + 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, + ]; + + static public function create(\JKingWeb\NewsSync\RuntimeData $data): Driver { + return new static($data); + } + + static public 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(\JKingWeb\NewsSync\RuntimeData $data) { + $this->data = $data; + } + + function auth(string $user, string $password): bool { + if(!$this->userExists($user)) return false; + if(password_verify($password, $this->db[$user]['password'])) return true; + return false; + } + + function userExists(string $user): bool { + return parent::userExists($user); + } + + 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($this->data->conf->userTempPasswordLength)->get(); + return parent::userAdd($user, $password); + } + + function userRemove(string $user): bool { + if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); + return parent::userRemove($user); + } + + function userList(string $domain = null): array { + if($domain===null) { + return parent::userList(); + } else { + return parent::userList($domain); + } + } + + 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($this->data->conf->userTempPasswordLength)->get(); + return parent::userPasswordSet($user, $newPassword); + } + + function userPropertiesGet(string $user): array { + if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); + return parent::userPropertiesGet($user); + } + + 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); + } + + function userRightsGet(string $user): int { + if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); + return parent::userRightsGet($user); + } + + function userRightsSet(string $user, int $level): bool { + if(!$this->userExists($user)) throw new Exception("doesNotExist", ["action" => __FUNCTION__, "user" => $user]); + return parent::userRightsSet($user, $level); + } +} \ No newline at end of file diff --git a/tests/phpunit.xml b/tests/phpunit.xml index 5b31655a..72d2bda7 100644 --- a/tests/phpunit.xml +++ b/tests/phpunit.xml @@ -23,6 +23,7 @@ User/TestUser.php + User/TestUserExternal.php \ No newline at end of file