From ecdd6d30910f6faf7cef6bdacf2b0782e8b07bd3 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 10:39:37 +0200 Subject: [PATCH 01/42] component --- .gitignore | 13 ++ .../Domain/DataStructure/AccessToken.php | 90 ++++++++++++ .../Domain/DataStructure/Application.php | 42 ++++++ .../Domain/DataStructure/RequestAccess.php | 130 ++++++++++++++++++ component/Domain/DataStructure/User.php | 36 +++++ .../Domain/DataStructure/Value/ApiKey.php | 26 ++++ .../DataStructure/Value/ApplicationName.php | 16 +++ .../Domain/DataStructure/Value/AuthMethod.php | 22 +++ .../Value/CollectionApplication.php | 25 ++++ .../DataStructure/Value/EmailAddress.php | 8 ++ .../Domain/DataStructure/Value/Firstname.php | 8 ++ .../DataStructure/Value/IdApplication.php | 8 ++ .../DataStructure/Value/IdRequestAccess.php | 8 ++ component/Domain/DataStructure/Value/Jwt.php | 8 ++ .../Domain/DataStructure/Value/Lastname.php | 8 ++ component/Domain/DataStructure/Value/Logo.php | 8 ++ .../Value/RequestAccessState.php | 45 ++++++ .../Value/RequestAccessToken.php | 8 ++ component/Domain/DataStructure/Value/Role.php | 8 ++ .../Domain/DataStructure/Value/SslKey.php | 66 +++++++++ component/Domain/Port/Application.php | 19 +++ component/Domain/Port/RequestAccess.php | 16 +++ component/Domain/Port/UserNotification.php | 15 ++ component/Domain/Serialize/Application.php | 19 +++ component/Domain/Serialize/User.php | 19 +++ component/Domain/Service/AccessToken.php | 83 +++++++++++ component/Domain/Service/Application.php | 59 ++++++++ component/Domain/Service/RequestAccess.php | 54 ++++++++ composer.json | 37 +++++ 29 files changed, 904 insertions(+) create mode 100644 .gitignore create mode 100644 component/Domain/DataStructure/AccessToken.php create mode 100644 component/Domain/DataStructure/Application.php create mode 100644 component/Domain/DataStructure/RequestAccess.php create mode 100644 component/Domain/DataStructure/User.php create mode 100644 component/Domain/DataStructure/Value/ApiKey.php create mode 100644 component/Domain/DataStructure/Value/ApplicationName.php create mode 100644 component/Domain/DataStructure/Value/AuthMethod.php create mode 100644 component/Domain/DataStructure/Value/CollectionApplication.php create mode 100644 component/Domain/DataStructure/Value/EmailAddress.php create mode 100644 component/Domain/DataStructure/Value/Firstname.php create mode 100644 component/Domain/DataStructure/Value/IdApplication.php create mode 100644 component/Domain/DataStructure/Value/IdRequestAccess.php create mode 100644 component/Domain/DataStructure/Value/Jwt.php create mode 100644 component/Domain/DataStructure/Value/Lastname.php create mode 100644 component/Domain/DataStructure/Value/Logo.php create mode 100644 component/Domain/DataStructure/Value/RequestAccessState.php create mode 100644 component/Domain/DataStructure/Value/RequestAccessToken.php create mode 100644 component/Domain/DataStructure/Value/Role.php create mode 100644 component/Domain/DataStructure/Value/SslKey.php create mode 100644 component/Domain/Port/Application.php create mode 100644 component/Domain/Port/RequestAccess.php create mode 100644 component/Domain/Port/UserNotification.php create mode 100644 component/Domain/Serialize/Application.php create mode 100644 component/Domain/Serialize/User.php create mode 100644 component/Domain/Service/AccessToken.php create mode 100644 component/Domain/Service/Application.php create mode 100644 component/Domain/Service/RequestAccess.php create mode 100644 composer.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5976415 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +# App +composer.lock +vendor/* + +# Test +.phpunit* +test/storage/* +!test/storage/.gitkeep +public/coverage/* + +# Dev +.DS_Store +.nova/* diff --git a/component/Domain/DataStructure/AccessToken.php b/component/Domain/DataStructure/AccessToken.php new file mode 100644 index 0000000..11de546 --- /dev/null +++ b/component/Domain/DataStructure/AccessToken.php @@ -0,0 +1,90 @@ +value = $value; + $this->lifetime = $lifetime; + } + + public function getValue(): string + { + return $this->value; + } + + public function __toString(): string + { + return $this->getValue(); + } + + public function check(SslKey $sslKey, Application $application): bool + { + try { + + $payload = (new Jwt($this->value))->decode($sslKey->getPublic()); + + $idApplication = $payload[ self::PAYLOAD_KEY_APP ]->id ?? null; + + if (!$idApplication) return false; + + if (!$application->isHisId(new IdApplication($idApplication))) return false; + + } catch (\Exception $e) { + return false; + } + + return true; + } + + public function getPayload(SslKey $sslKey): ?array + { + try { + + $payLoad = (new Jwt($this->value))->decode($sslKey->getPublic()); + + return $payLoad; + + } catch (\Exception $e) { + return null; + } + } + + public static function generate(SslKey $sslKey, Application $application, ?User $user = null, int $lifetime = self::LIFETIME): self + { + $payload = [ + self::PAYLOAD_KEY_APP => SerializeApplication::serialize($application), + ]; + + if ($user) { + $payload[ self::PAYLOAD_KEY_USER ] = SerializeUser::serialize($user); + } + + return new self((string)Jwt::encode($sslKey->getPrivate(), $payload, $lifetime)); + } +} diff --git a/component/Domain/DataStructure/Application.php b/component/Domain/DataStructure/Application.php new file mode 100644 index 0000000..21503f1 --- /dev/null +++ b/component/Domain/DataStructure/Application.php @@ -0,0 +1,42 @@ +id = $id; + $this->name = $name; + $this->logo = $logo; + $this->apiKey = $apiKey; + } + + public function isHisApiKey(ApiKey $apiKey): bool + { + return ((string)$this->apiKey === (string)$apiKey); + } + + public function isHisId(IdApplication $id): bool + { + return ((string)$this->id === (string)$id); + } +} diff --git a/component/Domain/DataStructure/RequestAccess.php b/component/Domain/DataStructure/RequestAccess.php new file mode 100644 index 0000000..c678e56 --- /dev/null +++ b/component/Domain/DataStructure/RequestAccess.php @@ -0,0 +1,130 @@ +id = $id; + $this->application = $application; + $this->authMethod = $authMethod; + $this->state = $state; + $this->user = $user; + $this->expiration = time() + $lifetime; + } + + public function getId(): IdRequestAccess + { + return $this->id; + } + + public function getApplication(): Application + { + return $this->application; + } + + public function getAuthMethod(): AuthMethod + { + return $this->authMethod; + } + + public function getState(): RequestAccessState + { + return $this->state; + } + + public function getUser(): ?User + { + return $this->user; + } + + public function setUser(User $user): void + { + $this->user = $user; + } + + public function canBeSetStateTo(RequestAccessState $state): bool + { + return $this->state->canBeSetTo($state); + } + + public function setState(RequestAccessState $state): self + { + if (!$this->state->canBeSetTo($state)) { + throw new NotCompliant('State can be set to set to : ' . $state); + } + + $this->state = $state; + + return $this; + } + + public function tokenizeId(SslKey $sslKey): RequestAccessToken + { + $id = (string)$this->id; + + $datas = json_encode([ + self::TOKEN_PAYLOAD_EXPIRATION => $this->expiration, + self::TOKEN_PAYLOAD_ID => $id, + ]); + + $token = $sslKey->encrypt($datas); + + $token = strtr(base64_encode($token), '+/=', '._-'); + + return new RequestAccessToken($token); + } + + public static function untokenizeId(RequestAccessToken $token, SslKey $sslKey): IdRequestAccess + { + $token = base64_decode(strtr((string)$token, '._-', '+/=')); + + $datas = $sslKey->decrypt($token); + + $datas = json_decode($datas, true); + + $expiration = $datas[ self::TOKEN_PAYLOAD_EXPIRATION ] ?? 0; + if ($expiration < time()) { + throw new NotCompliant('Token expired'); + } + + $id = $datas[ self::TOKEN_PAYLOAD_ID ]; + + return new IdRequestAccess($id); + } +} diff --git a/component/Domain/DataStructure/User.php b/component/Domain/DataStructure/User.php new file mode 100644 index 0000000..c1dd189 --- /dev/null +++ b/component/Domain/DataStructure/User.php @@ -0,0 +1,36 @@ +emailAddress = $emailAddress; + $this->lastname = $lastname; + $this->firstname = $firstname; + $this->role = $role; + } +} diff --git a/component/Domain/DataStructure/Value/ApiKey.php b/component/Domain/DataStructure/Value/ApiKey.php new file mode 100644 index 0000000..2002d39 --- /dev/null +++ b/component/Domain/DataStructure/Value/ApiKey.php @@ -0,0 +1,26 @@ + 'API key', + self::OTP => 'OTP', + self::THIRD_PARTY => 'Third party', + ]; + + public function is(string|self $authMethod): bool + { + return ($this->value == (string)$authMethod); + } +} diff --git a/component/Domain/DataStructure/Value/CollectionApplication.php b/component/Domain/DataStructure/Value/CollectionApplication.php new file mode 100644 index 0000000..e0303ac --- /dev/null +++ b/component/Domain/DataStructure/Value/CollectionApplication.php @@ -0,0 +1,25 @@ +itemsIterator() as $entity) { + if ($entity->isHisApiKey($apiKey)) return $entity; + } + + return null; + } +} diff --git a/component/Domain/DataStructure/Value/EmailAddress.php b/component/Domain/DataStructure/Value/EmailAddress.php new file mode 100644 index 0000000..e8e2d19 --- /dev/null +++ b/component/Domain/DataStructure/Value/EmailAddress.php @@ -0,0 +1,8 @@ + 'Requested', + self::REFUSED => 'Refused', + self::VERIFIED => 'Verified', + self::GRANTED => 'Granted', + ]; + + public function canBeSetTo(string|self $state): bool + { + if (is_string($state)) $state = new self($state); + + switch ($state->getValue()) { + case RequestAccessState::REQUESTED : + + break; + + case RequestAccessState::REFUSED : + + return ($this->value == RequestAccessState::REQUESTED); + + case RequestAccessState::VERIFIED : + + return ($this->value == RequestAccessState::REQUESTED); + + case RequestAccessState::GRANTED : + + return ($this->value == RequestAccessState::VERIFIED); + + } + + return false; + } +} diff --git a/component/Domain/DataStructure/Value/RequestAccessToken.php b/component/Domain/DataStructure/Value/RequestAccessToken.php new file mode 100644 index 0000000..5b750b4 --- /dev/null +++ b/component/Domain/DataStructure/Value/RequestAccessToken.php @@ -0,0 +1,8 @@ +private = $private; + $this->public = $public; + } + + public function getPrivate(): string + { + return $this->private; + } + + public function getPublic(): string + { + return $this->public; + } + + public function encrypt(string $data): string + { + try { + $success = openssl_private_encrypt( + $data, + $encryptedData, + $this->private + ); + } catch (\Exception $e) { + $success = false; + } + + if (!$success) { + throw new NotCompliant('Encryption invalid, verify private key'); + } + + return $encryptedData; + } + + public function decrypt(string $encryptedData): string + { + try { + $success = openssl_public_decrypt( + $encryptedData, + $data, + $this->public + ); + } catch (\Exception $e) { + $success = false; + } + + if (!$success) { + throw new NotCompliant('Decryption invalid, verify encrypted data or public key'); + } + + return $data; + } +} diff --git a/component/Domain/Port/Application.php b/component/Domain/Port/Application.php new file mode 100644 index 0000000..29e46a6 --- /dev/null +++ b/component/Domain/Port/Application.php @@ -0,0 +1,19 @@ + (string) $application->id, + 'name' => (string) $application->name, + 'logo' => $application->logo ? (string) $application->logo : null, + 'api_key' => (string) $application->apiKey, + ]; + } +} diff --git a/component/Domain/Serialize/User.php b/component/Domain/Serialize/User.php new file mode 100644 index 0000000..d33231e --- /dev/null +++ b/component/Domain/Serialize/User.php @@ -0,0 +1,19 @@ + (string)$user->emailAddress, + 'lastname' => $user->lastname ? (string)$user->lastname : null, + 'firstname' => $user->firstname ? (string)$user->firstname : null, + 'role' => $user->role ? (string)$user->role : null, + ]; + } +} diff --git a/component/Domain/Service/AccessToken.php b/component/Domain/Service/AccessToken.php new file mode 100644 index 0000000..ec86442 --- /dev/null +++ b/component/Domain/Service/AccessToken.php @@ -0,0 +1,83 @@ +sslKey = $sslKey; + $this->serviceRequestAccess = $serviceRequestAccess; + } + + public function getPublicKey(): string + { + return $this->sslKey->getPublic(); + } + + public function getAlgorithm(): string + { + return EntityAccessToken::ALGORITHM; + } + + public function check(string $accessToken, Application $application): bool + { + return (new EntityAccessToken($accessToken))->check( + $this->sslKey, + $application + ); + } + + public function getFromRequestAccessToken(RequestAccess $requestAccess): EntityAccessToken + { + // Check request access status + if (!$requestAccess->canBeSetStateTo(new RequestAccessState(RequestAccessState::GRANTED))) { + throw new NotCompliant('The access request is invalid'); + } + + // Generate new access token + $accessToken = EntityAccessToken::generate( + $this->sslKey, + $requestAccess->getApplication(), + $requestAccess->getUser() + ); + + // Change state + $this->serviceRequestAccess->set( + $requestAccess + ->setState(new RequestAccessState(RequestAccessState::GRANTED)) + ); + + return $accessToken; + } + + public function getUserInfos(string $accessToken): ?array + { + $payLoad = (new EntityAccessToken($accessToken))->getPayload($this->sslKey); + + if (!isset($payLoad[ EntityAccessToken::PAYLOAD_KEY_USER ])) return null; + + return (array)$payLoad[ EntityAccessToken::PAYLOAD_KEY_USER ]; + } +} diff --git a/component/Domain/Service/Application.php b/component/Domain/Service/Application.php new file mode 100644 index 0000000..1a0964f --- /dev/null +++ b/component/Domain/Service/Application.php @@ -0,0 +1,59 @@ +repository = $repository; + } + + public function add(string $name, ?string $logo = null): EntityApplication + { + $application = new EntityApplication( + IdApplication::generate(), + new ApplicationName($name), + $logo ? new Logo($logo) : null, + ApiKey::generate() + ); + + $this->repository->set($application); + + return $application; + } + + public function set(EntityApplication $application): void + { + $this->repository->set($application); + } + + public function get(string|IdApplication $id): EntityApplication + { + if (is_string($id)) $id = new IdApplication($id); + + return $this->repository->get($id); + } + + public function getFromApiKey(string|ApiKey $apiKey): EntityApplication + { + if (is_string($apiKey)) $apiKey = new ApiKey($apiKey); + + return $this->repository->getFromApiKey($apiKey); + } +} diff --git a/component/Domain/Service/RequestAccess.php b/component/Domain/Service/RequestAccess.php new file mode 100644 index 0000000..e6f936e --- /dev/null +++ b/component/Domain/Service/RequestAccess.php @@ -0,0 +1,54 @@ +repository = $repository; + $this->sslKey = $sslKey; + } + + public function set(EntityRequestAccess $requestAccess): void + { + $this->repository->set($requestAccess); + } + + public function get(string|IdRequestAccess $id): EntityRequestAccess + { + if (is_string($id)) $id = new IdRequestAccess($id); + + return $this->repository->get($id); + } + + public function getToken(EntityRequestAccess $requestAccess): RequestAccessToken + { + return $requestAccess->tokenizeId($this->sslKey); + } + + public function getFromToken(string|RequestAccessToken $token): EntityRequestAccess + { + if (is_string($token)) $token = new IdRequestAccess($token); + + $id = EntityRequestAccess::untokenizeId($token, $this->sslKey); + + return $this->get($id); + } +} diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..27a1e94 --- /dev/null +++ b/composer.json @@ -0,0 +1,37 @@ +{ + "name": "phant/auth", + "description": "Manage auth easily", + "license": "MIT", + "keywords": ["auth manager", "auth component", "SimpleAuth"], + "authors": [ + { + "name": "Lenny ROUANET", + "email": "lennyrouanet@users.noreply.github.com" + } + ], + "require": { + "php": ">=8.1", + "phant/data-structure": "3.*" + }, + "require-dev": { + "psr/simple-cache": "^3.0", + "phpstan/phpstan": "^1.4", + "phpunit/phpunit": "^9.5", + "phant/cache": "1.*" + }, + "scripts": { + "analyse": "vendor/bin/phpstan analyse component --memory-limit=4G", + "test": "vendor/bin/phpunit test --testdox", + "code-coverage": "XDEBUG_MODE=coverage vendor/bin/phpunit test --coverage-html public/coverage/html" + }, + "autoload": { + "psr-4": { + "Phant\\Auth\\": "component/" + } + }, + "autoload-dev": { + "psr-4": { + "Test\\": "test/" + } + } +} From 632a708eaa1dda2db1eee52a62738962b0d335bf Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 10:40:01 +0200 Subject: [PATCH 02/42] Fixture --- .../Fixture/DataStructure/AccessToken.php | 36 +++++++++ .../Fixture/DataStructure/Application.php | 67 ++++++++++++++++ component/Fixture/DataStructure/User.php | 25 ++++++ .../Fixture/DataStructure/Value/SslKey.php | 79 +++++++++++++++++++ component/Fixture/Port/Application.php | 61 ++++++++++++++ component/Fixture/Port/RequestAccess.php | 41 ++++++++++ component/Fixture/Port/UserNotification.php | 26 ++++++ component/Fixture/Service/AccessToken.php | 20 +++++ component/Fixture/Service/Application.php | 21 +++++ component/Fixture/Service/RequestAccess.php | 23 ++++++ 10 files changed, 399 insertions(+) create mode 100644 component/Fixture/DataStructure/AccessToken.php create mode 100644 component/Fixture/DataStructure/Application.php create mode 100644 component/Fixture/DataStructure/User.php create mode 100644 component/Fixture/DataStructure/Value/SslKey.php create mode 100644 component/Fixture/Port/Application.php create mode 100644 component/Fixture/Port/RequestAccess.php create mode 100644 component/Fixture/Port/UserNotification.php create mode 100644 component/Fixture/Service/AccessToken.php create mode 100644 component/Fixture/Service/Application.php create mode 100644 component/Fixture/Service/RequestAccess.php diff --git a/component/Fixture/DataStructure/AccessToken.php b/component/Fixture/DataStructure/AccessToken.php new file mode 100644 index 0000000..f18960a --- /dev/null +++ b/component/Fixture/DataStructure/AccessToken.php @@ -0,0 +1,36 @@ + 'c2280258-78e9-48fd-905f-2c8e023acb9c', + 'name' => 'Flashpoint', + 'logo' => 'https://via.placeholder.com/400x200?text=Flashpoint', + 'api_key' => 'fw9LAIpY.rP6ogyVSQtLu9dV1pj94vXnzzEO5sHJWGxwa5c1g6Lkz06Z9tcnsmF4SbyTjyDSh', + ], + [ + 'id' => 'fa9a72a5-5c21-4056-818a-66b26626874a', + 'name' => 'LiveTube', + 'logo' => 'https://via.placeholder.com/400x200?text=LiveTube', + 'api_key' => 'kMgyGJlO.H6pYDtv8E51rK9D0gDSTYknvM7oEGgLL3Lbekj3EqWsMpDSz0Oo6ri5l7mDVnpkE', + ], + [ + 'id' => '1fa914ab-5d34-48d5-82fd-fc364c62b0f9', + 'name' => 'Taskeo', + 'logo' => 'https://via.placeholder.com/400x200?text=Taskeo', + 'api_key' => 'R2FpV3FU.w5skjmLm4VDylSrH1cSu7EQfrHVkIB5vacBF63Ni5WI8sIKAIQ2WJqISx7sl4TlJ', + ], + ]; + + public static function get(): EntityApplication + { + $datas = self::DATAS[0]; + + return self::buildFromDatas($datas); + } + + public static function getCollection(): CollectionApplication + { + $collection = new CollectionApplication(); + + foreach (self::DATAS as $datas) { + $collection->addApplication( + self::buildFromDatas($datas) + ); + } + + return $collection; + } + + private static function buildFromDatas(array $datas): EntityApplication + { + return new EntityApplication( + new IdApplication($datas['id']), + new ApplicationName($datas['name']), + new Logo($datas['logo']), + new ApiKey($datas['api_key']) + ); + } +} diff --git a/component/Fixture/DataStructure/User.php b/component/Fixture/DataStructure/User.php new file mode 100644 index 0000000..f3f6feb --- /dev/null +++ b/component/Fixture/DataStructure/User.php @@ -0,0 +1,25 @@ +cache = $cache; + } + + public function set(EntityApplication $application): void + { + $this->cache->set((string)$application->id, $application); + } + + public function get(IdApplication $id): EntityApplication + { + $entity = $this->cache->get((string)$id); + if ($entity) return $entity; + + foreach (FixtureApplication::getCollection()->itemsIterator() as $entity) { + if ((string)$entity->id == (string)$id) continue; + + return $entity; + } + + throw new NotFound('Application not found from Id : ' . $id); + } + + public function getFromApiKey(ApiKey $apiKey): EntityApplication + { + foreach (FixtureApplication::getCollection()->itemsIterator() as $entity) { + if ((string)$entity->apiKey == (string)$apiKey) continue; + + return $entity; + } + + throw new NotFound('Application not found from API key : ' . $apiKey); + } + + public function getList(): CollectionApplication + { + return FixtureApplication::getCollection(); + } +} diff --git a/component/Fixture/Port/RequestAccess.php b/component/Fixture/Port/RequestAccess.php new file mode 100644 index 0000000..34fbad7 --- /dev/null +++ b/component/Fixture/Port/RequestAccess.php @@ -0,0 +1,41 @@ +cache = $cache; + } + + public function set(EntityRequestAccess $requestAccess): void + { + $this->cache->set((string)$requestAccess->getId(), $requestAccess); + } + + public function get(IdRequestAccess $id): EntityRequestAccess + { + $entity = $this->cache->get((string)$id); + if ($entity) return $entity; + + $entity = FixtureRequestAccessFromOtp::get(); + + if ((string)$entity->getId() == (string)$id) { + throw $entity; + } + + throw new NotFound('Request access not found from Id : ' . $id); + } +} diff --git a/component/Fixture/Port/UserNotification.php b/component/Fixture/Port/UserNotification.php new file mode 100644 index 0000000..ad6bde0 --- /dev/null +++ b/component/Fixture/Port/UserNotification.php @@ -0,0 +1,26 @@ +cache = $cache; + } + + public function sendOtpFromRequestAccess(RequestAccessToken $requestAccessToken, RequestAccess $requestAccess, Otp $otp): void + { + $this->cache->set((string)$requestAccessToken, $otp); + } +} diff --git a/component/Fixture/Service/AccessToken.php b/component/Fixture/Service/AccessToken.php new file mode 100644 index 0000000..c41345a --- /dev/null +++ b/component/Fixture/Service/AccessToken.php @@ -0,0 +1,20 @@ + Date: Tue, 20 Sep 2022 10:40:34 +0200 Subject: [PATCH 03/42] Test --- phpunit.xml | 15 ++ test/Domain/DataStructure/AccessTokenTest.php | 87 ++++++++++ test/Domain/DataStructure/ApplicationTest.php | 77 +++++++++ .../DataStructure/RequestAccessTest.php | 155 ++++++++++++++++++ test/Domain/DataStructure/UserTest.php | 36 ++++ .../Domain/DataStructure/Value/ApiKeyTest.php | 17 ++ .../Value/ApplicationNameTest.php | 26 +++ .../DataStructure/Value/AuthMethodTest.php | 25 +++ .../Value/CollectionApplicationTest.php | 44 +++++ test/Domain/DataStructure/Value/OtpTest.php | 50 ++++++ .../Value/RequestAccessStateTest.php | 127 ++++++++++++++ .../Domain/DataStructure/Value/SslKeyTest.php | 74 +++++++++ test/Domain/Serialize/ApplicationTest.php | 33 ++++ test/Domain/Serialize/UserTest.php | 33 ++++ test/Domain/Service/AccessTokenTest.php | 81 +++++++++ test/Domain/Service/ApplicationTest.php | 60 +++++++ test/Domain/Service/RequestAccessTest.php | 64 ++++++++ 17 files changed, 1004 insertions(+) create mode 100644 phpunit.xml create mode 100644 test/Domain/DataStructure/AccessTokenTest.php create mode 100644 test/Domain/DataStructure/ApplicationTest.php create mode 100644 test/Domain/DataStructure/RequestAccessTest.php create mode 100644 test/Domain/DataStructure/UserTest.php create mode 100644 test/Domain/DataStructure/Value/ApiKeyTest.php create mode 100644 test/Domain/DataStructure/Value/ApplicationNameTest.php create mode 100644 test/Domain/DataStructure/Value/AuthMethodTest.php create mode 100644 test/Domain/DataStructure/Value/CollectionApplicationTest.php create mode 100644 test/Domain/DataStructure/Value/OtpTest.php create mode 100644 test/Domain/DataStructure/Value/RequestAccessStateTest.php create mode 100644 test/Domain/DataStructure/Value/SslKeyTest.php create mode 100644 test/Domain/Serialize/ApplicationTest.php create mode 100644 test/Domain/Serialize/UserTest.php create mode 100644 test/Domain/Service/AccessTokenTest.php create mode 100644 test/Domain/Service/ApplicationTest.php create mode 100644 test/Domain/Service/RequestAccessTest.php diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..ed1ffac --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,15 @@ + + + + test + + + + + + + + component/Domain + + + \ No newline at end of file diff --git a/test/Domain/DataStructure/AccessTokenTest.php b/test/Domain/DataStructure/AccessTokenTest.php new file mode 100644 index 0000000..cd51534 --- /dev/null +++ b/test/Domain/DataStructure/AccessTokenTest.php @@ -0,0 +1,87 @@ +fixture = FixtureAccessToken::get(); + } + + public function testConstruct(): void + { + $entity = new AccessToken($this->fixture->getValue()); + + $this->assertIsObject($entity); + $this->assertInstanceOf(AccessToken::class, $entity); + } + + public function testCheck(): void + { + $result = $this->fixture->check( + FixtureSslKey::get(), + FixtureApplication::get() + ); + + $this->assertIsBool($result); + $this->assertEquals(true, $result); + } + + public function testCheckInvalid(): void + { + $result = $this->fixture->check( + FixtureSslKey::getInvalid(), + FixtureApplication::get() + ); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + } + + public function testGetPayload(): void + { + $result = $this->fixture->getPayload( + FixtureSslKey::get() + ); + + $this->assertIsArray($result); + $this->assertArrayHasKey(AccessToken::PAYLOAD_KEY_APP, $result); + $this->assertArrayHasKey(AccessToken::PAYLOAD_KEY_USER, $result); + } + + public function testGetPayloadInvalid(): void + { + $result = $this->fixture->getPayload( + FixtureSslKey::getInvalid() + ); + + $this->assertNull($result); + } + + public function testGenerate(): void + { + $entity = AccessToken::generate( + FixtureSslKey::get(), + FixtureApplication::get(), + FixtureUser::get() + ); + + $this->assertIsObject($entity); + $this->assertInstanceOf(AccessToken::class, $entity); + } +} diff --git a/test/Domain/DataStructure/ApplicationTest.php b/test/Domain/DataStructure/ApplicationTest.php new file mode 100644 index 0000000..9ea1fe2 --- /dev/null +++ b/test/Domain/DataStructure/ApplicationTest.php @@ -0,0 +1,77 @@ +fixture = FixtureApplication::get(); + } + + public function testConstruct(): void + { + $entity = new Application( + IdApplication::generate(), + new ApplicationName('Foo bar'), + new Logo('https://domain.ext/file.ext'), + ApiKey::generate() + ); + + $this->assertIsObject($entity); + $this->assertInstanceOf(Application::class, $entity); + } + + public function testCheck(): void + { + $result = $this->fixture->isHisApiKey( + $this->fixture->apiKey + ); + + $this->assertIsBool($result); + $this->assertEquals(true, $result); + } + + public function testCheckInvalid(): void + { + $result = $this->fixture->isHisApiKey( + ApiKey::generate() + ); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + } + + public function testIsHisId(): void + { + $result = $this->fixture->isHisId( + $this->fixture->id + ); + + $this->assertIsBool($result); + $this->assertEquals(true, $result); + } + + public function testIsHisIdInvalid(): void + { + $result = $this->fixture->isHisId( + IdApplication::generate() + ); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + } +} diff --git a/test/Domain/DataStructure/RequestAccessTest.php b/test/Domain/DataStructure/RequestAccessTest.php new file mode 100644 index 0000000..8e2225c --- /dev/null +++ b/test/Domain/DataStructure/RequestAccessTest.php @@ -0,0 +1,155 @@ +fixture = FixtureRequestAccessFromOtp::get(); + } + + public function testGetId(): void + { + $value = $this->fixture->getId(); + + $this->assertIsObject($value); + $this->assertInstanceOf(IdRequestAccess::class, $value); + } + + public function testApplication(): void + { + $value = $this->fixture->getApplication(); + + $this->assertIsObject($value); + $this->assertInstanceOf(Application::class, $value); + } + + public function testGetAuthMethod(): void + { + $value = $this->fixture->getAuthMethod(); + + $this->assertIsObject($value); + $this->assertInstanceOf(AuthMethod::class, $value); + } + + public function testGetState(): void + { + $value = $this->fixture->getState(); + + $this->assertIsObject($value); + $this->assertInstanceOf(RequestAccessState::class, $value); + } + + public function testGetUser(): void + { + $value = $this->fixture->getUser(); + + $this->assertIsObject($value); + $this->assertInstanceOf(User::class, $value); + } + + public function testSetUser(): void + { + $this->fixture->setUser(FixtureUser::get()); + + $value = $this->fixture->getUser(); + + $this->assertIsObject($value); + $this->assertInstanceOf(User::class, $value); + $this->assertEquals(FixtureUser::get(), $value); + } + + public function testCanBeSetStateTo(): void + { + $result = $this->fixture->canBeSetStateTo(new RequestAccessState(RequestAccessState::VERIFIED)); + + $this->assertIsBool($result); + $this->assertEquals(true, $result); + } + + public function testSetState(): void + { + $entity = $this->fixture->setState(new RequestAccessState(RequestAccessState::VERIFIED)); + + $this->assertIsObject($entity); + $this->assertInstanceOf(RequestAccessFromOtp::class, $entity); + + $this->assertIsObject($entity->getState()); + $this->assertInstanceOf(RequestAccessState::class, $entity->getState()); + $this->assertEquals(new RequestAccessState(RequestAccessState::VERIFIED), $entity->getState()); + } + + public function testSetStateInvalid(): void + { + $this->expectException(NotCompliant::class); + + $entity = $this->fixture->setState(new RequestAccessState(RequestAccessState::REQUESTED)); + } + + public function testTokenizeIdAndUntokenizeId(): void + { + $result = $this->fixture->tokenizeId(FixtureSslKey::get()); + + $this->assertIsObject($result); + $this->assertInstanceOf(RequestAccessToken::class, $result); + + $entity = $this->fixture->untokenizeId($result, FixtureSslKey::get()); + + $this->assertIsObject($entity); + $this->assertInstanceOf(IdRequestAccess::class, $entity); + } + + public function testTokenizeIdInvalid(): void + { + $this->expectException(NotCompliant::class); + + $this->fixture->tokenizeId(FixtureSslKey::getInvalid()); + } + + public function testUntokenizeIdInvalid(): void + { + $this->expectException(NotCompliant::class); + + $this->fixture->untokenizeId( + $this->fixture->tokenizeId(FixtureSslKey::get()), + FixtureSslKey::getInvalid() + ); + } + + public function testUntokenizeIdExpired(): void + { + $this->expectException(NotCompliant::class); + + $this->fixture->untokenizeId( + FixtureRequestAccessFromOtp::getExpired()->tokenizeId(FixtureSslKey::get()), + FixtureSslKey::get() + ); + } +} diff --git a/test/Domain/DataStructure/UserTest.php b/test/Domain/DataStructure/UserTest.php new file mode 100644 index 0000000..14ec72e --- /dev/null +++ b/test/Domain/DataStructure/UserTest.php @@ -0,0 +1,36 @@ +fixture = FixtureUser::get(); + } + + public function testConstruct(): void + { + $entity = new User( + 'john.doe@domain.ext', + 'John', + 'DOE' + ); + + $this->assertIsObject($entity); + $this->assertInstanceOf(User::class, $entity); + } +} diff --git a/test/Domain/DataStructure/Value/ApiKeyTest.php b/test/Domain/DataStructure/Value/ApiKeyTest.php new file mode 100644 index 0000000..7735ffa --- /dev/null +++ b/test/Domain/DataStructure/Value/ApiKeyTest.php @@ -0,0 +1,17 @@ +assertIsObject($value); + $this->assertInstanceOf(ApiKey::class, $value); + } +} diff --git a/test/Domain/DataStructure/Value/ApplicationNameTest.php b/test/Domain/DataStructure/Value/ApplicationNameTest.php new file mode 100644 index 0000000..fc6b15a --- /dev/null +++ b/test/Domain/DataStructure/Value/ApplicationNameTest.php @@ -0,0 +1,26 @@ +assertIsObject($result); + $this->assertInstanceOf(ApplicationName::class, $result); + } + + public function testConstructFail(): void + { + $this->expectException(NotCompliant::class); + + new ApplicationName('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'); + } +} diff --git a/test/Domain/DataStructure/Value/AuthMethodTest.php b/test/Domain/DataStructure/Value/AuthMethodTest.php new file mode 100644 index 0000000..ad14911 --- /dev/null +++ b/test/Domain/DataStructure/Value/AuthMethodTest.php @@ -0,0 +1,25 @@ +is(AuthMethod::API_KEY); + + $this->assertIsBool($result); + $this->assertEquals(true, $result); + } + + public function testIsDifferent(): void + { + $result = (new AuthMethod(AuthMethod::API_KEY))->is(AuthMethod::OTP); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + } +} diff --git a/test/Domain/DataStructure/Value/CollectionApplicationTest.php b/test/Domain/DataStructure/Value/CollectionApplicationTest.php new file mode 100644 index 0000000..fa1c464 --- /dev/null +++ b/test/Domain/DataStructure/Value/CollectionApplicationTest.php @@ -0,0 +1,44 @@ +assertEquals(0, $collection->getNbItems()); + + $collection->addApplication( + FixtureApplication::get() + ); + + $this->assertEquals(1, $collection->getNbItems()); + } + + public function testSearchByApiKey(): void + { + $collection = FixtureApplication::getCollection(); + + $result = $collection->searchByApiKey( + FixtureApplication::get()->apiKey + ); + + $this->assertIsObject($result); + + $collection = FixtureApplication::getCollection(); + + $result = $collection->searchByApiKey( + 'XXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' + ); + + $this->assertNull($result); + } +} diff --git a/test/Domain/DataStructure/Value/OtpTest.php b/test/Domain/DataStructure/Value/OtpTest.php new file mode 100644 index 0000000..8a1cb3e --- /dev/null +++ b/test/Domain/DataStructure/Value/OtpTest.php @@ -0,0 +1,50 @@ +assertIsObject($result); + $this->assertInstanceOf(Otp::class, $result); + } + + public function testConstructFail(): void + { + $this->expectException(NotCompliant::class); + + new Otp('I23456'); + } + + public function testCheck(): void + { + $result = (new Otp('123456'))->check('123456'); + + $this->assertIsBool($result); + $this->assertEquals(true, $result); + } + + public function testCheckDifferent(): void + { + $result = (new Otp('123456'))->check('I23456'); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + } + + public function testGenerate(): void + { + $result = Otp::generate(); + + $this->assertIsObject($result); + $this->assertInstanceOf(Otp::class, $result); + } +} diff --git a/test/Domain/DataStructure/Value/RequestAccessStateTest.php b/test/Domain/DataStructure/Value/RequestAccessStateTest.php new file mode 100644 index 0000000..b74c2d7 --- /dev/null +++ b/test/Domain/DataStructure/Value/RequestAccessStateTest.php @@ -0,0 +1,127 @@ +canBeSetTo(RequestAccessState::REQUESTED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + + + $result = (new RequestAccessState(RequestAccessState::REQUESTED)) + ->canBeSetTo(RequestAccessState::REFUSED); + + $this->assertIsBool($result); + $this->assertEquals(true, $result); + + + $result = (new RequestAccessState(RequestAccessState::REQUESTED)) + ->canBeSetTo(RequestAccessState::VERIFIED); + + $this->assertIsBool($result); + $this->assertEquals(true, $result); + + + $result = (new RequestAccessState(RequestAccessState::REQUESTED)) + ->canBeSetTo(RequestAccessState::GRANTED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + + + // Refused to ... + $result = (new RequestAccessState(RequestAccessState::REFUSED)) + ->canBeSetTo(RequestAccessState::REQUESTED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + + + $result = (new RequestAccessState(RequestAccessState::REFUSED)) + ->canBeSetTo(RequestAccessState::REFUSED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + + + $result = (new RequestAccessState(RequestAccessState::REFUSED)) + ->canBeSetTo(RequestAccessState::VERIFIED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + + + $result = (new RequestAccessState(RequestAccessState::REFUSED)) + ->canBeSetTo(RequestAccessState::GRANTED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + + + // Verified to ... + $result = (new RequestAccessState(RequestAccessState::VERIFIED)) + ->canBeSetTo(RequestAccessState::REQUESTED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + + + $result = (new RequestAccessState(RequestAccessState::VERIFIED)) + ->canBeSetTo(RequestAccessState::REFUSED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + + + $result = (new RequestAccessState(RequestAccessState::VERIFIED)) + ->canBeSetTo(RequestAccessState::VERIFIED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + + + $result = (new RequestAccessState(RequestAccessState::VERIFIED)) + ->canBeSetTo(RequestAccessState::GRANTED); + + $this->assertIsBool($result); + $this->assertEquals(true, $result); + + + // Granted to ... + $result = (new RequestAccessState(RequestAccessState::GRANTED)) + ->canBeSetTo(RequestAccessState::REQUESTED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + + + $result = (new RequestAccessState(RequestAccessState::GRANTED)) + ->canBeSetTo(RequestAccessState::REFUSED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + + + $result = (new RequestAccessState(RequestAccessState::GRANTED)) + ->canBeSetTo(RequestAccessState::VERIFIED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + + + $result = (new RequestAccessState(RequestAccessState::GRANTED)) + ->canBeSetTo(RequestAccessState::GRANTED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + } +} diff --git a/test/Domain/DataStructure/Value/SslKeyTest.php b/test/Domain/DataStructure/Value/SslKeyTest.php new file mode 100644 index 0000000..efbbc21 --- /dev/null +++ b/test/Domain/DataStructure/Value/SslKeyTest.php @@ -0,0 +1,74 @@ +fixture = FixtureSslKey::get(); + $this->fixtureInvalid = FixtureSslKey::getInvalid(); + } + + public function testGetPrivate(): void + { + $result = $this->fixture->getPrivate(); + + $this->assertIsString($result); + } + + public function testGetPublic(): void + { + $result = $this->fixture->getPublic(); + + $this->assertIsString($result); + } + + public function testEncrypt(): void + { + $result = $this->fixture->encrypt('Foo bar'); + + $this->assertIsString($result); + } + + public function testEncryptInvalid(): void + { + $this->expectException(NotCompliant::class); + + $result = $this->fixtureInvalid->encrypt('Foo bar'); + } + + public function testEncryptInvalidBis(): void + { + $this->expectException(NotCompliant::class); + + $result = $this->fixtureInvalid->encrypt(''); + } + + public function testDecrypt(): void + { + $result = $this->fixture->decrypt( + $this->fixture->encrypt('Foo bar') + ); + + $this->assertIsString($result); + } + + public function testDecryptInvalid(): void + { + $this->expectException(NotCompliant::class); + + $result = $this->fixtureInvalid->decrypt( + $this->fixture->encrypt('Foo bar') + ); + } +} diff --git a/test/Domain/Serialize/ApplicationTest.php b/test/Domain/Serialize/ApplicationTest.php new file mode 100644 index 0000000..943c39d --- /dev/null +++ b/test/Domain/Serialize/ApplicationTest.php @@ -0,0 +1,33 @@ +fixture = FixtureApplication::get(); + } + + public function testSerialize(): void + { + $value = SerializeApplication::serialize( + $this->fixture + ); + + $this->assertIsArray($value); + $this->assertCount(4, $value); + $this->assertArrayHasKey('id', $value); + $this->assertArrayHasKey('name', $value); + $this->assertArrayHasKey('logo', $value); + $this->assertArrayHasKey('api_key', $value); + } +} diff --git a/test/Domain/Serialize/UserTest.php b/test/Domain/Serialize/UserTest.php new file mode 100644 index 0000000..e7b07a6 --- /dev/null +++ b/test/Domain/Serialize/UserTest.php @@ -0,0 +1,33 @@ +fixture = FixtureUser::get(); + } + + public function testSerialize(): void + { + $value = SerializeUser::serialize( + $this->fixture + ); + + $this->assertIsArray($value); + $this->assertCount(4, $value); + $this->assertArrayHasKey('email_address', $value); + $this->assertArrayHasKey('lastname', $value); + $this->assertArrayHasKey('firstname', $value); + $this->assertArrayHasKey('role', $value); + } +} diff --git a/test/Domain/Service/AccessTokenTest.php b/test/Domain/Service/AccessTokenTest.php new file mode 100644 index 0000000..f3f286c --- /dev/null +++ b/test/Domain/Service/AccessTokenTest.php @@ -0,0 +1,81 @@ +service = (new FixtureServiceAccessToken())(); + $this->fixture = FixtureAccessToken::get(); + } + + public function testGetPublicKey(): void + { + $value = $this->service->getPublicKey(); + + $this->assertIsString($value); + } + + public function testGetAlgorithm(): void + { + $value = $this->service->getAlgorithm(); + + $this->assertIsString($value); + } + + public function testCheck(): void + { + $value = $this->service->check( + (string)$this->fixture, + FixtureApplication::get() + ); + + $this->assertIsBool($value); + $this->assertEquals(true, $value); + } + + public function testGetFromRequestAccessToken(): void + { + $entity = $this->service->getFromRequestAccessToken( + FixtureRequestAccessFromOtp::getVerified() + ); + + $this->assertIsObject($entity); + $this->assertInstanceOf(AccessToken::class, $entity); + } + + public function testGetFromRequestAccessTokenInvalid(): void + { + $this->expectException(NotCompliant::class); + + $entity = $this->service->getFromRequestAccessToken( + FixtureRequestAccessFromOtp::get() + ); + } + + public function testGetUserInfos(): void + { + $value = $this->service->getUserInfos( + (string)$this->fixture + ); + + $this->assertIsArray($value); + } +} diff --git a/test/Domain/Service/ApplicationTest.php b/test/Domain/Service/ApplicationTest.php new file mode 100644 index 0000000..dcdd64d --- /dev/null +++ b/test/Domain/Service/ApplicationTest.php @@ -0,0 +1,60 @@ +fixture = (new FixtureServiceApplication())(); + } + + public function testAdd(): void + { + $entity = $this->fixture->add( + 'Foo bar', + 'https://domain.ext/file.ext' + ); + + $this->assertIsObject($entity); + $this->assertInstanceOf(Application::class, $entity); + } + + public function testSet(): void + { + $this->fixture->set( + FixtureApplication::get() + ); + + $this->addToAssertionCount(1); + } + + public function testGet(): void + { + $entity = $this->fixture->get( + FixtureApplication::get()->id + ); + + $this->assertIsObject($entity); + $this->assertInstanceOf(Application::class, $entity); + } + + public function testGetFromApiKey(): void + { + $entity = $this->fixture->getFromApiKey( + FixtureApplication::get()->apiKey + ); + + $this->assertIsObject($entity); + $this->assertInstanceOf(Application::class, $entity); + } +} diff --git a/test/Domain/Service/RequestAccessTest.php b/test/Domain/Service/RequestAccessTest.php new file mode 100644 index 0000000..7930cc5 --- /dev/null +++ b/test/Domain/Service/RequestAccessTest.php @@ -0,0 +1,64 @@ +service = (new FixtureServiceRequestAccess())(); + $this->fixture = FixtureRequestAccessFromOtp::get(); + } + + public function testSet(): void + { + $this->service->set( + $this->fixture + ); + + $this->addToAssertionCount(1); + } + + public function testGet(): void + { + $entity = $this->service->get( + $this->fixture->getId() + ); + + $this->assertIsObject($entity); + $this->assertInstanceOf(RequestAccessFromOtp::class, $entity); + } + + public function testGetToken(): void + { + $value = $this->service->getToken( + $this->fixture + ); + + $this->assertIsObject($value); + $this->assertInstanceOf(RequestAccessToken::class, $value); + } + + public function testGetFromToken(): void + { + $entity = $this->service->getFromToken( + $this->service->getToken( + $this->fixture + ) + ); + + $this->assertIsObject($entity); + $this->assertInstanceOf(RequestAccessFromOtp::class, $entity); + } +} From 20a9b929e790893a163ec47dda5e6601d752c511 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 10:40:52 +0200 Subject: [PATCH 04/42] Request access from OTP --- .../DataStructure/RequestAccessFromOtp.php | 50 +++++++++++ component/Domain/DataStructure/Value/Otp.php | 34 ++++++++ .../Domain/Service/RequestAccessFromOtp.php | 82 +++++++++++++++++++ .../DataStructure/RequestAccessFromOtp.php | 49 +++++++++++ .../Fixture/Service/RequestAccessFromOtp.php | 27 ++++++ .../RequestAccessFromOtpTest.php | 50 +++++++++++ .../Service/RequestAccessFromOtpTest.php | 70 ++++++++++++++++ test/storage/.gitkeep | 0 8 files changed, 362 insertions(+) create mode 100644 component/Domain/DataStructure/RequestAccessFromOtp.php create mode 100644 component/Domain/DataStructure/Value/Otp.php create mode 100644 component/Domain/Service/RequestAccessFromOtp.php create mode 100644 component/Fixture/DataStructure/RequestAccessFromOtp.php create mode 100644 component/Fixture/Service/RequestAccessFromOtp.php create mode 100644 test/Domain/DataStructure/RequestAccessFromOtpTest.php create mode 100644 test/Domain/Service/RequestAccessFromOtpTest.php create mode 100644 test/storage/.gitkeep diff --git a/component/Domain/DataStructure/RequestAccessFromOtp.php b/component/Domain/DataStructure/RequestAccessFromOtp.php new file mode 100644 index 0000000..50c1259 --- /dev/null +++ b/component/Domain/DataStructure/RequestAccessFromOtp.php @@ -0,0 +1,50 @@ +otp = $otp; + } + + public function checkOtp(string|Otp $otp): bool + { + if (is_string($otp)) $otp = new Otp($otp); + + return $this->otp->check($otp); + } +} diff --git a/component/Domain/DataStructure/Value/Otp.php b/component/Domain/DataStructure/Value/Otp.php new file mode 100644 index 0000000..ddc91a9 --- /dev/null +++ b/component/Domain/DataStructure/Value/Otp.php @@ -0,0 +1,34 @@ +value === (string)$otp; + } + + public static function generate(): self + { + $otp = ''; + + $characters = '0123456789'; + for ($i = 0; $i < self::LENGTH; $i++) { + $otp.= $characters[mt_rand(0, strlen($characters) - 1)]; + } + + return new self($otp); + } +} diff --git a/component/Domain/Service/RequestAccessFromOtp.php b/component/Domain/Service/RequestAccessFromOtp.php new file mode 100644 index 0000000..b4e8630 --- /dev/null +++ b/component/Domain/Service/RequestAccessFromOtp.php @@ -0,0 +1,82 @@ +serviceRequestAccess = $serviceRequestAccess; + $this->serviceAccessToken = $serviceAccessToken; + $this->userNotification = $userNotification; + } + + public function generate(User $user, Application $application): RequestAccessToken + { + $otp = Otp::generate(); + + $requestAccessFromOtp = new EntityRequestAccessFromOtp( + IdRequestAccess::generate(), + $application, + new RequestAccessState(RequestAccessState::REQUESTED), + $user, + $otp + ); + + $requestAccessToken = $this->serviceRequestAccess->getToken($requestAccessFromOtp); + + $this->userNotification->sendOtpFromRequestAccess($requestAccessToken, $requestAccessFromOtp, $otp); + + $this->serviceRequestAccess->set($requestAccessFromOtp); + + return $requestAccessToken; + } + + public function getAccessToken(RequestAccessToken $requestAccessToken, string|Otp $otp): ?AccessToken + { + $requestAccessFromOtp = $this->serviceRequestAccess->getFromToken($requestAccessToken); + + if (is_string($otp)) $otp = new Otp($otp); + + if ( ! $requestAccessFromOtp->checkOtp($otp)) return null; + + $requestAccessFromOtp->setState(new RequestAccessState(RequestAccessState::VERIFIED)); + + $this->serviceRequestAccess->set($requestAccessFromOtp); + + $accessToken = $this->serviceAccessToken->getFromRequestAccessToken($requestAccessFromOtp); + + return $accessToken; + } +} diff --git a/component/Fixture/DataStructure/RequestAccessFromOtp.php b/component/Fixture/DataStructure/RequestAccessFromOtp.php new file mode 100644 index 0000000..a29c812 --- /dev/null +++ b/component/Fixture/DataStructure/RequestAccessFromOtp.php @@ -0,0 +1,49 @@ +setState(new RequestAccessState(RequestAccessState::VERIFIED)); + } +} diff --git a/component/Fixture/Service/RequestAccessFromOtp.php b/component/Fixture/Service/RequestAccessFromOtp.php new file mode 100644 index 0000000..5239dde --- /dev/null +++ b/component/Fixture/Service/RequestAccessFromOtp.php @@ -0,0 +1,27 @@ +fixture = FixtureRequestAccessFromOtp::get(); + } + + public function testConstruct(): void + { + $entity = new RequestAccessFromOtp( + IdRequestAccess::generate(), + FixtureApplication::get(), + new RequestAccessState(RequestAccessState::REQUESTED), + FixtureUser::get(), + Otp::generate() + ); + + $this->assertIsObject($entity); + $this->assertInstanceOf(RequestAccessFromOtp::class, $entity); + } + + public function testCheckOtp(): void + { + $result = $this->fixture->checkOtp('123456'); + + $this->assertIsBool($result); + $this->assertEquals(true, $result); + } +} diff --git a/test/Domain/Service/RequestAccessFromOtpTest.php b/test/Domain/Service/RequestAccessFromOtpTest.php new file mode 100644 index 0000000..55b381e --- /dev/null +++ b/test/Domain/Service/RequestAccessFromOtpTest.php @@ -0,0 +1,70 @@ +service = (new FixtureServiceRequestAccessFromOtp())(); + $this->fixture = $this->service->generate( + FixtureUser::get(), + FixtureApplication::get() + ); + $this->cache = new SimpleCache(realpath(__DIR__ . '/../../../test/storage/'), 'user-notification'); + } + + public function testGenerate(): void + { + $this->assertIsObject($this->fixture); + $this->assertInstanceOf(RequestAccessToken::class, $this->fixture); + } + + public function testGetAccessToken(): void + { + $otp = $this->cache->get((string)$this->fixture); + + $entity = $this->service->getAccessToken( + $this->fixture, + $otp + ); + + $this->assertIsObject($entity); + $this->assertInstanceOf(AccessToken::class, $entity); + } + + public function testGetAccessTokenInvalid(): void + { + $entity = $this->service->getAccessToken( + $this->fixture, + '000000' + ); + + $this->assertNull($entity); + } +} diff --git a/test/storage/.gitkeep b/test/storage/.gitkeep new file mode 100644 index 0000000..e69de29 From 0e131b525a317b982653ed5f4006965949443a12 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 11:37:05 +0200 Subject: [PATCH 05/42] CS --- component/Domain/Service/RequestAccessFromOtp.php | 4 +--- component/Fixture/DataStructure/AccessToken.php | 4 +--- test/Domain/DataStructure/AccessTokenTest.php | 4 +--- test/Domain/DataStructure/RequestAccessFromOtpTest.php | 4 +++- test/Domain/DataStructure/RequestAccessTest.php | 2 +- 5 files changed, 7 insertions(+), 11 deletions(-) diff --git a/component/Domain/Service/RequestAccessFromOtp.php b/component/Domain/Service/RequestAccessFromOtp.php index b4e8630..9d52585 100644 --- a/component/Domain/Service/RequestAccessFromOtp.php +++ b/component/Domain/Service/RequestAccessFromOtp.php @@ -8,9 +8,7 @@ RequestAccess as ServiceRequestAccess, }; -use Phant\Auth\Domain\Port\{ - UserNotification, -}; +use Phant\Auth\Domain\Port\UserNotification; use Phant\Auth\Domain\DataStructure\{ AccessToken, Application, diff --git a/component/Fixture/DataStructure/AccessToken.php b/component/Fixture/DataStructure/AccessToken.php index f18960a..810d6c0 100644 --- a/component/Fixture/DataStructure/AccessToken.php +++ b/component/Fixture/DataStructure/AccessToken.php @@ -9,9 +9,7 @@ Application as FixtureApplication, User as FixtureUser, }; -use Phant\Auth\Fixture\DataStructure\Value\{ - SslKey as FixtureSslKey, -}; +use Phant\Auth\Fixture\DataStructure\Value\SslKey as FixtureSslKey; final class AccessToken { diff --git a/test/Domain/DataStructure/AccessTokenTest.php b/test/Domain/DataStructure/AccessTokenTest.php index cd51534..5450e2b 100644 --- a/test/Domain/DataStructure/AccessTokenTest.php +++ b/test/Domain/DataStructure/AccessTokenTest.php @@ -10,9 +10,7 @@ Application as FixtureApplication, User as FixtureUser, }; -use Phant\Auth\Fixture\DataStructure\Value\{ - SslKey as FixtureSslKey, -}; +use Phant\Auth\Fixture\DataStructure\Value\SslKey as FixtureSslKey; final class AccessTokenTest extends \PHPUnit\Framework\TestCase { diff --git a/test/Domain/DataStructure/RequestAccessFromOtpTest.php b/test/Domain/DataStructure/RequestAccessFromOtpTest.php index c169caa..5a2287f 100644 --- a/test/Domain/DataStructure/RequestAccessFromOtpTest.php +++ b/test/Domain/DataStructure/RequestAccessFromOtpTest.php @@ -42,7 +42,9 @@ public function testConstruct(): void public function testCheckOtp(): void { - $result = $this->fixture->checkOtp('123456'); + $result = $this->fixture->checkOtp( + '123456' + ); $this->assertIsBool($result); $this->assertEquals(true, $result); diff --git a/test/Domain/DataStructure/RequestAccessTest.php b/test/Domain/DataStructure/RequestAccessTest.php index 8e2225c..ca1c15f 100644 --- a/test/Domain/DataStructure/RequestAccessTest.php +++ b/test/Domain/DataStructure/RequestAccessTest.php @@ -43,7 +43,7 @@ public function testGetId(): void $this->assertInstanceOf(IdRequestAccess::class, $value); } - public function testApplication(): void + public function testGetApplication(): void { $value = $this->fixture->getApplication(); From 6cd51d8de560e08183c431c4a7b0865a59bb8a10 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 11:46:41 +0200 Subject: [PATCH 06/42] CS --- .../Domain/Service/RequestAccessFromOtp.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/component/Domain/Service/RequestAccessFromOtp.php b/component/Domain/Service/RequestAccessFromOtp.php index 9d52585..b746c0d 100644 --- a/component/Domain/Service/RequestAccessFromOtp.php +++ b/component/Domain/Service/RequestAccessFromOtp.php @@ -44,7 +44,7 @@ public function generate(User $user, Application $application): RequestAccessTok { $otp = Otp::generate(); - $requestAccessFromOtp = new EntityRequestAccessFromOtp( + $requestAccess = new EntityRequestAccessFromOtp( IdRequestAccess::generate(), $application, new RequestAccessState(RequestAccessState::REQUESTED), @@ -52,28 +52,28 @@ public function generate(User $user, Application $application): RequestAccessTok $otp ); - $requestAccessToken = $this->serviceRequestAccess->getToken($requestAccessFromOtp); + $requestAccessToken = $this->serviceRequestAccess->getToken($requestAccess); - $this->userNotification->sendOtpFromRequestAccess($requestAccessToken, $requestAccessFromOtp, $otp); + $this->userNotification->sendOtpFromRequestAccess($requestAccessToken, $requestAccess, $otp); - $this->serviceRequestAccess->set($requestAccessFromOtp); + $this->serviceRequestAccess->set($requestAccess); return $requestAccessToken; } public function getAccessToken(RequestAccessToken $requestAccessToken, string|Otp $otp): ?AccessToken { - $requestAccessFromOtp = $this->serviceRequestAccess->getFromToken($requestAccessToken); + $requestAccess = $this->serviceRequestAccess->getFromToken($requestAccessToken); if (is_string($otp)) $otp = new Otp($otp); - if ( ! $requestAccessFromOtp->checkOtp($otp)) return null; + if ( ! $requestAccess->checkOtp($otp)) return null; - $requestAccessFromOtp->setState(new RequestAccessState(RequestAccessState::VERIFIED)); + $requestAccess->setState(new RequestAccessState(RequestAccessState::VERIFIED)); - $this->serviceRequestAccess->set($requestAccessFromOtp); + $this->serviceRequestAccess->set($requestAccess); - $accessToken = $this->serviceAccessToken->getFromRequestAccessToken($requestAccessFromOtp); + $accessToken = $this->serviceAccessToken->getFromRequestAccessToken($requestAccess); return $accessToken; } From 9d0c1d5b84d8a85f9338d4ada8ab8e10bb4e0227 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 12:12:48 +0200 Subject: [PATCH 07/42] Fix --- component/Fixture/Port/Application.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/component/Fixture/Port/Application.php b/component/Fixture/Port/Application.php index 151335d..5e2b9fb 100644 --- a/component/Fixture/Port/Application.php +++ b/component/Fixture/Port/Application.php @@ -35,7 +35,7 @@ public function get(IdApplication $id): EntityApplication if ($entity) return $entity; foreach (FixtureApplication::getCollection()->itemsIterator() as $entity) { - if ((string)$entity->id == (string)$id) continue; + if ((string)$entity->id != (string)$id) continue; return $entity; } @@ -46,7 +46,7 @@ public function get(IdApplication $id): EntityApplication public function getFromApiKey(ApiKey $apiKey): EntityApplication { foreach (FixtureApplication::getCollection()->itemsIterator() as $entity) { - if ((string)$entity->apiKey == (string)$apiKey) continue; + if ((string)$entity->apiKey != (string)$apiKey) continue; return $entity; } From 549cd252fd48e38930dacf295d668dead6c2c586 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 12:13:06 +0200 Subject: [PATCH 08/42] request access from API key --- .../Domain/DataStructure/RequestAccess.php | 11 ++- .../DataStructure/RequestAccessFromApiKey.php | 38 ++++++++++ .../Domain/DataStructure/Value/ApiKey.php | 5 ++ .../Service/RequestAccessFromApiKey.php | 74 +++++++++++++++++++ .../DataStructure/RequestAccessFromApiKey.php | 47 ++++++++++++ .../Service/RequestAccessFromApiKey.php | 27 +++++++ .../RequestAccessFromApiKeyTest.php | 40 ++++++++++ .../DataStructure/RequestAccessTest.php | 12 +++ .../Service/RequestAccessFromApiKeyTest.php | 40 ++++++++++ 9 files changed, 291 insertions(+), 3 deletions(-) create mode 100644 component/Domain/DataStructure/RequestAccessFromApiKey.php create mode 100644 component/Domain/Service/RequestAccessFromApiKey.php create mode 100644 component/Fixture/DataStructure/RequestAccessFromApiKey.php create mode 100644 component/Fixture/Service/RequestAccessFromApiKey.php create mode 100644 test/Domain/DataStructure/RequestAccessFromApiKeyTest.php create mode 100644 test/Domain/Service/RequestAccessFromApiKeyTest.php diff --git a/component/Domain/DataStructure/RequestAccess.php b/component/Domain/DataStructure/RequestAccess.php index c678e56..5b1c7d5 100644 --- a/component/Domain/DataStructure/RequestAccess.php +++ b/component/Domain/DataStructure/RequestAccess.php @@ -25,7 +25,7 @@ abstract class RequestAccess extends \Phant\DataStructure\Abstract\Entity const LIFETIME = 900; // 15 min protected IdRequestAccess $id; - protected Application $application; + protected ?Application $application; protected AuthMethod $authMethod; protected RequestAccessState $state; protected ?User $user; @@ -33,7 +33,7 @@ abstract class RequestAccess extends \Phant\DataStructure\Abstract\Entity public function __construct( IdRequestAccess $id, - Application $application, + ?Application $application, AuthMethod $authMethod, RequestAccessState $state, ?User $user = null, @@ -53,11 +53,16 @@ public function getId(): IdRequestAccess return $this->id; } - public function getApplication(): Application + public function getApplication(): ?Application { return $this->application; } + public function setApplication(Application $application): void + { + $this->application = $application; + } + public function getAuthMethod(): AuthMethod { return $this->authMethod; diff --git a/component/Domain/DataStructure/RequestAccessFromApiKey.php b/component/Domain/DataStructure/RequestAccessFromApiKey.php new file mode 100644 index 0000000..74fd894 --- /dev/null +++ b/component/Domain/DataStructure/RequestAccessFromApiKey.php @@ -0,0 +1,38 @@ +apiKey = $apiKey; + } +} diff --git a/component/Domain/DataStructure/Value/ApiKey.php b/component/Domain/DataStructure/Value/ApiKey.php index 2002d39..5332523 100644 --- a/component/Domain/DataStructure/Value/ApiKey.php +++ b/component/Domain/DataStructure/Value/ApiKey.php @@ -12,6 +12,11 @@ public static function generate(): ApiKey return new ApiKey(self::generateRandomString(8) . '.' . self::generateRandomString(64)); } + public function check(string|self $apiKey): bool + { + return $this->value === (string)$apiKey; + } + private static function generateRandomString($length = 10) { $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; diff --git a/component/Domain/Service/RequestAccessFromApiKey.php b/component/Domain/Service/RequestAccessFromApiKey.php new file mode 100644 index 0000000..53fa759 --- /dev/null +++ b/component/Domain/Service/RequestAccessFromApiKey.php @@ -0,0 +1,74 @@ +serviceRequestAccess = $serviceRequestAccess; + $this->serviceAccessToken = $serviceAccessToken; + $this->repositoryApplication = $repositoryApplication; + } + + public function getAccessToken(string|ApiKey $apiKey): ?AccessToken + { + if (is_string($apiKey)) $apiKey = new ApiKey($apiKey); + + $requestAccess = $this->generate($apiKey); + + $application = $this->repositoryApplication->getFromApiKey($apiKey); + + if ( ! $application) return null; + + if ( ! $application->isHisApiKey($apiKey)) return null; + + $requestAccess->setApplication($application); + + $requestAccess->setState(new RequestAccessState(RequestAccessState::VERIFIED)); + + $this->serviceRequestAccess->set($requestAccess); + + $accessToken = $this->serviceAccessToken->getFromRequestAccessToken($requestAccess); + + return $accessToken; + } + + private function generate(ApiKey $apiKey): EntityRequestAccessFromApiKey + { + return new EntityRequestAccessFromApiKey( + IdRequestAccess::generate(), + new RequestAccessState(RequestAccessState::REQUESTED), + $apiKey + ); + } +} diff --git a/component/Fixture/DataStructure/RequestAccessFromApiKey.php b/component/Fixture/DataStructure/RequestAccessFromApiKey.php new file mode 100644 index 0000000..710b018 --- /dev/null +++ b/component/Fixture/DataStructure/RequestAccessFromApiKey.php @@ -0,0 +1,47 @@ +apiKey, + $lifetime + ); + } + + public static function getExpired(): EntityRequestAccessFromApiKey + { + return self::get(null, null, -9999); + } + + public static function getVerified(): EntityRequestAccessFromApiKey + { + return (self::get())->setState(new RequestAccessState(RequestAccessState::VERIFIED)); + } +} diff --git a/component/Fixture/Service/RequestAccessFromApiKey.php b/component/Fixture/Service/RequestAccessFromApiKey.php new file mode 100644 index 0000000..a4357ca --- /dev/null +++ b/component/Fixture/Service/RequestAccessFromApiKey.php @@ -0,0 +1,27 @@ +fixture = FixtureRequestAccessFromApiKey::get(); + } + + public function testConstruct(): void + { + $entity = new RequestAccessFromApiKey( + IdRequestAccess::generate(), + new RequestAccessState(RequestAccessState::REQUESTED), + FixtureApplication::get()->apiKey + ); + + $this->assertIsObject($entity); + $this->assertInstanceOf(RequestAccessFromApiKey::class, $entity); + } +} diff --git a/test/Domain/DataStructure/RequestAccessTest.php b/test/Domain/DataStructure/RequestAccessTest.php index ca1c15f..e21acc2 100644 --- a/test/Domain/DataStructure/RequestAccessTest.php +++ b/test/Domain/DataStructure/RequestAccessTest.php @@ -17,6 +17,7 @@ }; use Phant\Auth\Fixture\DataStructure\{ + Application as FixtureApplication, RequestAccessFromOtp as FixtureRequestAccessFromOtp, User as FixtureUser, }; @@ -51,6 +52,17 @@ public function testGetApplication(): void $this->assertInstanceOf(Application::class, $value); } + public function testSetApplication(): void + { + $this->fixture->setApplication(FixtureApplication::get()); + + $value = $this->fixture->getApplication(); + + $this->assertIsObject($value); + $this->assertInstanceOf(Application::class, $value); + $this->assertEquals(FixtureApplication::get(), $value); + } + public function testGetAuthMethod(): void { $value = $this->fixture->getAuthMethod(); diff --git a/test/Domain/Service/RequestAccessFromApiKeyTest.php b/test/Domain/Service/RequestAccessFromApiKeyTest.php new file mode 100644 index 0000000..6c70b8a --- /dev/null +++ b/test/Domain/Service/RequestAccessFromApiKeyTest.php @@ -0,0 +1,40 @@ +service = (new FixtureServiceRequestAccessFromApiKey())(); + } + + public function testGetAccessToken(): void + { + $entity = $this->service->getAccessToken( + FixtureApplication::get()->apiKey + ); + + $this->assertIsObject($entity); + $this->assertInstanceOf(AccessToken::class, $entity); + } + /* + public function testGetAccessTokenInvalid(): void + { + $entity = $this->service->getAccessToken( + $this->fixture, + '000000' + ); + + $this->assertNull($entity); + } + */ +} From a921d9b32bd8384db8cd6c5390aa6d17d0fb1fe9 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 13:28:42 +0200 Subject: [PATCH 09/42] Fix Request access from API key --- .../Domain/DataStructure/RequestAccessFromApiKey.php | 3 ++- component/Domain/Service/RequestAccessFromApiKey.php | 1 + .../Fixture/DataStructure/RequestAccessFromApiKey.php | 1 + .../DataStructure/RequestAccessFromApiKeyTest.php | 1 + test/Domain/Service/RequestAccessFromApiKeyTest.php | 11 +++++++---- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/component/Domain/DataStructure/RequestAccessFromApiKey.php b/component/Domain/DataStructure/RequestAccessFromApiKey.php index 74fd894..4d0a664 100644 --- a/component/Domain/DataStructure/RequestAccessFromApiKey.php +++ b/component/Domain/DataStructure/RequestAccessFromApiKey.php @@ -19,6 +19,7 @@ final class RequestAccessFromApiKey extends \Phant\Auth\Domain\DataStructure\Req public function __construct( IdRequestAccess $id, + ?Application $application, RequestAccessState $state, ApiKey $apiKey, int $lifetime = self::LIFETIME @@ -26,7 +27,7 @@ public function __construct( { parent::__construct( $id, - null, + $application, new AuthMethod(AuthMethod::API_KEY), $state, null, diff --git a/component/Domain/Service/RequestAccessFromApiKey.php b/component/Domain/Service/RequestAccessFromApiKey.php index 53fa759..a9f4585 100644 --- a/component/Domain/Service/RequestAccessFromApiKey.php +++ b/component/Domain/Service/RequestAccessFromApiKey.php @@ -67,6 +67,7 @@ private function generate(ApiKey $apiKey): EntityRequestAccessFromApiKey { return new EntityRequestAccessFromApiKey( IdRequestAccess::generate(), + null, new RequestAccessState(RequestAccessState::REQUESTED), $apiKey ); diff --git a/component/Fixture/DataStructure/RequestAccessFromApiKey.php b/component/Fixture/DataStructure/RequestAccessFromApiKey.php index 710b018..c57e80a 100644 --- a/component/Fixture/DataStructure/RequestAccessFromApiKey.php +++ b/component/Fixture/DataStructure/RequestAccessFromApiKey.php @@ -29,6 +29,7 @@ public static function get(?IdRequestAccess $id = null, ?RequestAccessState $sta return new EntityRequestAccessFromApiKey( $id, + null, $state, FixtureApplication::get()->apiKey, $lifetime diff --git a/test/Domain/DataStructure/RequestAccessFromApiKeyTest.php b/test/Domain/DataStructure/RequestAccessFromApiKeyTest.php index a66e9ad..d346a43 100644 --- a/test/Domain/DataStructure/RequestAccessFromApiKeyTest.php +++ b/test/Domain/DataStructure/RequestAccessFromApiKeyTest.php @@ -30,6 +30,7 @@ public function testConstruct(): void { $entity = new RequestAccessFromApiKey( IdRequestAccess::generate(), + null, new RequestAccessState(RequestAccessState::REQUESTED), FixtureApplication::get()->apiKey ); diff --git a/test/Domain/Service/RequestAccessFromApiKeyTest.php b/test/Domain/Service/RequestAccessFromApiKeyTest.php index 6c70b8a..14e47f3 100644 --- a/test/Domain/Service/RequestAccessFromApiKeyTest.php +++ b/test/Domain/Service/RequestAccessFromApiKeyTest.php @@ -3,11 +3,14 @@ namespace Test\Domain\Service; use Phant\Auth\Domain\DataStructure\AccessToken; +use Phant\Auth\Domain\DataStructure\Value\ApiKey; use Phant\Auth\Domain\Service\RequestAccessFromApiKey as ServiceRequestAccessFromApiKey; use Phant\Auth\Fixture\DataStructure\Application as FixtureApplication; use Phant\Auth\Fixture\Service\RequestAccessFromApiKey as FixtureServiceRequestAccessFromApiKey; +use Phant\Error\NotFound; + final class RequestAccessFromApiKeyTest extends \PHPUnit\Framework\TestCase { protected ServiceRequestAccessFromApiKey $service; @@ -26,15 +29,15 @@ public function testGetAccessToken(): void $this->assertIsObject($entity); $this->assertInstanceOf(AccessToken::class, $entity); } - /* + public function testGetAccessTokenInvalid(): void { + $this->expectException(NotFound::class); + $entity = $this->service->getAccessToken( - $this->fixture, - '000000' + ApiKey::generate() ); $this->assertNull($entity); } - */ } From 6c69ec82219caf3118dca71773ed5f2116197680 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 13:31:54 +0200 Subject: [PATCH 10/42] Cleaning --- component/Domain/Service/RequestAccessFromApiKey.php | 1 - component/Domain/Service/RequestAccessFromOtp.php | 1 - 2 files changed, 2 deletions(-) diff --git a/component/Domain/Service/RequestAccessFromApiKey.php b/component/Domain/Service/RequestAccessFromApiKey.php index a9f4585..b3ab53e 100644 --- a/component/Domain/Service/RequestAccessFromApiKey.php +++ b/component/Domain/Service/RequestAccessFromApiKey.php @@ -17,7 +17,6 @@ }; use Phant\Auth\Domain\DataStructure\Value\{ ApiKey, - AuthMethod, IdRequestAccess, RequestAccessState, RequestAccessToken, diff --git a/component/Domain/Service/RequestAccessFromOtp.php b/component/Domain/Service/RequestAccessFromOtp.php index b746c0d..30ac217 100644 --- a/component/Domain/Service/RequestAccessFromOtp.php +++ b/component/Domain/Service/RequestAccessFromOtp.php @@ -16,7 +16,6 @@ User, }; use Phant\Auth\Domain\DataStructure\Value\{ - AuthMethod, IdRequestAccess, Otp, RequestAccessState, From 134e4acd229caba63e5d2fa3659ea20e3469c4fe Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 13:37:19 +0200 Subject: [PATCH 11/42] Cleaning --- .../Fixture/DataStructure/RequestAccessFromApiKey.php | 9 +-------- component/Fixture/DataStructure/RequestAccessFromOtp.php | 8 +------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/component/Fixture/DataStructure/RequestAccessFromApiKey.php b/component/Fixture/DataStructure/RequestAccessFromApiKey.php index c57e80a..dc735a2 100644 --- a/component/Fixture/DataStructure/RequestAccessFromApiKey.php +++ b/component/Fixture/DataStructure/RequestAccessFromApiKey.php @@ -3,16 +3,9 @@ namespace Phant\Auth\Fixture\DataStructure; -use Phant\Auth\Domain\DataStructure\{ - Application, - RequestAccessFromApiKey as EntityRequestAccessFromApiKey, - User, -}; +use Phant\Auth\Domain\DataStructure\RequestAccessFromApiKey as EntityRequestAccessFromApiKey; use Phant\Auth\Domain\DataStructure\Value\{ - AuthMethod, IdRequestAccess, - Jwt, - Otp, RequestAccessState, }; diff --git a/component/Fixture/DataStructure/RequestAccessFromOtp.php b/component/Fixture/DataStructure/RequestAccessFromOtp.php index a29c812..d757bb4 100644 --- a/component/Fixture/DataStructure/RequestAccessFromOtp.php +++ b/component/Fixture/DataStructure/RequestAccessFromOtp.php @@ -3,15 +3,9 @@ namespace Phant\Auth\Fixture\DataStructure; -use Phant\Auth\Domain\DataStructure\{ - Application, - RequestAccessFromOtp as EntityRequestAccessFromOtp, - User, -}; +use Phant\Auth\Domain\DataStructure\RequestAccessFromOtp as EntityRequestAccessFromOtp; use Phant\Auth\Domain\DataStructure\Value\{ - AuthMethod, IdRequestAccess, - Jwt, Otp, RequestAccessState, }; From b364cae6c229f1c966e8a6e4adc67805ab38e43d Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 13:43:09 +0200 Subject: [PATCH 12/42] Test --- test/Domain/DataStructure/Value/ApiKeyTest.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/Domain/DataStructure/Value/ApiKeyTest.php b/test/Domain/DataStructure/Value/ApiKeyTest.php index 7735ffa..5a1c8bb 100644 --- a/test/Domain/DataStructure/Value/ApiKeyTest.php +++ b/test/Domain/DataStructure/Value/ApiKeyTest.php @@ -14,4 +14,22 @@ public function testGenerate(): void $this->assertIsObject($value); $this->assertInstanceOf(ApiKey::class, $value); } + + public function testCheck(): void + { + $value = ApiKey::generate(); + $result = $value->check($value); + + $this->assertIsBool($result); + $this->assertEquals(true, $result); + } + + public function testCheckInvalid(): void + { + $value = ApiKey::generate(); + $result = $value->check(ApiKey::generate()); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + } } From 4fc9f7021fabaee0246c1eabddf57e9566816901 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 13:43:16 +0200 Subject: [PATCH 13/42] Cleaning --- test/Domain/DataStructure/RequestAccessFromApiKeyTest.php | 1 - test/Domain/DataStructure/RequestAccessFromOtpTest.php | 1 - 2 files changed, 2 deletions(-) diff --git a/test/Domain/DataStructure/RequestAccessFromApiKeyTest.php b/test/Domain/DataStructure/RequestAccessFromApiKeyTest.php index d346a43..b23f041 100644 --- a/test/Domain/DataStructure/RequestAccessFromApiKeyTest.php +++ b/test/Domain/DataStructure/RequestAccessFromApiKeyTest.php @@ -5,7 +5,6 @@ use Phant\Auth\Domain\DataStructure\RequestAccessFromApiKey; use Phant\Auth\Domain\DataStructure\Value\{ - AuthMethod, IdRequestAccess, Otp, RequestAccessState, diff --git a/test/Domain/DataStructure/RequestAccessFromOtpTest.php b/test/Domain/DataStructure/RequestAccessFromOtpTest.php index 5a2287f..7c9ac1c 100644 --- a/test/Domain/DataStructure/RequestAccessFromOtpTest.php +++ b/test/Domain/DataStructure/RequestAccessFromOtpTest.php @@ -5,7 +5,6 @@ use Phant\Auth\Domain\DataStructure\RequestAccessFromOtp; use Phant\Auth\Domain\DataStructure\Value\{ - AuthMethod, IdRequestAccess, Otp, RequestAccessState, From f4b8c5a4e745c0bf8da39faefcb8978547c99cf9 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 13:54:55 +0200 Subject: [PATCH 14/42] Request access from third party --- .../RequestAccessFromThirdParty.php | 35 +++++++++ .../Service/RequestAccessFromThirdParty.php | 71 +++++++++++++++++++ .../RequestAccessFromThirdParty.php | 43 +++++++++++ .../Service/RequestAccessFromThirdParty.php | 22 ++++++ .../RequestAccessFromThirdPartyTest.php | 38 ++++++++++ .../RequestAccessFromThirdPartyTest.php | 67 +++++++++++++++++ 6 files changed, 276 insertions(+) create mode 100644 component/Domain/DataStructure/RequestAccessFromThirdParty.php create mode 100644 component/Domain/Service/RequestAccessFromThirdParty.php create mode 100644 component/Fixture/DataStructure/RequestAccessFromThirdParty.php create mode 100644 component/Fixture/Service/RequestAccessFromThirdParty.php create mode 100644 test/Domain/DataStructure/RequestAccessFromThirdPartyTest.php create mode 100644 test/Domain/Service/RequestAccessFromThirdPartyTest.php diff --git a/component/Domain/DataStructure/RequestAccessFromThirdParty.php b/component/Domain/DataStructure/RequestAccessFromThirdParty.php new file mode 100644 index 0000000..2184fe6 --- /dev/null +++ b/component/Domain/DataStructure/RequestAccessFromThirdParty.php @@ -0,0 +1,35 @@ +serviceRequestAccess = $serviceRequestAccess; + $this->serviceAccessToken = $serviceAccessToken; + } + + public function generate(Application $application): RequestAccessToken + { + $requestAccess = new EntityRequestAccessFromThirdParty( + IdRequestAccess::generate(), + $application, + new RequestAccessState(RequestAccessState::REQUESTED), + null + ); + + $requestAccessToken = $this->serviceRequestAccess->getToken($requestAccess); + + $this->serviceRequestAccess->set($requestAccess); + + return $requestAccessToken; + } + + public function verify(RequestAccessToken $requestAccessToken, User $user): void + { + $requestAccess = $this->serviceRequestAccess->getFromToken($requestAccessToken); + + $requestAccess->setUser($user); + $requestAccess->setState(new RequestAccessState(RequestAccessState::VERIFIED)); + + $this->serviceRequestAccess->set($requestAccess); + } + + public function getAccessToken(RequestAccessToken $requestAccessToken): ?AccessToken + { + $requestAccess = $this->serviceRequestAccess->getFromToken($requestAccessToken); + + $accessToken = $this->serviceAccessToken->getFromRequestAccessToken($requestAccess); + + return $accessToken; + } +} diff --git a/component/Fixture/DataStructure/RequestAccessFromThirdParty.php b/component/Fixture/DataStructure/RequestAccessFromThirdParty.php new file mode 100644 index 0000000..148485e --- /dev/null +++ b/component/Fixture/DataStructure/RequestAccessFromThirdParty.php @@ -0,0 +1,43 @@ +setUser(FixtureUser::get()) + ->setState(new RequestAccessState(RequestAccessState::VERIFIED)); + } +} diff --git a/component/Fixture/Service/RequestAccessFromThirdParty.php b/component/Fixture/Service/RequestAccessFromThirdParty.php new file mode 100644 index 0000000..86961ef --- /dev/null +++ b/component/Fixture/Service/RequestAccessFromThirdParty.php @@ -0,0 +1,22 @@ +fixture = FixtureRequestAccessFromThirdParty::get(); + } + + public function testConstruct(): void + { + $entity = new RequestAccessFromThirdParty( + IdRequestAccess::generate(), + FixtureApplication::get(), + new RequestAccessState(RequestAccessState::REQUESTED), + null + ); + + $this->assertIsObject($entity); + $this->assertInstanceOf(RequestAccessFromThirdParty::class, $entity); + } +} diff --git a/test/Domain/Service/RequestAccessFromThirdPartyTest.php b/test/Domain/Service/RequestAccessFromThirdPartyTest.php new file mode 100644 index 0000000..5785a59 --- /dev/null +++ b/test/Domain/Service/RequestAccessFromThirdPartyTest.php @@ -0,0 +1,67 @@ +service = (new FixtureServiceRequestAccessFromThirdParty())(); + $this->fixture = $this->service->generate( + FixtureApplication::get() + ); + } + + public function testGenerate(): void + { + $this->assertIsObject($this->fixture); + $this->assertInstanceOf(RequestAccessToken::class, $this->fixture); + } + + public function testVerify(): void + { + $this->service->verify( + $this->fixture, + FixtureUser::get() + ); + + $this->addToAssertionCount(1); + } + + public function testGetAccessToken(): void + { + $this->service->verify( + $this->fixture, + FixtureUser::get() + ); + + $entity = $this->service->getAccessToken( + $this->fixture + ); + + $this->assertIsObject($entity); + $this->assertInstanceOf(AccessToken::class, $entity); + } +} From daf792ff213f776e06b6be16002626defa174bf2 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 15:15:34 +0200 Subject: [PATCH 15/42] Refacto --- component/Domain/DataStructure/Application.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/component/Domain/DataStructure/Application.php b/component/Domain/DataStructure/Application.php index 21503f1..363f298 100644 --- a/component/Domain/DataStructure/Application.php +++ b/component/Domain/DataStructure/Application.php @@ -18,12 +18,16 @@ final class Application extends \Phant\DataStructure\Abstract\Entity public ApiKey $apiKey; public function __construct( - IdApplication $id, - ApplicationName $name, - ?Logo $logo, - ApiKey $apiKey + null|string|IdApplication $id, + null|string|ApplicationName $name, + null|string|Logo $logo, + string|ApiKey $apiKey ) { + if (is_string($id)) $id = new IdApplication($id); + if (is_string($name)) $name = new ApplicationName($name); + if (is_string($logo)) $logo = new Logo($logo); + $this->id = $id; $this->name = $name; $this->logo = $logo; From 75fa7f8634997dd7c433b0ca9fad099bd2e4bcf3 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 15:15:52 +0200 Subject: [PATCH 16/42] Refacto --- .../Service/RequestAccessFromThirdParty.php | 4 ++-- .../RequestAccessFromThirdPartyTest.php | 23 +++++++++++++++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/component/Domain/Service/RequestAccessFromThirdParty.php b/component/Domain/Service/RequestAccessFromThirdParty.php index 5c71b3b..43f7a2f 100644 --- a/component/Domain/Service/RequestAccessFromThirdParty.php +++ b/component/Domain/Service/RequestAccessFromThirdParty.php @@ -50,12 +50,12 @@ public function generate(Application $application): RequestAccessToken return $requestAccessToken; } - public function verify(RequestAccessToken $requestAccessToken, User $user): void + public function verify(RequestAccessToken $requestAccessToken, User $user, bool $isAuthorized): void { $requestAccess = $this->serviceRequestAccess->getFromToken($requestAccessToken); $requestAccess->setUser($user); - $requestAccess->setState(new RequestAccessState(RequestAccessState::VERIFIED)); + $requestAccess->setState(new RequestAccessState($isAuthorized ? RequestAccessState::VERIFIED : RequestAccessState::REFUSED)); $this->serviceRequestAccess->set($requestAccess); } diff --git a/test/Domain/Service/RequestAccessFromThirdPartyTest.php b/test/Domain/Service/RequestAccessFromThirdPartyTest.php index 5785a59..2885930 100644 --- a/test/Domain/Service/RequestAccessFromThirdPartyTest.php +++ b/test/Domain/Service/RequestAccessFromThirdPartyTest.php @@ -21,6 +21,8 @@ RequestAccessFromThirdParty as FixtureServiceRequestAccessFromThirdParty, }; +use Phant\Error\NotCompliant; + final class RequestAccessFromThirdPartyTest extends \PHPUnit\Framework\TestCase { protected ServiceRequestAccessFromThirdParty $service; @@ -44,7 +46,8 @@ public function testVerify(): void { $this->service->verify( $this->fixture, - FixtureUser::get() + FixtureUser::get(), + true ); $this->addToAssertionCount(1); @@ -54,7 +57,8 @@ public function testGetAccessToken(): void { $this->service->verify( $this->fixture, - FixtureUser::get() + FixtureUser::get(), + true ); $entity = $this->service->getAccessToken( @@ -64,4 +68,19 @@ public function testGetAccessToken(): void $this->assertIsObject($entity); $this->assertInstanceOf(AccessToken::class, $entity); } + + public function testGetAccessTokenInvalid(): void + { + $this->expectException(NotCompliant::class); + + $this->service->verify( + $this->fixture, + FixtureUser::get(), + false + ); + + $entity = $this->service->getAccessToken( + $this->fixture + ); + } } From 8b3ec984564cdc28e0e1f7f898b1b77060ac9e63 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 15:41:09 +0200 Subject: [PATCH 17/42] Refacto --- component/Domain/Service/AccessToken.php | 4 ++-- test/Domain/Service/RequestAccessFromThirdPartyTest.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/component/Domain/Service/AccessToken.php b/component/Domain/Service/AccessToken.php index ec86442..31bdeb6 100644 --- a/component/Domain/Service/AccessToken.php +++ b/component/Domain/Service/AccessToken.php @@ -15,7 +15,7 @@ }; use Phant\Auth\Domain\DataStructure\Application; -use Phant\Error\NotCompliant; +use Phant\Error\NotAuthorized; final class AccessToken { @@ -53,7 +53,7 @@ public function getFromRequestAccessToken(RequestAccess $requestAccess): EntityA { // Check request access status if (!$requestAccess->canBeSetStateTo(new RequestAccessState(RequestAccessState::GRANTED))) { - throw new NotCompliant('The access request is invalid'); + throw new NotAuthorized('The access request is invalid'); } // Generate new access token diff --git a/test/Domain/Service/RequestAccessFromThirdPartyTest.php b/test/Domain/Service/RequestAccessFromThirdPartyTest.php index 2885930..4d05fcc 100644 --- a/test/Domain/Service/RequestAccessFromThirdPartyTest.php +++ b/test/Domain/Service/RequestAccessFromThirdPartyTest.php @@ -21,7 +21,7 @@ RequestAccessFromThirdParty as FixtureServiceRequestAccessFromThirdParty, }; -use Phant\Error\NotCompliant; +use Phant\Error\NotAuthorized; final class RequestAccessFromThirdPartyTest extends \PHPUnit\Framework\TestCase { @@ -71,7 +71,7 @@ public function testGetAccessToken(): void public function testGetAccessTokenInvalid(): void { - $this->expectException(NotCompliant::class); + $this->expectException(NotAuthorized::class); $this->service->verify( $this->fixture, From 66d2512c0a53bb71463872fa211e91d609ab2095 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 15:41:16 +0200 Subject: [PATCH 18/42] Refacto OTP --- .../DataStructure/RequestAccessFromOtp.php | 19 +++++++ .../Domain/Service/RequestAccessFromOtp.php | 28 ++++++++-- .../DataStructure/RequestAccessFromOtp.php | 2 + .../RequestAccessFromOtpTest.php | 46 ++++++++++++++- test/Domain/Service/AccessTokenTest.php | 4 +- .../Service/RequestAccessFromOtpTest.php | 56 ++++++++++++++++--- 6 files changed, 141 insertions(+), 14 deletions(-) diff --git a/component/Domain/DataStructure/RequestAccessFromOtp.php b/component/Domain/DataStructure/RequestAccessFromOtp.php index 50c1259..796e2f0 100644 --- a/component/Domain/DataStructure/RequestAccessFromOtp.php +++ b/component/Domain/DataStructure/RequestAccessFromOtp.php @@ -14,11 +14,13 @@ Otp, }; +use Phant\Error\NotAuthorized; use Phant\Error\NotCompliant; final class RequestAccessFromOtp extends \Phant\Auth\Domain\DataStructure\RequestAccess { protected Otp $otp; + protected int $numberOfRemainingAttempts; public function __construct( IdRequestAccess $id, @@ -26,9 +28,14 @@ public function __construct( RequestAccessState $state, User $user, Otp $otp, + int $numberOfAttemptsLimit, int $lifetime = self::LIFETIME ) { + if ($numberOfAttemptsLimit < 1) { + throw new NotCompliant('the number of attempts must be at least 1'); + } + parent::__construct( $id, $application, @@ -39,12 +46,24 @@ public function __construct( ); $this->otp = $otp; + $this->numberOfRemainingAttempts = $numberOfAttemptsLimit; + } + + public function getNumberOfRemainingAttempts(): int + { + return $this->numberOfRemainingAttempts; } public function checkOtp(string|Otp $otp): bool { + if ($this->numberOfRemainingAttempts <= 0) { + throw new NotAuthorized('The number of attempts is reach'); + } + if (is_string($otp)) $otp = new Otp($otp); + $this->numberOfRemainingAttempts--; + return $this->otp->check($otp); } } diff --git a/component/Domain/Service/RequestAccessFromOtp.php b/component/Domain/Service/RequestAccessFromOtp.php index 30ac217..5599363 100644 --- a/component/Domain/Service/RequestAccessFromOtp.php +++ b/component/Domain/Service/RequestAccessFromOtp.php @@ -39,7 +39,7 @@ public function __construct( $this->userNotification = $userNotification; } - public function generate(User $user, Application $application): RequestAccessToken + public function generate(User $user, Application $application, int $numberOfAttemptsLimit = 3): RequestAccessToken { $otp = Otp::generate(); @@ -48,7 +48,8 @@ public function generate(User $user, Application $application): RequestAccessTok $application, new RequestAccessState(RequestAccessState::REQUESTED), $user, - $otp + $otp, + $numberOfAttemptsLimit ); $requestAccessToken = $this->serviceRequestAccess->getToken($requestAccess); @@ -60,18 +61,37 @@ public function generate(User $user, Application $application): RequestAccessTok return $requestAccessToken; } - public function getAccessToken(RequestAccessToken $requestAccessToken, string|Otp $otp): ?AccessToken + public function verify(RequestAccessToken $requestAccessToken, string|Otp $otp): bool { $requestAccess = $this->serviceRequestAccess->getFromToken($requestAccessToken); if (is_string($otp)) $otp = new Otp($otp); - if ( ! $requestAccess->checkOtp($otp)) return null; + if ( ! $requestAccess->checkOtp($otp)) { + + $requestAccess->setState(new RequestAccessState(RequestAccessState::REFUSED)); + + return false; + } $requestAccess->setState(new RequestAccessState(RequestAccessState::VERIFIED)); $this->serviceRequestAccess->set($requestAccess); + return true; + } + + public function getNumberOfRemainingAttempts(RequestAccessToken $requestAccessToken): int + { + $requestAccess = $this->serviceRequestAccess->getFromToken($requestAccessToken); + + return $requestAccess->getNumberOfRemainingAttempts($requestAccess); + } + + public function getAccessToken(RequestAccessToken $requestAccessToken): ?AccessToken + { + $requestAccess = $this->serviceRequestAccess->getFromToken($requestAccessToken); + $accessToken = $this->serviceAccessToken->getFromRequestAccessToken($requestAccess); return $accessToken; diff --git a/component/Fixture/DataStructure/RequestAccessFromOtp.php b/component/Fixture/DataStructure/RequestAccessFromOtp.php index d757bb4..779afdd 100644 --- a/component/Fixture/DataStructure/RequestAccessFromOtp.php +++ b/component/Fixture/DataStructure/RequestAccessFromOtp.php @@ -20,6 +20,7 @@ public static function get(?IdRequestAccess $id = null, ?RequestAccessState $sta if (is_null($id)) $id = new IdRequestAccess('2362ecd5-ac3b-4806-817a-966eaaf308f0'); if (is_null($state)) $state = new RequestAccessState(RequestAccessState::REQUESTED); if (is_null($lifetime)) $lifetime = EntityRequestAccessFromOtp::LIFETIME; + $numberOfAttemptsLimit = 3; return new EntityRequestAccessFromOtp( $id, @@ -27,6 +28,7 @@ public static function get(?IdRequestAccess $id = null, ?RequestAccessState $sta $state, FixtureUser::get(), new Otp('123456'), + $numberOfAttemptsLimit, $lifetime ); } diff --git a/test/Domain/DataStructure/RequestAccessFromOtpTest.php b/test/Domain/DataStructure/RequestAccessFromOtpTest.php index 7c9ac1c..9997a2e 100644 --- a/test/Domain/DataStructure/RequestAccessFromOtpTest.php +++ b/test/Domain/DataStructure/RequestAccessFromOtpTest.php @@ -16,6 +16,8 @@ User as FixtureUser, }; +use Phant\Error\NotAuthorized; + final class RequestAccessFromOtpTest extends \PHPUnit\Framework\TestCase { protected RequestAccessFromOtp $fixture; @@ -32,7 +34,8 @@ public function testConstruct(): void FixtureApplication::get(), new RequestAccessState(RequestAccessState::REQUESTED), FixtureUser::get(), - Otp::generate() + Otp::generate(), + 3 ); $this->assertIsObject($entity); @@ -48,4 +51,45 @@ public function testCheckOtp(): void $this->assertIsBool($result); $this->assertEquals(true, $result); } + + public function testGetNumberOfRemainingAttempts(): void + { + $result = $this->fixture->getNumberOfRemainingAttempts(); + + $this->assertIsInt($result); + $this->assertEquals(3, $result); + } + + public function testCheckOtpNotAuthorized(): void + { + $this->expectException(NotAuthorized::class); + + $result = $this->fixture->checkOtp( + '000000' + ); + $this->assertEquals(false, $result); + + $result = $this->fixture->getNumberOfRemainingAttempts(); + $this->assertEquals(2, $result); + + $result = $this->fixture->checkOtp( + '000000' + ); + $this->assertEquals(false, $result); + + $result = $this->fixture->getNumberOfRemainingAttempts(); + $this->assertEquals(1, $result); + + $result = $this->fixture->checkOtp( + '000000' + ); + $this->assertEquals(false, $result); + + $result = $this->fixture->getNumberOfRemainingAttempts(); + $this->assertEquals(0, $result); + + $this->fixture->checkOtp( + '000000' + ); + } } diff --git a/test/Domain/Service/AccessTokenTest.php b/test/Domain/Service/AccessTokenTest.php index f3f286c..0785b8b 100644 --- a/test/Domain/Service/AccessTokenTest.php +++ b/test/Domain/Service/AccessTokenTest.php @@ -13,7 +13,7 @@ }; use Phant\Auth\Fixture\Service\AccessToken as FixtureServiceAccessToken; -use Phant\Error\NotCompliant; +use Phant\Error\NotAuthorized; final class AccessTokenTest extends \PHPUnit\Framework\TestCase { @@ -63,7 +63,7 @@ public function testGetFromRequestAccessToken(): void public function testGetFromRequestAccessTokenInvalid(): void { - $this->expectException(NotCompliant::class); + $this->expectException(NotAuthorized::class); $entity = $this->service->getFromRequestAccessToken( FixtureRequestAccessFromOtp::get() diff --git a/test/Domain/Service/RequestAccessFromOtpTest.php b/test/Domain/Service/RequestAccessFromOtpTest.php index 55b381e..fd4aaf1 100644 --- a/test/Domain/Service/RequestAccessFromOtpTest.php +++ b/test/Domain/Service/RequestAccessFromOtpTest.php @@ -23,6 +23,8 @@ }; use Phant\Cache\SimpleCache; +use Phant\Error\NotCompliant; + final class RequestAccessFromOtpTest extends \PHPUnit\Framework\TestCase { protected ServiceRequestAccessFromOtp $service; @@ -45,26 +47,66 @@ public function testGenerate(): void $this->assertInstanceOf(RequestAccessToken::class, $this->fixture); } - public function testGetAccessToken(): void + public function testGenerateInvalid(): void + { + $this->expectException(NotCompliant::class); + + $this->service->generate( + FixtureUser::get(), + FixtureApplication::get(), + 0 + ); + } + + public function testVerify(): void { $otp = $this->cache->get((string)$this->fixture); - $entity = $this->service->getAccessToken( + $result = $this->service->verify( $this->fixture, $otp ); - $this->assertIsObject($entity); - $this->assertInstanceOf(AccessToken::class, $entity); + $this->assertIsBool($result); + $this->assertEquals(true, $result); } - public function testGetAccessTokenInvalid(): void + public function testVerifyInvalid(): void { - $entity = $this->service->getAccessToken( + $result = $this->service->verify( $this->fixture, '000000' ); - $this->assertNull($entity); + $this->assertIsBool($result); + $this->assertEquals(false, $result); + } + + public function testGetNumberOfRemainingAttempts(): void + { + $result = $this->service->getNumberOfRemainingAttempts( + $this->fixture + ); + + $this->assertIsInt($result); + $this->assertEquals(3, $result); + } + + public function testGetAccessToken(): void + { + $otp = $this->cache->get((string)$this->fixture); + + $result = $this->service->verify( + $this->fixture, + $otp + ); + + $entity = $this->service->getAccessToken( + $this->fixture, + $otp + ); + + $this->assertIsObject($entity); + $this->assertInstanceOf(AccessToken::class, $entity); } } From 57619afde5eea2533c26dc29be90d2c02f993dcd Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 15:48:48 +0200 Subject: [PATCH 19/42] Refacto request access interface --- .../DataStructure/RequestAccessFromApiKey.php | 3 +-- .../DataStructure/RequestAccessFromOtp.php | 3 +-- .../RequestAccessFromThirdParty.php | 3 +-- .../Domain/Service/RequestAccessFromApiKey.php | 1 - .../Domain/Service/RequestAccessFromOtp.php | 1 - .../Service/RequestAccessFromThirdParty.php | 1 - .../DataStructure/RequestAccessFromApiKey.php | 18 +++++++----------- .../DataStructure/RequestAccessFromOtp.php | 12 +++++------- .../RequestAccessFromThirdParty.php | 13 ++++--------- .../RequestAccessFromApiKeyTest.php | 1 - .../DataStructure/RequestAccessFromOtpTest.php | 1 - .../RequestAccessFromThirdPartyTest.php | 1 - test/Domain/Service/RequestAccessTest.php | 12 ++++++++++++ 13 files changed, 31 insertions(+), 39 deletions(-) diff --git a/component/Domain/DataStructure/RequestAccessFromApiKey.php b/component/Domain/DataStructure/RequestAccessFromApiKey.php index 4d0a664..a2d682d 100644 --- a/component/Domain/DataStructure/RequestAccessFromApiKey.php +++ b/component/Domain/DataStructure/RequestAccessFromApiKey.php @@ -18,7 +18,6 @@ final class RequestAccessFromApiKey extends \Phant\Auth\Domain\DataStructure\Req protected ApiKey $apiKey; public function __construct( - IdRequestAccess $id, ?Application $application, RequestAccessState $state, ApiKey $apiKey, @@ -26,7 +25,7 @@ public function __construct( ) { parent::__construct( - $id, + IdRequestAccess::generate(), $application, new AuthMethod(AuthMethod::API_KEY), $state, diff --git a/component/Domain/DataStructure/RequestAccessFromOtp.php b/component/Domain/DataStructure/RequestAccessFromOtp.php index 796e2f0..717ef0b 100644 --- a/component/Domain/DataStructure/RequestAccessFromOtp.php +++ b/component/Domain/DataStructure/RequestAccessFromOtp.php @@ -23,7 +23,6 @@ final class RequestAccessFromOtp extends \Phant\Auth\Domain\DataStructure\Reques protected int $numberOfRemainingAttempts; public function __construct( - IdRequestAccess $id, Application $application, RequestAccessState $state, User $user, @@ -37,7 +36,7 @@ public function __construct( } parent::__construct( - $id, + IdRequestAccess::generate(), $application, new AuthMethod(AuthMethod::OTP), $state, diff --git a/component/Domain/DataStructure/RequestAccessFromThirdParty.php b/component/Domain/DataStructure/RequestAccessFromThirdParty.php index 2184fe6..47dd287 100644 --- a/component/Domain/DataStructure/RequestAccessFromThirdParty.php +++ b/component/Domain/DataStructure/RequestAccessFromThirdParty.php @@ -16,7 +16,6 @@ final class RequestAccessFromThirdParty extends \Phant\Auth\Domain\DataStructure\RequestAccess { public function __construct( - IdRequestAccess $id, Application $application, RequestAccessState $state, ?User $user, @@ -24,7 +23,7 @@ public function __construct( ) { parent::__construct( - $id, + IdRequestAccess::generate(), $application, new AuthMethod(AuthMethod::THIRD_PARTY), $state, diff --git a/component/Domain/Service/RequestAccessFromApiKey.php b/component/Domain/Service/RequestAccessFromApiKey.php index b3ab53e..d843fd9 100644 --- a/component/Domain/Service/RequestAccessFromApiKey.php +++ b/component/Domain/Service/RequestAccessFromApiKey.php @@ -65,7 +65,6 @@ public function getAccessToken(string|ApiKey $apiKey): ?AccessToken private function generate(ApiKey $apiKey): EntityRequestAccessFromApiKey { return new EntityRequestAccessFromApiKey( - IdRequestAccess::generate(), null, new RequestAccessState(RequestAccessState::REQUESTED), $apiKey diff --git a/component/Domain/Service/RequestAccessFromOtp.php b/component/Domain/Service/RequestAccessFromOtp.php index 5599363..2c3f35f 100644 --- a/component/Domain/Service/RequestAccessFromOtp.php +++ b/component/Domain/Service/RequestAccessFromOtp.php @@ -44,7 +44,6 @@ public function generate(User $user, Application $application, int $numberOfAtte $otp = Otp::generate(); $requestAccess = new EntityRequestAccessFromOtp( - IdRequestAccess::generate(), $application, new RequestAccessState(RequestAccessState::REQUESTED), $user, diff --git a/component/Domain/Service/RequestAccessFromThirdParty.php b/component/Domain/Service/RequestAccessFromThirdParty.php index 43f7a2f..40f5e25 100644 --- a/component/Domain/Service/RequestAccessFromThirdParty.php +++ b/component/Domain/Service/RequestAccessFromThirdParty.php @@ -37,7 +37,6 @@ public function __construct( public function generate(Application $application): RequestAccessToken { $requestAccess = new EntityRequestAccessFromThirdParty( - IdRequestAccess::generate(), $application, new RequestAccessState(RequestAccessState::REQUESTED), null diff --git a/component/Fixture/DataStructure/RequestAccessFromApiKey.php b/component/Fixture/DataStructure/RequestAccessFromApiKey.php index dc735a2..d0da37e 100644 --- a/component/Fixture/DataStructure/RequestAccessFromApiKey.php +++ b/component/Fixture/DataStructure/RequestAccessFromApiKey.php @@ -4,24 +4,18 @@ namespace Phant\Auth\Fixture\DataStructure; use Phant\Auth\Domain\DataStructure\RequestAccessFromApiKey as EntityRequestAccessFromApiKey; -use Phant\Auth\Domain\DataStructure\Value\{ - IdRequestAccess, - RequestAccessState, -}; +use Phant\Auth\Domain\DataStructure\Value\RequestAccessState; use Phant\Auth\Fixture\DataStructure\Application as FixtureApplication; -use Phant\Auth\Fixture\DataStructure\User as FixtureUser; final class RequestAccessFromApiKey { - public static function get(?IdRequestAccess $id = null, ?RequestAccessState $state = null, int $lifetime = null): EntityRequestAccessFromApiKey + public static function get(?RequestAccessState $state = null, int $lifetime = null): EntityRequestAccessFromApiKey { - if (is_null($id)) $id = new IdRequestAccess('2362ecd5-ac3b-4806-817a-966eaaf308f0'); if (is_null($state)) $state = new RequestAccessState(RequestAccessState::REQUESTED); if (is_null($lifetime)) $lifetime = EntityRequestAccessFromApiKey::LIFETIME; return new EntityRequestAccessFromApiKey( - $id, null, $state, FixtureApplication::get()->apiKey, @@ -29,13 +23,15 @@ public static function get(?IdRequestAccess $id = null, ?RequestAccessState $sta ); } - public static function getExpired(): EntityRequestAccessFromApiKey + public static function getExpired(?RequestAccessState $state = null): EntityRequestAccessFromApiKey { - return self::get(null, null, -9999); + return self::get($state, -9999); } public static function getVerified(): EntityRequestAccessFromApiKey { - return (self::get())->setState(new RequestAccessState(RequestAccessState::VERIFIED)); + return (self::get()) + ->setApplication(FixtureApplication::get()) + ->setState(new RequestAccessState(RequestAccessState::VERIFIED)); } } diff --git a/component/Fixture/DataStructure/RequestAccessFromOtp.php b/component/Fixture/DataStructure/RequestAccessFromOtp.php index 779afdd..ba094c5 100644 --- a/component/Fixture/DataStructure/RequestAccessFromOtp.php +++ b/component/Fixture/DataStructure/RequestAccessFromOtp.php @@ -5,7 +5,6 @@ use Phant\Auth\Domain\DataStructure\RequestAccessFromOtp as EntityRequestAccessFromOtp; use Phant\Auth\Domain\DataStructure\Value\{ - IdRequestAccess, Otp, RequestAccessState, }; @@ -15,15 +14,13 @@ final class RequestAccessFromOtp { - public static function get(?IdRequestAccess $id = null, ?RequestAccessState $state = null, int $lifetime = null): EntityRequestAccessFromOtp + public static function get(?RequestAccessState $state = null, int $lifetime = null): EntityRequestAccessFromOtp { - if (is_null($id)) $id = new IdRequestAccess('2362ecd5-ac3b-4806-817a-966eaaf308f0'); if (is_null($state)) $state = new RequestAccessState(RequestAccessState::REQUESTED); if (is_null($lifetime)) $lifetime = EntityRequestAccessFromOtp::LIFETIME; $numberOfAttemptsLimit = 3; return new EntityRequestAccessFromOtp( - $id, FixtureApplication::get(), $state, FixtureUser::get(), @@ -33,13 +30,14 @@ public static function get(?IdRequestAccess $id = null, ?RequestAccessState $sta ); } - public static function getExpired(): EntityRequestAccessFromOtp + public static function getExpired(?RequestAccessState $state = null): EntityRequestAccessFromOtp { - return self::get(null, null, -9999); + return self::get($state, -9999); } public static function getVerified(): EntityRequestAccessFromOtp { - return (self::get())->setState(new RequestAccessState(RequestAccessState::VERIFIED)); + return (self::get()) + ->setState(new RequestAccessState(RequestAccessState::VERIFIED)); } } diff --git a/component/Fixture/DataStructure/RequestAccessFromThirdParty.php b/component/Fixture/DataStructure/RequestAccessFromThirdParty.php index 148485e..c0e604f 100644 --- a/component/Fixture/DataStructure/RequestAccessFromThirdParty.php +++ b/component/Fixture/DataStructure/RequestAccessFromThirdParty.php @@ -4,24 +4,19 @@ namespace Phant\Auth\Fixture\DataStructure; use Phant\Auth\Domain\DataStructure\RequestAccessFromThirdParty as EntityRequestAccessFromThirdParty; -use Phant\Auth\Domain\DataStructure\Value\{ - IdRequestAccess, - RequestAccessState, -}; +use Phant\Auth\Domain\DataStructure\Value\RequestAccessState; use Phant\Auth\Fixture\DataStructure\Application as FixtureApplication; use Phant\Auth\Fixture\DataStructure\User as FixtureUser; final class RequestAccessFromThirdParty { - public static function get(?IdRequestAccess $id = null, ?RequestAccessState $state = null, int $lifetime = null): EntityRequestAccessFromThirdParty + public static function get(?RequestAccessState $state = null, int $lifetime = null): EntityRequestAccessFromThirdParty { - if (is_null($id)) $id = new IdRequestAccess('2362ecd5-ac3b-4806-817a-966eaaf308f0'); if (is_null($state)) $state = new RequestAccessState(RequestAccessState::REQUESTED); if (is_null($lifetime)) $lifetime = EntityRequestAccessFromThirdParty::LIFETIME; return new EntityRequestAccessFromThirdParty( - $id, FixtureApplication::get(), $state, null, @@ -29,9 +24,9 @@ public static function get(?IdRequestAccess $id = null, ?RequestAccessState $sta ); } - public static function getExpired(): EntityRequestAccessFromThirdParty + public static function getExpired(?RequestAccessState $state = null): EntityRequestAccessFromThirdParty { - return self::get(null, null, -9999); + return self::get($state, -9999); } public static function getVerified(): EntityRequestAccessFromThirdParty diff --git a/test/Domain/DataStructure/RequestAccessFromApiKeyTest.php b/test/Domain/DataStructure/RequestAccessFromApiKeyTest.php index b23f041..9f51199 100644 --- a/test/Domain/DataStructure/RequestAccessFromApiKeyTest.php +++ b/test/Domain/DataStructure/RequestAccessFromApiKeyTest.php @@ -28,7 +28,6 @@ public function setUp(): void public function testConstruct(): void { $entity = new RequestAccessFromApiKey( - IdRequestAccess::generate(), null, new RequestAccessState(RequestAccessState::REQUESTED), FixtureApplication::get()->apiKey diff --git a/test/Domain/DataStructure/RequestAccessFromOtpTest.php b/test/Domain/DataStructure/RequestAccessFromOtpTest.php index 9997a2e..e43ed6d 100644 --- a/test/Domain/DataStructure/RequestAccessFromOtpTest.php +++ b/test/Domain/DataStructure/RequestAccessFromOtpTest.php @@ -30,7 +30,6 @@ public function setUp(): void public function testConstruct(): void { $entity = new RequestAccessFromOtp( - IdRequestAccess::generate(), FixtureApplication::get(), new RequestAccessState(RequestAccessState::REQUESTED), FixtureUser::get(), diff --git a/test/Domain/DataStructure/RequestAccessFromThirdPartyTest.php b/test/Domain/DataStructure/RequestAccessFromThirdPartyTest.php index ee3d598..ec2ee40 100644 --- a/test/Domain/DataStructure/RequestAccessFromThirdPartyTest.php +++ b/test/Domain/DataStructure/RequestAccessFromThirdPartyTest.php @@ -26,7 +26,6 @@ public function setUp(): void public function testConstruct(): void { $entity = new RequestAccessFromThirdParty( - IdRequestAccess::generate(), FixtureApplication::get(), new RequestAccessState(RequestAccessState::REQUESTED), null diff --git a/test/Domain/Service/RequestAccessTest.php b/test/Domain/Service/RequestAccessTest.php index 7930cc5..a6d6c16 100644 --- a/test/Domain/Service/RequestAccessTest.php +++ b/test/Domain/Service/RequestAccessTest.php @@ -32,6 +32,10 @@ public function testSet(): void public function testGet(): void { + $this->service->set( + $this->fixture + ); + $entity = $this->service->get( $this->fixture->getId() ); @@ -42,6 +46,10 @@ public function testGet(): void public function testGetToken(): void { + $this->service->set( + $this->fixture + ); + $value = $this->service->getToken( $this->fixture ); @@ -52,6 +60,10 @@ public function testGetToken(): void public function testGetFromToken(): void { + $this->service->set( + $this->fixture + ); + $entity = $this->service->getFromToken( $this->service->getToken( $this->fixture From 5b4e56bcd2554477456d3b1788cfd17096ace27a Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 16:12:09 +0200 Subject: [PATCH 20/42] Refacto build request access interface --- .../Domain/DataStructure/RequestAccess.php | 39 +++++++++------ .../DataStructure/RequestAccessFromApiKey.php | 8 ++- .../DataStructure/RequestAccessFromOtp.php | 13 +++-- .../RequestAccessFromThirdParty.php | 6 +-- .../Service/RequestAccessFromApiKey.php | 6 +-- .../Domain/Service/RequestAccessFromOtp.php | 23 ++++----- .../Service/RequestAccessFromThirdParty.php | 13 +++-- .../DataStructure/RequestAccessFromApiKey.php | 2 - .../DataStructure/RequestAccessFromOtp.php | 2 - .../RequestAccessFromThirdParty.php | 2 - .../RequestAccessFromApiKeyTest.php | 2 - .../RequestAccessFromOtpTest.php | 12 +++-- .../RequestAccessFromThirdPartyTest.php | 4 +- .../DataStructure/RequestAccessTest.php | 49 +++++++++---------- .../Service/RequestAccessFromOtpTest.php | 6 +-- 15 files changed, 96 insertions(+), 91 deletions(-) diff --git a/component/Domain/DataStructure/RequestAccess.php b/component/Domain/DataStructure/RequestAccess.php index 5b1c7d5..09cd038 100644 --- a/component/Domain/DataStructure/RequestAccess.php +++ b/component/Domain/DataStructure/RequestAccess.php @@ -16,6 +16,7 @@ SslKey, }; +use Phant\Error\NotAuthorized; use Phant\Error\NotCompliant; abstract class RequestAccess extends \Phant\DataStructure\Abstract\Entity @@ -26,25 +27,25 @@ abstract class RequestAccess extends \Phant\DataStructure\Abstract\Entity protected IdRequestAccess $id; protected ?Application $application; + protected ?User $user; protected AuthMethod $authMethod; protected RequestAccessState $state; - protected ?User $user; protected int $expiration; public function __construct( IdRequestAccess $id, ?Application $application, + ?User $user, AuthMethod $authMethod, RequestAccessState $state, - ?User $user = null, int $lifetime = self::LIFETIME ) { $this->id = $id; $this->application = $application; + $this->user = $user; $this->authMethod = $authMethod; $this->state = $state; - $this->user = $user; $this->expiration = time() + $lifetime; } @@ -53,24 +54,27 @@ public function getId(): IdRequestAccess return $this->id; } - public function getApplication(): ?Application - { - return $this->application; - } - public function setApplication(Application $application): void { + if ($this->application) { + throw new NotAuthorized('It is not allowed to modify the application'); + } + $this->application = $application; } - public function getAuthMethod(): AuthMethod + public function getApplication(): ?Application { - return $this->authMethod; + return $this->application; } - public function getState(): RequestAccessState + public function setUser(User $user): void { - return $this->state; + if ($this->user) { + throw new NotAuthorized('It is not allowed to modify the user'); + } + + $this->user = $user; } public function getUser(): ?User @@ -78,9 +82,9 @@ public function getUser(): ?User return $this->user; } - public function setUser(User $user): void + public function getAuthMethod(): AuthMethod { - $this->user = $user; + return $this->authMethod; } public function canBeSetStateTo(RequestAccessState $state): bool @@ -91,7 +95,7 @@ public function canBeSetStateTo(RequestAccessState $state): bool public function setState(RequestAccessState $state): self { if (!$this->state->canBeSetTo($state)) { - throw new NotCompliant('State can be set to set to : ' . $state); + throw new NotAuthorized('State can be set to set to : ' . $state); } $this->state = $state; @@ -99,6 +103,11 @@ public function setState(RequestAccessState $state): self return $this; } + public function getState(): RequestAccessState + { + return $this->state; + } + public function tokenizeId(SslKey $sslKey): RequestAccessToken { $id = (string)$this->id; diff --git a/component/Domain/DataStructure/RequestAccessFromApiKey.php b/component/Domain/DataStructure/RequestAccessFromApiKey.php index a2d682d..2a114b3 100644 --- a/component/Domain/DataStructure/RequestAccessFromApiKey.php +++ b/component/Domain/DataStructure/RequestAccessFromApiKey.php @@ -18,18 +18,16 @@ final class RequestAccessFromApiKey extends \Phant\Auth\Domain\DataStructure\Req protected ApiKey $apiKey; public function __construct( - ?Application $application, - RequestAccessState $state, ApiKey $apiKey, int $lifetime = self::LIFETIME ) { parent::__construct( IdRequestAccess::generate(), - $application, - new AuthMethod(AuthMethod::API_KEY), - $state, null, + null, + new AuthMethod(AuthMethod::API_KEY), + new RequestAccessState(RequestAccessState::REQUESTED), $lifetime ); diff --git a/component/Domain/DataStructure/RequestAccessFromOtp.php b/component/Domain/DataStructure/RequestAccessFromOtp.php index 717ef0b..b2e050b 100644 --- a/component/Domain/DataStructure/RequestAccessFromOtp.php +++ b/component/Domain/DataStructure/RequestAccessFromOtp.php @@ -24,9 +24,7 @@ final class RequestAccessFromOtp extends \Phant\Auth\Domain\DataStructure\Reques public function __construct( Application $application, - RequestAccessState $state, User $user, - Otp $otp, int $numberOfAttemptsLimit, int $lifetime = self::LIFETIME ) @@ -38,16 +36,21 @@ public function __construct( parent::__construct( IdRequestAccess::generate(), $application, - new AuthMethod(AuthMethod::OTP), - $state, $user, + new AuthMethod(AuthMethod::OTP), + new RequestAccessState(RequestAccessState::REQUESTED), $lifetime ); - $this->otp = $otp; + $this->otp = Otp::generate(); $this->numberOfRemainingAttempts = $numberOfAttemptsLimit; } + public function getOtp(): Otp + { + return $this->otp; + } + public function getNumberOfRemainingAttempts(): int { return $this->numberOfRemainingAttempts; diff --git a/component/Domain/DataStructure/RequestAccessFromThirdParty.php b/component/Domain/DataStructure/RequestAccessFromThirdParty.php index 47dd287..4ea594c 100644 --- a/component/Domain/DataStructure/RequestAccessFromThirdParty.php +++ b/component/Domain/DataStructure/RequestAccessFromThirdParty.php @@ -17,17 +17,15 @@ final class RequestAccessFromThirdParty extends \Phant\Auth\Domain\DataStructure { public function __construct( Application $application, - RequestAccessState $state, - ?User $user, int $lifetime = self::LIFETIME ) { parent::__construct( IdRequestAccess::generate(), $application, + null, new AuthMethod(AuthMethod::THIRD_PARTY), - $state, - $user, + new RequestAccessState(RequestAccessState::REQUESTED), $lifetime ); } diff --git a/component/Domain/Service/RequestAccessFromApiKey.php b/component/Domain/Service/RequestAccessFromApiKey.php index d843fd9..47153c6 100644 --- a/component/Domain/Service/RequestAccessFromApiKey.php +++ b/component/Domain/Service/RequestAccessFromApiKey.php @@ -43,7 +43,7 @@ public function getAccessToken(string|ApiKey $apiKey): ?AccessToken { if (is_string($apiKey)) $apiKey = new ApiKey($apiKey); - $requestAccess = $this->generate($apiKey); + $requestAccess = $this->build($apiKey); $application = $this->repositoryApplication->getFromApiKey($apiKey); @@ -62,11 +62,9 @@ public function getAccessToken(string|ApiKey $apiKey): ?AccessToken return $accessToken; } - private function generate(ApiKey $apiKey): EntityRequestAccessFromApiKey + private function build(ApiKey $apiKey): EntityRequestAccessFromApiKey { return new EntityRequestAccessFromApiKey( - null, - new RequestAccessState(RequestAccessState::REQUESTED), $apiKey ); } diff --git a/component/Domain/Service/RequestAccessFromOtp.php b/component/Domain/Service/RequestAccessFromOtp.php index 2c3f35f..dbda65b 100644 --- a/component/Domain/Service/RequestAccessFromOtp.php +++ b/component/Domain/Service/RequestAccessFromOtp.php @@ -39,21 +39,13 @@ public function __construct( $this->userNotification = $userNotification; } - public function generate(User $user, Application $application, int $numberOfAttemptsLimit = 3): RequestAccessToken + public function generate(Application $application, User $user, int $numberOfAttemptsLimit = 3): RequestAccessToken { - $otp = Otp::generate(); - - $requestAccess = new EntityRequestAccessFromOtp( - $application, - new RequestAccessState(RequestAccessState::REQUESTED), - $user, - $otp, - $numberOfAttemptsLimit - ); + $requestAccess = $this->build($application, $user, $numberOfAttemptsLimit); $requestAccessToken = $this->serviceRequestAccess->getToken($requestAccess); - $this->userNotification->sendOtpFromRequestAccess($requestAccessToken, $requestAccess, $otp); + $this->userNotification->sendOtpFromRequestAccess($requestAccessToken, $requestAccess, $requestAccess->getOtp()); $this->serviceRequestAccess->set($requestAccess); @@ -95,4 +87,13 @@ public function getAccessToken(RequestAccessToken $requestAccessToken): ?AccessT return $accessToken; } + + private function build(Application $application, User $user, int $numberOfAttemptsLimit): EntityRequestAccessFromOtp + { + return new EntityRequestAccessFromOtp( + $application, + $user, + $numberOfAttemptsLimit + ); + } } diff --git a/component/Domain/Service/RequestAccessFromThirdParty.php b/component/Domain/Service/RequestAccessFromThirdParty.php index 40f5e25..731c864 100644 --- a/component/Domain/Service/RequestAccessFromThirdParty.php +++ b/component/Domain/Service/RequestAccessFromThirdParty.php @@ -36,11 +36,7 @@ public function __construct( public function generate(Application $application): RequestAccessToken { - $requestAccess = new EntityRequestAccessFromThirdParty( - $application, - new RequestAccessState(RequestAccessState::REQUESTED), - null - ); + $requestAccess = $this->build($application); $requestAccessToken = $this->serviceRequestAccess->getToken($requestAccess); @@ -67,4 +63,11 @@ public function getAccessToken(RequestAccessToken $requestAccessToken): ?AccessT return $accessToken; } + + private function build(Application $application): EntityRequestAccessFromThirdParty + { + return new EntityRequestAccessFromThirdParty( + $application + ); + } } diff --git a/component/Fixture/DataStructure/RequestAccessFromApiKey.php b/component/Fixture/DataStructure/RequestAccessFromApiKey.php index d0da37e..570e12d 100644 --- a/component/Fixture/DataStructure/RequestAccessFromApiKey.php +++ b/component/Fixture/DataStructure/RequestAccessFromApiKey.php @@ -16,8 +16,6 @@ public static function get(?RequestAccessState $state = null, int $lifetime = nu if (is_null($lifetime)) $lifetime = EntityRequestAccessFromApiKey::LIFETIME; return new EntityRequestAccessFromApiKey( - null, - $state, FixtureApplication::get()->apiKey, $lifetime ); diff --git a/component/Fixture/DataStructure/RequestAccessFromOtp.php b/component/Fixture/DataStructure/RequestAccessFromOtp.php index ba094c5..05744a3 100644 --- a/component/Fixture/DataStructure/RequestAccessFromOtp.php +++ b/component/Fixture/DataStructure/RequestAccessFromOtp.php @@ -22,9 +22,7 @@ public static function get(?RequestAccessState $state = null, int $lifetime = nu return new EntityRequestAccessFromOtp( FixtureApplication::get(), - $state, FixtureUser::get(), - new Otp('123456'), $numberOfAttemptsLimit, $lifetime ); diff --git a/component/Fixture/DataStructure/RequestAccessFromThirdParty.php b/component/Fixture/DataStructure/RequestAccessFromThirdParty.php index c0e604f..d25e83e 100644 --- a/component/Fixture/DataStructure/RequestAccessFromThirdParty.php +++ b/component/Fixture/DataStructure/RequestAccessFromThirdParty.php @@ -18,8 +18,6 @@ public static function get(?RequestAccessState $state = null, int $lifetime = nu return new EntityRequestAccessFromThirdParty( FixtureApplication::get(), - $state, - null, $lifetime ); } diff --git a/test/Domain/DataStructure/RequestAccessFromApiKeyTest.php b/test/Domain/DataStructure/RequestAccessFromApiKeyTest.php index 9f51199..b4356f9 100644 --- a/test/Domain/DataStructure/RequestAccessFromApiKeyTest.php +++ b/test/Domain/DataStructure/RequestAccessFromApiKeyTest.php @@ -28,8 +28,6 @@ public function setUp(): void public function testConstruct(): void { $entity = new RequestAccessFromApiKey( - null, - new RequestAccessState(RequestAccessState::REQUESTED), FixtureApplication::get()->apiKey ); diff --git a/test/Domain/DataStructure/RequestAccessFromOtpTest.php b/test/Domain/DataStructure/RequestAccessFromOtpTest.php index e43ed6d..0ae6632 100644 --- a/test/Domain/DataStructure/RequestAccessFromOtpTest.php +++ b/test/Domain/DataStructure/RequestAccessFromOtpTest.php @@ -31,9 +31,7 @@ public function testConstruct(): void { $entity = new RequestAccessFromOtp( FixtureApplication::get(), - new RequestAccessState(RequestAccessState::REQUESTED), FixtureUser::get(), - Otp::generate(), 3 ); @@ -41,10 +39,18 @@ public function testConstruct(): void $this->assertInstanceOf(RequestAccessFromOtp::class, $entity); } + public function testGetOtp(): void + { + $value = $this->fixture->getOtp(); + + $this->assertIsObject($value); + $this->assertInstanceOf(Otp::class, $value); + } + public function testCheckOtp(): void { $result = $this->fixture->checkOtp( - '123456' + $this->fixture->getOtp() ); $this->assertIsBool($result); diff --git a/test/Domain/DataStructure/RequestAccessFromThirdPartyTest.php b/test/Domain/DataStructure/RequestAccessFromThirdPartyTest.php index ec2ee40..4babb7a 100644 --- a/test/Domain/DataStructure/RequestAccessFromThirdPartyTest.php +++ b/test/Domain/DataStructure/RequestAccessFromThirdPartyTest.php @@ -26,9 +26,7 @@ public function setUp(): void public function testConstruct(): void { $entity = new RequestAccessFromThirdParty( - FixtureApplication::get(), - new RequestAccessState(RequestAccessState::REQUESTED), - null + FixtureApplication::get() ); $this->assertIsObject($entity); diff --git a/test/Domain/DataStructure/RequestAccessTest.php b/test/Domain/DataStructure/RequestAccessTest.php index e21acc2..d36cf02 100644 --- a/test/Domain/DataStructure/RequestAccessTest.php +++ b/test/Domain/DataStructure/RequestAccessTest.php @@ -5,7 +5,7 @@ use Phant\Auth\Domain\DataStructure\{ Application, - RequestAccessFromOtp, + RequestAccessFromApiKey, User, }; use Phant\Auth\Domain\DataStructure\Value\{ @@ -18,22 +18,23 @@ use Phant\Auth\Fixture\DataStructure\{ Application as FixtureApplication, - RequestAccessFromOtp as FixtureRequestAccessFromOtp, + RequestAccessFromApiKey as FixtureRequestAccessFromApiKey, User as FixtureUser, }; use Phant\Auth\Fixture\DataStructure\Value\{ SslKey as FixtureSslKey, }; +use Phant\Error\NotAuthorized; use Phant\Error\NotCompliant; final class RequestAccessTest extends \PHPUnit\Framework\TestCase { - protected RequestAccessFromOtp $fixture; + protected RequestAccessFromApiKey $fixture; public function setUp(): void { - $this->fixture = FixtureRequestAccessFromOtp::get(); + $this->fixture = FixtureRequestAccessFromApiKey::get(); } public function testGetId(): void @@ -48,8 +49,7 @@ public function testGetApplication(): void { $value = $this->fixture->getApplication(); - $this->assertIsObject($value); - $this->assertInstanceOf(Application::class, $value); + $this->assertNull($value); } public function testSetApplication(): void @@ -63,39 +63,38 @@ public function testSetApplication(): void $this->assertEquals(FixtureApplication::get(), $value); } - public function testGetAuthMethod(): void + public function testGetUser(): void { - $value = $this->fixture->getAuthMethod(); + $value = $this->fixture->getUser(); - $this->assertIsObject($value); - $this->assertInstanceOf(AuthMethod::class, $value); + $this->assertNull($value); } - public function testGetState(): void + public function testSetUser(): void { - $value = $this->fixture->getState(); + $this->fixture->setUser(FixtureUser::get()); + + $value = $this->fixture->getUser(); $this->assertIsObject($value); - $this->assertInstanceOf(RequestAccessState::class, $value); + $this->assertInstanceOf(User::class, $value); + $this->assertEquals(FixtureUser::get(), $value); } - public function testGetUser(): void + public function testGetAuthMethod(): void { - $value = $this->fixture->getUser(); + $value = $this->fixture->getAuthMethod(); $this->assertIsObject($value); - $this->assertInstanceOf(User::class, $value); + $this->assertInstanceOf(AuthMethod::class, $value); } - public function testSetUser(): void + public function testGetState(): void { - $this->fixture->setUser(FixtureUser::get()); - - $value = $this->fixture->getUser(); + $value = $this->fixture->getState(); $this->assertIsObject($value); - $this->assertInstanceOf(User::class, $value); - $this->assertEquals(FixtureUser::get(), $value); + $this->assertInstanceOf(RequestAccessState::class, $value); } public function testCanBeSetStateTo(): void @@ -111,7 +110,7 @@ public function testSetState(): void $entity = $this->fixture->setState(new RequestAccessState(RequestAccessState::VERIFIED)); $this->assertIsObject($entity); - $this->assertInstanceOf(RequestAccessFromOtp::class, $entity); + $this->assertInstanceOf(RequestAccessFromApiKey::class, $entity); $this->assertIsObject($entity->getState()); $this->assertInstanceOf(RequestAccessState::class, $entity->getState()); @@ -120,7 +119,7 @@ public function testSetState(): void public function testSetStateInvalid(): void { - $this->expectException(NotCompliant::class); + $this->expectException(NotAuthorized::class); $entity = $this->fixture->setState(new RequestAccessState(RequestAccessState::REQUESTED)); } @@ -160,7 +159,7 @@ public function testUntokenizeIdExpired(): void $this->expectException(NotCompliant::class); $this->fixture->untokenizeId( - FixtureRequestAccessFromOtp::getExpired()->tokenizeId(FixtureSslKey::get()), + FixtureRequestAccessFromApiKey::getExpired()->tokenizeId(FixtureSslKey::get()), FixtureSslKey::get() ); } diff --git a/test/Domain/Service/RequestAccessFromOtpTest.php b/test/Domain/Service/RequestAccessFromOtpTest.php index fd4aaf1..7042d3c 100644 --- a/test/Domain/Service/RequestAccessFromOtpTest.php +++ b/test/Domain/Service/RequestAccessFromOtpTest.php @@ -35,8 +35,8 @@ public function setUp(): void { $this->service = (new FixtureServiceRequestAccessFromOtp())(); $this->fixture = $this->service->generate( - FixtureUser::get(), - FixtureApplication::get() + FixtureApplication::get(), + FixtureUser::get() ); $this->cache = new SimpleCache(realpath(__DIR__ . '/../../../test/storage/'), 'user-notification'); } @@ -52,8 +52,8 @@ public function testGenerateInvalid(): void $this->expectException(NotCompliant::class); $this->service->generate( - FixtureUser::get(), FixtureApplication::get(), + FixtureUser::get(), 0 ); } From b0ffc23b6bcd4fbab7c0665cad803b702580c0cb Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 16:26:42 +0200 Subject: [PATCH 21/42] Test --- test/Domain/DataStructure/RequestAccessTest.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/Domain/DataStructure/RequestAccessTest.php b/test/Domain/DataStructure/RequestAccessTest.php index d36cf02..a49b2f2 100644 --- a/test/Domain/DataStructure/RequestAccessTest.php +++ b/test/Domain/DataStructure/RequestAccessTest.php @@ -63,6 +63,14 @@ public function testSetApplication(): void $this->assertEquals(FixtureApplication::get(), $value); } + public function testSetApplicationInvalid(): void + { + $this->expectException(NotAuthorized::class); + + $this->fixture->setApplication(FixtureApplication::get()); + $this->fixture->setApplication(FixtureApplication::get()); + } + public function testGetUser(): void { $value = $this->fixture->getUser(); @@ -81,6 +89,14 @@ public function testSetUser(): void $this->assertEquals(FixtureUser::get(), $value); } + public function testSetUserInvalid(): void + { + $this->expectException(NotAuthorized::class); + + $this->fixture->setUser(FixtureUser::get()); + $this->fixture->setUser(FixtureUser::get()); + } + public function testGetAuthMethod(): void { $value = $this->fixture->getAuthMethod(); From aac44a44c65ba224a088b190d87b30d58e84d547 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 16:27:00 +0200 Subject: [PATCH 22/42] Refacto request access interface --- .../Domain/Service/RequestAccessFromThirdParty.php | 2 +- .../Domain/Service/RequestAccessFromThirdPartyTest.php | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/component/Domain/Service/RequestAccessFromThirdParty.php b/component/Domain/Service/RequestAccessFromThirdParty.php index 731c864..4f0de33 100644 --- a/component/Domain/Service/RequestAccessFromThirdParty.php +++ b/component/Domain/Service/RequestAccessFromThirdParty.php @@ -45,7 +45,7 @@ public function generate(Application $application): RequestAccessToken return $requestAccessToken; } - public function verify(RequestAccessToken $requestAccessToken, User $user, bool $isAuthorized): void + public function setStatus(RequestAccessToken $requestAccessToken, User $user, bool $isAuthorized): void { $requestAccess = $this->serviceRequestAccess->getFromToken($requestAccessToken); diff --git a/test/Domain/Service/RequestAccessFromThirdPartyTest.php b/test/Domain/Service/RequestAccessFromThirdPartyTest.php index 4d05fcc..e5173d6 100644 --- a/test/Domain/Service/RequestAccessFromThirdPartyTest.php +++ b/test/Domain/Service/RequestAccessFromThirdPartyTest.php @@ -42,9 +42,9 @@ public function testGenerate(): void $this->assertInstanceOf(RequestAccessToken::class, $this->fixture); } - public function testVerify(): void + public function testSetStatus(): void { - $this->service->verify( + $this->service->setStatus( $this->fixture, FixtureUser::get(), true @@ -53,9 +53,9 @@ public function testVerify(): void $this->addToAssertionCount(1); } - public function testGetAccessToken(): void + public function testSetStatusToken(): void { - $this->service->verify( + $this->service->setStatus( $this->fixture, FixtureUser::get(), true @@ -73,7 +73,7 @@ public function testGetAccessTokenInvalid(): void { $this->expectException(NotAuthorized::class); - $this->service->verify( + $this->service->setStatus( $this->fixture, FixtureUser::get(), false From fc086f353b8e70924458d59615118cbb8f1dbf0b Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 16:43:32 +0200 Subject: [PATCH 23/42] Cleaning --- README.md | 1 + component/Domain/DataStructure/AccessToken.php | 1 - component/Domain/Service/AccessToken.php | 5 ----- test/Domain/Service/AccessTokenTest.php | 7 ------- 4 files changed, 1 insertion(+), 13 deletions(-) diff --git a/README.md b/README.md index 441babc..898d7e1 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ # auth Auth + diff --git a/component/Domain/DataStructure/AccessToken.php b/component/Domain/DataStructure/AccessToken.php index 11de546..27efd5b 100644 --- a/component/Domain/DataStructure/AccessToken.php +++ b/component/Domain/DataStructure/AccessToken.php @@ -21,7 +21,6 @@ final class AccessToken extends \Phant\DataStructure\Abstract\Entity { public const PAYLOAD_KEY_APP = 'app'; public const PAYLOAD_KEY_USER = 'user'; - public const ALGORITHM = Jwt::ALGORITHM; public const LIFETIME = 10800; protected string $value; diff --git a/component/Domain/Service/AccessToken.php b/component/Domain/Service/AccessToken.php index 31bdeb6..c387950 100644 --- a/component/Domain/Service/AccessToken.php +++ b/component/Domain/Service/AccessToken.php @@ -36,11 +36,6 @@ public function getPublicKey(): string return $this->sslKey->getPublic(); } - public function getAlgorithm(): string - { - return EntityAccessToken::ALGORITHM; - } - public function check(string $accessToken, Application $application): bool { return (new EntityAccessToken($accessToken))->check( diff --git a/test/Domain/Service/AccessTokenTest.php b/test/Domain/Service/AccessTokenTest.php index 0785b8b..eb1bf6c 100644 --- a/test/Domain/Service/AccessTokenTest.php +++ b/test/Domain/Service/AccessTokenTest.php @@ -33,13 +33,6 @@ public function testGetPublicKey(): void $this->assertIsString($value); } - public function testGetAlgorithm(): void - { - $value = $this->service->getAlgorithm(); - - $this->assertIsString($value); - } - public function testCheck(): void { $value = $this->service->check( From b262e0157840b44029a45c1786c8474fb5ecffd1 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 16:44:03 +0200 Subject: [PATCH 24/42] Doc --- README.md | 338 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 336 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 898d7e1..ad12353 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,337 @@ -# auth -Auth +# Auth +## Presentation + +The authentication service is intended to manage access (Applications and Users) to applications and APIs. + +The application wishing to use this service must first obtain an API key (to be generated). + +Authentication service aims to provide an access token allowing access of applications and users. + +Obtaining the access token is subject to various methods. + +The access token has a limited lifetime. +It embeds data relating to its applicant (application, user). + + +## Technologies used + +- `PHP 8.1` +- `Composer` for dependencies management (PHP) + + +## Installation + +`composer install` + + +## Request access + +For each use case the following setup is required. + +```php +use Phant\Auth\Domain\Service\AccessToken as ServiceAccessToken; +use Phant\Auth\Domain\Service\RequestAccess as ServiceRequestAccess; +use Phant\Auth\FixtDomainure\DataStructure\Value\SslKey; +use App\RepositoryRequestAccess; + + +// Config + +$sslKey = new SslKey('private key', 'public key'); +$repositoryRequestAccess = new RepositoryRequestAccess(); + + +// Build services + +$serviceRequestAccess = new ServiceRequestAccess( + $repositoryRequestAccess, + $sslKey +); + +$serviceAccessToken = return new ServiceAccessToken( + $sslKey, + $serviceRequestAccess +) +``` + +### From API key + +Process : + +1. The application requests an access token by providing its API key, +2. The service provides an access token. + +```php +use Phant\Auth\Domain\Service\RequestAccessFromApiKey as ServiceRequestAccessFromApiKey; +use App\RepositoryApplication; + + +// Config + +$repositoryApplication = new RepositoryApplication(); + + +// Build services + +$serviceRequestAccessFromApiKey = new ServiceRequestAccessFromApiKey( + $serviceRequestAccess, + $serviceAccessToken, + $repositoryApplication +); + + +// Obtain API key from application + +/* @todo */ +$apiKey = 'XXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'; + + +// Request access token + +$accessToken = $serviceRequestAccessFromApiKey->getAccessToken($apiKey); +``` + + +### From OTP + +Process : + +1. The application asks the user to authenticate himself by providing his contact details (last name, first name and e-mail address), +2. The application generates an access request by providing its identity and the user's contact details (last name, first name and e-mail address), +3. The service generates an OTP and requests its sending to the user, +4. The user receives an OTP, +5. The application retrieves the OTP from the user, +6. The user transmits the received OTP to the application, +7. The application verifies the OTP with the service, +8. The application requests an access token, +9. The service provides an access token. + +The OTP is sent to user by your own UserNotification service (e-mail, SMS, etc.). + +```php +use Phant\Auth\Domain\Service\RequestAccessFromOtp as ServiceRequestAccessFromOtp; +use Phant\Auth\Domain\DataStructure\Application; +use Phant\Auth\Domain\DataStructure\User; +use App\UserNotification; + + +// Config + +$repositoryApplication = new RepositoryApplication(); +$userNotification = new UserNotification(); + + +// Build services + +$serviceRequestAccessFromOtp = new ServiceRequestAccessFromOtp( + $serviceRequestAccess, + $serviceAccessToken, + $userNotification +); + + +// Request access token + +$user = new User( + 'john.doe@domain.ext', + 'John', + 'DOE' +); + +$application = new Application( + 'eb7c9c44-32c2-4e88-8410-4ebafb18fdf7', + 'My app', + 'https://domain.ext/image.ext' +); + +$requestAccessToken = $serviceRequestAccessFromOtp->generate($user, $application); + + +// Obtain OTP from user + +/* @todo */ +$otp = '123456'; + + +// Verify OTP + +$isValid = $serviceRequestAccessFromOtp->verify($otp); + +if ( ! $isValid) { + $numberOfAttemptsRemaining = $serviceRequestAccessFromOtp->numberOfAttemptsRemaining($requestAccessToken); +} + + +// Get access token + +$accessToken = $serviceRequestAccessFromOtp->getAccessToken($requestAccessToken); +``` + + +### From third party + +Process : + +1. The application generates an access request by providing its identity, +2. The service generates an Access-Request and returns an Access-Request Token, +3. The application forwards the authentication request to the third party service by passing the access request token, +4. The user authenticates with the third-party authentication service, +5. The application retrieves the user authentication result, +6. The application declares the authentication result, +7. The service takes note of the authentication. +8. The service provides an access token. + +```php +use Phant\Auth\Domain\Service\RequestAccessFromThirdParty as ServiceRequestAccessFromThirdParty; +use Phant\Auth\Domain\DataStructure\Application; +use Phant\Auth\Domain\DataStructure\User; +use App\RepositoryRequestAccess; + + +// Config + +$repositoryApplication = new RepositoryApplication(); +$userNotification = new UserNotification(); + + +// Build services + +$serviceRequestAccessFromThirdParty = new ServiceRequestAccessFromThirdParty( + $serviceRequestAccess, + $serviceAccessToken +); + + +// Request access token + +$application = new Application( + 'eb7c9c44-32c2-4e88-8410-4ebafb18fdf7', + 'My app', + 'https://domain.ext/image.ext' +); + +$requestAccessToken = $serviceRequestAccessFromThirdParty->generate($application); + + +// Request third party auth with requestAccessToken + +/* @todo */ + + +// Obtain authentication status + +/* @todo */ +$isAuthorized = true; + + +// Obtain user data + +/* @todo */ +$user = new User( + 'john.doe@domain.ext', + 'John', + 'DOE' +); + + +// Set auth status + +$serviceRequestAccessFromThirdParty->setStatus($requestAccessToken, $user, $isAuthorized); + + +// Get access token + +$accessToken = $serviceRequestAccessFromThirdParty->getAccessToken($requestAccessToken); +``` + + +## Access token + +The access token is a JWT. + +For each use case the following setup is required. + +```php +use Phant\Auth\Domain\Service\AccessToken as ServiceAccessToken; +use Phant\Auth\Domain\Service\RequestAccess as ServiceRequestAccess; +use Phant\Auth\FixtDomainure\DataStructure\Value\SslKey; +use App\RepositoryRequestAccess; + + +// Config + +$sslKey = new SslKey('private key', 'public key'); +$repositoryRequestAccess = new RepositoryRequestAccess(); + + +// Build services + +$serviceRequestAccess = new ServiceRequestAccess( + $repositoryRequestAccess, + $sslKey +); + +$serviceAccessToken = return new ServiceAccessToken( + $sslKey, + $serviceRequestAccess +) + + +// An access token + +$accessToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhcHAiOnsiaWQiOiJjMjI4MDI1OC03OGU5LTQ4ZmQtOTA1Zi0yYzhlMDIzYWNiOWMiLCJuYW1lIjoiRmxhc2hwb2ludCIsImxvZ28iOiJodHRwczpcL1wvdmlhLnBsYWNlaG9sZGVyLmNvbVwvNDAweDIwMD90ZXh0PUZsYXNocG9pbnQiLCJhcGlfa2V5IjoiZnc5TEFJcFkuclA2b2d5VlNRdEx1OWRWMXBqOTR2WG56ekVPNXNISldHeHdhNWMxZzZMa3owNlo5dGNuc21GNFNieVRqeURTaCJ9LCJ1c2VyIjp7ImVtYWlsX2FkZHJlc3MiOiJqb2huLmRvZUBkb21haW4uZXh0IiwibGFzdG5hbWUiOiJET0UiLCJmaXJzdG5hbWUiOiJKb2huIiwicm9sZSI6bnVsbH0sImlhdCI6MTY2MzY4NDM3MCwiZXhwIjoxNjYzNjk1MTcwfQ.a-wJ_T1ENG58zCw2X7oP2oZrziZRP_m0rOOkUkC2axAsx7O72ebGjQja-iry-lFvd1PF48BxejQw69LPUQKrx1Tb9oQ_8VqMhU97nR8Jd5v2jlWIA7CP2H9voQLE5ybHpqFO2IzgPf2MurzwXQ0tlSeiRbQzHLzMBbWhcQLU4aI'; +``` + +### JWT decrypt method + +The application may need the public key for the following uses : +- check the integrity of the token, +- extract data from the token. + +```php +use Phant\DataStructure\Token\Jwt; +use Phant\Error\NotCompliant; + +$publicKey = $serviceAccessToken->getPublicKey(); + +try { + $payLoad = (new Jwt($accessToken))->decode(publicKey); +} catch (NotCompliant $e) { + +} +``` + + +### Verification + +The application can verify the integrity of the token with the service. + +```php +use Phant\Auth\Domain\DataStructure\Application; + +$application = new Application( + 'eb7c9c44-32c2-4e88-8410-4ebafb18fdf7', + 'My app', + 'https://domain.ext/image.ext' +); + +$isValid = $serviceAccessToken->check($accessToken, $application); +``` + + +### Get user infos + +The app can get the token user data from the service. + +```php +use Phant\Auth\Domain\DataStructure\Application; + +$application = new Application( + 'eb7c9c44-32c2-4e88-8410-4ebafb18fdf7', + 'My app', + 'https://domain.ext/image.ext' +); + +$userInfos = $serviceAccessToken->getUserInfos($accessToken); +``` From 4a4c3a9c2364614710558ed6b6f384defe146341 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 17:00:37 +0200 Subject: [PATCH 25/42] Allow lifetime service set up --- component/Domain/DataStructure/RequestAccess.php | 3 +-- .../Domain/DataStructure/RequestAccessFromApiKey.php | 2 +- .../Domain/DataStructure/RequestAccessFromOtp.php | 2 +- .../DataStructure/RequestAccessFromThirdParty.php | 2 +- component/Domain/Service/RequestAccessFromApiKey.php | 11 +++++++---- component/Domain/Service/RequestAccessFromOtp.php | 11 +++++++---- .../Domain/Service/RequestAccessFromThirdParty.php | 11 +++++++---- .../Fixture/DataStructure/RequestAccessFromApiKey.php | 3 +-- .../Fixture/DataStructure/RequestAccessFromOtp.php | 8 +++----- .../DataStructure/RequestAccessFromThirdParty.php | 3 +-- .../DataStructure/RequestAccessFromApiKeyTest.php | 3 ++- .../Domain/DataStructure/RequestAccessFromOtpTest.php | 3 ++- .../DataStructure/RequestAccessFromThirdPartyTest.php | 3 ++- 13 files changed, 36 insertions(+), 29 deletions(-) diff --git a/component/Domain/DataStructure/RequestAccess.php b/component/Domain/DataStructure/RequestAccess.php index 09cd038..ab740d9 100644 --- a/component/Domain/DataStructure/RequestAccess.php +++ b/component/Domain/DataStructure/RequestAccess.php @@ -23,7 +23,6 @@ abstract class RequestAccess extends \Phant\DataStructure\Abstract\Entity { const TOKEN_PAYLOAD_EXPIRATION = 'expiration'; const TOKEN_PAYLOAD_ID = 'request_access_id'; - const LIFETIME = 900; // 15 min protected IdRequestAccess $id; protected ?Application $application; @@ -38,7 +37,7 @@ public function __construct( ?User $user, AuthMethod $authMethod, RequestAccessState $state, - int $lifetime = self::LIFETIME + int $lifetime ) { $this->id = $id; diff --git a/component/Domain/DataStructure/RequestAccessFromApiKey.php b/component/Domain/DataStructure/RequestAccessFromApiKey.php index 2a114b3..102f13f 100644 --- a/component/Domain/DataStructure/RequestAccessFromApiKey.php +++ b/component/Domain/DataStructure/RequestAccessFromApiKey.php @@ -19,7 +19,7 @@ final class RequestAccessFromApiKey extends \Phant\Auth\Domain\DataStructure\Req public function __construct( ApiKey $apiKey, - int $lifetime = self::LIFETIME + int $lifetime ) { parent::__construct( diff --git a/component/Domain/DataStructure/RequestAccessFromOtp.php b/component/Domain/DataStructure/RequestAccessFromOtp.php index b2e050b..9c434a5 100644 --- a/component/Domain/DataStructure/RequestAccessFromOtp.php +++ b/component/Domain/DataStructure/RequestAccessFromOtp.php @@ -26,7 +26,7 @@ public function __construct( Application $application, User $user, int $numberOfAttemptsLimit, - int $lifetime = self::LIFETIME + int $lifetime ) { if ($numberOfAttemptsLimit < 1) { diff --git a/component/Domain/DataStructure/RequestAccessFromThirdParty.php b/component/Domain/DataStructure/RequestAccessFromThirdParty.php index 4ea594c..3dbb8e0 100644 --- a/component/Domain/DataStructure/RequestAccessFromThirdParty.php +++ b/component/Domain/DataStructure/RequestAccessFromThirdParty.php @@ -17,7 +17,7 @@ final class RequestAccessFromThirdParty extends \Phant\Auth\Domain\DataStructure { public function __construct( Application $application, - int $lifetime = self::LIFETIME + int $lifetime ) { parent::__construct( diff --git a/component/Domain/Service/RequestAccessFromApiKey.php b/component/Domain/Service/RequestAccessFromApiKey.php index 47153c6..c766ec2 100644 --- a/component/Domain/Service/RequestAccessFromApiKey.php +++ b/component/Domain/Service/RequestAccessFromApiKey.php @@ -24,6 +24,8 @@ final class RequestAccessFromApiKey { + const LIFETIME = 300; // 5 min + protected ServiceRequestAccess $serviceRequestAccess; protected ServiceAccessToken $serviceAccessToken; protected PortApplication $repositoryApplication; @@ -39,11 +41,11 @@ public function __construct( $this->repositoryApplication = $repositoryApplication; } - public function getAccessToken(string|ApiKey $apiKey): ?AccessToken + public function getAccessToken(string|ApiKey $apiKey, int $lifetime = self::LIFETIME): ?AccessToken { if (is_string($apiKey)) $apiKey = new ApiKey($apiKey); - $requestAccess = $this->build($apiKey); + $requestAccess = $this->build($apiKey, $lifetime); $application = $this->repositoryApplication->getFromApiKey($apiKey); @@ -62,10 +64,11 @@ public function getAccessToken(string|ApiKey $apiKey): ?AccessToken return $accessToken; } - private function build(ApiKey $apiKey): EntityRequestAccessFromApiKey + private function build(ApiKey $apiKey, int $lifetime): EntityRequestAccessFromApiKey { return new EntityRequestAccessFromApiKey( - $apiKey + $apiKey, + $lifetime ); } } diff --git a/component/Domain/Service/RequestAccessFromOtp.php b/component/Domain/Service/RequestAccessFromOtp.php index dbda65b..2505576 100644 --- a/component/Domain/Service/RequestAccessFromOtp.php +++ b/component/Domain/Service/RequestAccessFromOtp.php @@ -24,6 +24,8 @@ final class RequestAccessFromOtp { + const LIFETIME = 900; // 15 min + protected ServiceRequestAccess $serviceRequestAccess; protected ServiceAccessToken $serviceAccessToken; protected UserNotification $userNotification; @@ -39,9 +41,9 @@ public function __construct( $this->userNotification = $userNotification; } - public function generate(Application $application, User $user, int $numberOfAttemptsLimit = 3): RequestAccessToken + public function generate(Application $application, User $user, int $numberOfAttemptsLimit = 3, int $lifetime = self::LIFETIME): RequestAccessToken { - $requestAccess = $this->build($application, $user, $numberOfAttemptsLimit); + $requestAccess = $this->build($application, $user, $numberOfAttemptsLimit, $lifetime); $requestAccessToken = $this->serviceRequestAccess->getToken($requestAccess); @@ -88,12 +90,13 @@ public function getAccessToken(RequestAccessToken $requestAccessToken): ?AccessT return $accessToken; } - private function build(Application $application, User $user, int $numberOfAttemptsLimit): EntityRequestAccessFromOtp + private function build(Application $application, User $user, int $numberOfAttemptsLimit, int $lifetime): EntityRequestAccessFromOtp { return new EntityRequestAccessFromOtp( $application, $user, - $numberOfAttemptsLimit + $numberOfAttemptsLimit, + $lifetime ); } } diff --git a/component/Domain/Service/RequestAccessFromThirdParty.php b/component/Domain/Service/RequestAccessFromThirdParty.php index 4f0de33..4e4406b 100644 --- a/component/Domain/Service/RequestAccessFromThirdParty.php +++ b/component/Domain/Service/RequestAccessFromThirdParty.php @@ -22,6 +22,8 @@ final class RequestAccessFromThirdParty { + const LIFETIME = 900; // 15 min + protected ServiceRequestAccess $serviceRequestAccess; protected ServiceAccessToken $serviceAccessToken; @@ -34,9 +36,9 @@ public function __construct( $this->serviceAccessToken = $serviceAccessToken; } - public function generate(Application $application): RequestAccessToken + public function generate(Application $application, int $lifetime = self::LIFETIME): RequestAccessToken { - $requestAccess = $this->build($application); + $requestAccess = $this->build($application, $lifetime); $requestAccessToken = $this->serviceRequestAccess->getToken($requestAccess); @@ -64,10 +66,11 @@ public function getAccessToken(RequestAccessToken $requestAccessToken): ?AccessT return $accessToken; } - private function build(Application $application): EntityRequestAccessFromThirdParty + private function build(Application $application, int $lifetime): EntityRequestAccessFromThirdParty { return new EntityRequestAccessFromThirdParty( - $application + $application, + $lifetime ); } } diff --git a/component/Fixture/DataStructure/RequestAccessFromApiKey.php b/component/Fixture/DataStructure/RequestAccessFromApiKey.php index 570e12d..5f2284b 100644 --- a/component/Fixture/DataStructure/RequestAccessFromApiKey.php +++ b/component/Fixture/DataStructure/RequestAccessFromApiKey.php @@ -10,10 +10,9 @@ final class RequestAccessFromApiKey { - public static function get(?RequestAccessState $state = null, int $lifetime = null): EntityRequestAccessFromApiKey + public static function get(?RequestAccessState $state = null, int $lifetime = 300): EntityRequestAccessFromApiKey { if (is_null($state)) $state = new RequestAccessState(RequestAccessState::REQUESTED); - if (is_null($lifetime)) $lifetime = EntityRequestAccessFromApiKey::LIFETIME; return new EntityRequestAccessFromApiKey( FixtureApplication::get()->apiKey, diff --git a/component/Fixture/DataStructure/RequestAccessFromOtp.php b/component/Fixture/DataStructure/RequestAccessFromOtp.php index 05744a3..f892ddc 100644 --- a/component/Fixture/DataStructure/RequestAccessFromOtp.php +++ b/component/Fixture/DataStructure/RequestAccessFromOtp.php @@ -14,11 +14,9 @@ final class RequestAccessFromOtp { - public static function get(?RequestAccessState $state = null, int $lifetime = null): EntityRequestAccessFromOtp + public static function get(?RequestAccessState $state = null, int $numberOfAttemptsLimit = 3, int $lifetime = 900): EntityRequestAccessFromOtp { if (is_null($state)) $state = new RequestAccessState(RequestAccessState::REQUESTED); - if (is_null($lifetime)) $lifetime = EntityRequestAccessFromOtp::LIFETIME; - $numberOfAttemptsLimit = 3; return new EntityRequestAccessFromOtp( FixtureApplication::get(), @@ -28,9 +26,9 @@ public static function get(?RequestAccessState $state = null, int $lifetime = nu ); } - public static function getExpired(?RequestAccessState $state = null): EntityRequestAccessFromOtp + public static function getExpired(?RequestAccessState $state = null, int $numberOfAttemptsLimit = 3): EntityRequestAccessFromOtp { - return self::get($state, -9999); + return self::get($state, $numberOfAttemptsLimit, -9999); } public static function getVerified(): EntityRequestAccessFromOtp diff --git a/component/Fixture/DataStructure/RequestAccessFromThirdParty.php b/component/Fixture/DataStructure/RequestAccessFromThirdParty.php index d25e83e..4cb6f29 100644 --- a/component/Fixture/DataStructure/RequestAccessFromThirdParty.php +++ b/component/Fixture/DataStructure/RequestAccessFromThirdParty.php @@ -11,10 +11,9 @@ final class RequestAccessFromThirdParty { - public static function get(?RequestAccessState $state = null, int $lifetime = null): EntityRequestAccessFromThirdParty + public static function get(?RequestAccessState $state = null, int $lifetime = 900): EntityRequestAccessFromThirdParty { if (is_null($state)) $state = new RequestAccessState(RequestAccessState::REQUESTED); - if (is_null($lifetime)) $lifetime = EntityRequestAccessFromThirdParty::LIFETIME; return new EntityRequestAccessFromThirdParty( FixtureApplication::get(), diff --git a/test/Domain/DataStructure/RequestAccessFromApiKeyTest.php b/test/Domain/DataStructure/RequestAccessFromApiKeyTest.php index b4356f9..44bb65b 100644 --- a/test/Domain/DataStructure/RequestAccessFromApiKeyTest.php +++ b/test/Domain/DataStructure/RequestAccessFromApiKeyTest.php @@ -28,7 +28,8 @@ public function setUp(): void public function testConstruct(): void { $entity = new RequestAccessFromApiKey( - FixtureApplication::get()->apiKey + FixtureApplication::get()->apiKey, + 300 ); $this->assertIsObject($entity); diff --git a/test/Domain/DataStructure/RequestAccessFromOtpTest.php b/test/Domain/DataStructure/RequestAccessFromOtpTest.php index 0ae6632..fad8623 100644 --- a/test/Domain/DataStructure/RequestAccessFromOtpTest.php +++ b/test/Domain/DataStructure/RequestAccessFromOtpTest.php @@ -32,7 +32,8 @@ public function testConstruct(): void $entity = new RequestAccessFromOtp( FixtureApplication::get(), FixtureUser::get(), - 3 + 3, + 900 ); $this->assertIsObject($entity); diff --git a/test/Domain/DataStructure/RequestAccessFromThirdPartyTest.php b/test/Domain/DataStructure/RequestAccessFromThirdPartyTest.php index 4babb7a..7e1cdeb 100644 --- a/test/Domain/DataStructure/RequestAccessFromThirdPartyTest.php +++ b/test/Domain/DataStructure/RequestAccessFromThirdPartyTest.php @@ -26,7 +26,8 @@ public function setUp(): void public function testConstruct(): void { $entity = new RequestAccessFromThirdParty( - FixtureApplication::get() + FixtureApplication::get(), + 900 ); $this->assertIsObject($entity); From 1f3e477e7292876aee6deb7121851b08b4ff198a Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Tue, 20 Sep 2022 17:11:15 +0200 Subject: [PATCH 26/42] Allow access token lifetime set up --- component/Domain/DataStructure/AccessToken.php | 7 +++---- component/Domain/Service/AccessToken.php | 15 +++++++++------ component/Fixture/DataStructure/AccessToken.php | 3 ++- test/Domain/DataStructure/AccessTokenTest.php | 5 +++-- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/component/Domain/DataStructure/AccessToken.php b/component/Domain/DataStructure/AccessToken.php index 27efd5b..6555844 100644 --- a/component/Domain/DataStructure/AccessToken.php +++ b/component/Domain/DataStructure/AccessToken.php @@ -21,12 +21,11 @@ final class AccessToken extends \Phant\DataStructure\Abstract\Entity { public const PAYLOAD_KEY_APP = 'app'; public const PAYLOAD_KEY_USER = 'user'; - public const LIFETIME = 10800; protected string $value; protected int $lifetime; - public function __construct(string $value, int $lifetime = self::LIFETIME) + public function __construct(string $value, int $lifetime) { $this->value = $value; $this->lifetime = $lifetime; @@ -74,7 +73,7 @@ public function getPayload(SslKey $sslKey): ?array } } - public static function generate(SslKey $sslKey, Application $application, ?User $user = null, int $lifetime = self::LIFETIME): self + public static function generate(SslKey $sslKey, Application $application, ?User $user, int $lifetime): self { $payload = [ self::PAYLOAD_KEY_APP => SerializeApplication::serialize($application), @@ -84,6 +83,6 @@ public static function generate(SslKey $sslKey, Application $application, ?User $payload[ self::PAYLOAD_KEY_USER ] = SerializeUser::serialize($user); } - return new self((string)Jwt::encode($sslKey->getPrivate(), $payload, $lifetime)); + return new self((string)Jwt::encode($sslKey->getPrivate(), $payload, $lifetime), $lifetime); } } diff --git a/component/Domain/Service/AccessToken.php b/component/Domain/Service/AccessToken.php index c387950..2b1668d 100644 --- a/component/Domain/Service/AccessToken.php +++ b/component/Domain/Service/AccessToken.php @@ -19,6 +19,8 @@ final class AccessToken { + public const LIFETIME = 86400; // 24h + protected SslKey $sslKey; protected ServiceRequestAccess $serviceRequestAccess; @@ -36,15 +38,15 @@ public function getPublicKey(): string return $this->sslKey->getPublic(); } - public function check(string $accessToken, Application $application): bool + public function check(string $accessToken, Application $application, int $lifetime = self::LIFETIME): bool { - return (new EntityAccessToken($accessToken))->check( + return (new EntityAccessToken($accessToken, $lifetime))->check( $this->sslKey, $application ); } - public function getFromRequestAccessToken(RequestAccess $requestAccess): EntityAccessToken + public function getFromRequestAccessToken(RequestAccess $requestAccess, int $lifetime = self::LIFETIME): EntityAccessToken { // Check request access status if (!$requestAccess->canBeSetStateTo(new RequestAccessState(RequestAccessState::GRANTED))) { @@ -55,7 +57,8 @@ public function getFromRequestAccessToken(RequestAccess $requestAccess): EntityA $accessToken = EntityAccessToken::generate( $this->sslKey, $requestAccess->getApplication(), - $requestAccess->getUser() + $requestAccess->getUser(), + $lifetime ); // Change state @@ -67,9 +70,9 @@ public function getFromRequestAccessToken(RequestAccess $requestAccess): EntityA return $accessToken; } - public function getUserInfos(string $accessToken): ?array + public function getUserInfos(string $accessToken, int $lifetime = self::LIFETIME): ?array { - $payLoad = (new EntityAccessToken($accessToken))->getPayload($this->sslKey); + $payLoad = (new EntityAccessToken($accessToken, $lifetime))->getPayload($this->sslKey); if (!isset($payLoad[ EntityAccessToken::PAYLOAD_KEY_USER ])) return null; diff --git a/component/Fixture/DataStructure/AccessToken.php b/component/Fixture/DataStructure/AccessToken.php index 810d6c0..011fa6e 100644 --- a/component/Fixture/DataStructure/AccessToken.php +++ b/component/Fixture/DataStructure/AccessToken.php @@ -18,7 +18,8 @@ public static function get(): EntityAccessToken return EntityAccessToken::generate( FixtureSslKey::get(), FixtureApplication::get(), - FixtureUser::get() + FixtureUser::get(), + 86400 ); } diff --git a/test/Domain/DataStructure/AccessTokenTest.php b/test/Domain/DataStructure/AccessTokenTest.php index 5450e2b..d1626b1 100644 --- a/test/Domain/DataStructure/AccessTokenTest.php +++ b/test/Domain/DataStructure/AccessTokenTest.php @@ -23,7 +23,7 @@ public function setUp(): void public function testConstruct(): void { - $entity = new AccessToken($this->fixture->getValue()); + $entity = new AccessToken($this->fixture->getValue(), 86400); $this->assertIsObject($entity); $this->assertInstanceOf(AccessToken::class, $entity); @@ -76,7 +76,8 @@ public function testGenerate(): void $entity = AccessToken::generate( FixtureSslKey::get(), FixtureApplication::get(), - FixtureUser::get() + FixtureUser::get(), + 86400 ); $this->assertIsObject($entity); From 0d70153c9e2a85d33b2fb3d4ba975f8b681f8a52 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Wed, 21 Sep 2022 09:17:02 +0200 Subject: [PATCH 27/42] Add token expire date --- component/Domain/DataStructure/AccessToken.php | 10 ++++++++-- component/Domain/DataStructure/Value/Expire.php | 8 ++++++++ test/Domain/DataStructure/AccessTokenTest.php | 9 +++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 component/Domain/DataStructure/Value/Expire.php diff --git a/component/Domain/DataStructure/AccessToken.php b/component/Domain/DataStructure/AccessToken.php index 6555844..308d8db 100644 --- a/component/Domain/DataStructure/AccessToken.php +++ b/component/Domain/DataStructure/AccessToken.php @@ -8,6 +8,7 @@ User, }; use Phant\Auth\Domain\DataStructure\Value\{ + Expire, IdApplication, Jwt, SslKey, @@ -23,12 +24,12 @@ final class AccessToken extends \Phant\DataStructure\Abstract\Entity public const PAYLOAD_KEY_USER = 'user'; protected string $value; - protected int $lifetime; + protected Expire $expire; public function __construct(string $value, int $lifetime) { $this->value = $value; - $this->lifetime = $lifetime; + $this->expire = new Expire(date('Y-m-d', time() + $lifetime)); } public function getValue(): string @@ -36,6 +37,11 @@ public function getValue(): string return $this->value; } + public function getExpire(): Expire + { + return $this->expire; + } + public function __toString(): string { return $this->getValue(); diff --git a/component/Domain/DataStructure/Value/Expire.php b/component/Domain/DataStructure/Value/Expire.php new file mode 100644 index 0000000..0ef1c62 --- /dev/null +++ b/component/Domain/DataStructure/Value/Expire.php @@ -0,0 +1,8 @@ +assertInstanceOf(AccessToken::class, $entity); } + public function testGetExpire(): void + { + $value = $this->fixture->getExpire(); + + $this->assertIsObject($value); + $this->assertInstanceOf(Expire::class, $value); + } + public function testCheck(): void { $result = $this->fixture->check( From f73ed5eb1b9c656005f3fc54d7e798c0d8e68da4 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Wed, 21 Sep 2022 09:17:12 +0200 Subject: [PATCH 28/42] Access token serialize --- component/Domain/Serialize/AccessToken.php | 17 ++++++++++++ test/Domain/Serialize/AccessTokenTest.php | 31 ++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 component/Domain/Serialize/AccessToken.php create mode 100644 test/Domain/Serialize/AccessTokenTest.php diff --git a/component/Domain/Serialize/AccessToken.php b/component/Domain/Serialize/AccessToken.php new file mode 100644 index 0000000..fb6147c --- /dev/null +++ b/component/Domain/Serialize/AccessToken.php @@ -0,0 +1,17 @@ + (string) $accessToken->getValue(), + 'expire' => (string) $accessToken->getExpire()->getUtc(), + ]; + } +} diff --git a/test/Domain/Serialize/AccessTokenTest.php b/test/Domain/Serialize/AccessTokenTest.php new file mode 100644 index 0000000..b89952d --- /dev/null +++ b/test/Domain/Serialize/AccessTokenTest.php @@ -0,0 +1,31 @@ +fixture = FixtureAccessToken::get(); + } + + public function testSerialize(): void + { + $value = SerializeAccessToken::serialize( + $this->fixture + ); + + $this->assertIsArray($value); + $this->assertCount(2, $value); + $this->assertArrayHasKey('token', $value); + $this->assertArrayHasKey('expire', $value); + } +} From e156d48e8431680ebb663768c1bdf10a66e5849c Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Wed, 21 Sep 2022 09:45:10 +0200 Subject: [PATCH 29/42] Add search by id --- .../Value/CollectionApplication.php | 15 +++++++++++++++ .../Value/CollectionApplicationTest.php | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/component/Domain/DataStructure/Value/CollectionApplication.php b/component/Domain/DataStructure/Value/CollectionApplication.php index e0303ac..1c75579 100644 --- a/component/Domain/DataStructure/Value/CollectionApplication.php +++ b/component/Domain/DataStructure/Value/CollectionApplication.php @@ -4,6 +4,10 @@ namespace Phant\Auth\Domain\DataStructure\Value; use Phant\Auth\Domain\DataStructure\Application; +use Phant\Auth\Domain\DataStructure\Value\{ + ApiKey, + IdApplication, +}; final class CollectionApplication extends \Phant\DataStructure\Abstract\Collection { @@ -12,6 +16,17 @@ public function addApplication(Application $entity) parent::addItem($entity); } + public function searchById(string|IdApplication $id): ?Application + { + if (is_string($id)) $id = new IdApplication($id); + + foreach ($this->itemsIterator() as $entity) { + if ($entity->isHisId($id)) return $entity; + } + + return null; + } + public function searchByApiKey(string|ApiKey $apiKey): ?Application { if (is_string($apiKey)) $apiKey = new ApiKey($apiKey); diff --git a/test/Domain/DataStructure/Value/CollectionApplicationTest.php b/test/Domain/DataStructure/Value/CollectionApplicationTest.php index fa1c464..1259539 100644 --- a/test/Domain/DataStructure/Value/CollectionApplicationTest.php +++ b/test/Domain/DataStructure/Value/CollectionApplicationTest.php @@ -23,6 +23,25 @@ public function testAddApplication(): void $this->assertEquals(1, $collection->getNbItems()); } + public function testSearchById(): void + { + $collection = FixtureApplication::getCollection(); + + $result = $collection->searchById( + FixtureApplication::get()->id + ); + + $this->assertIsObject($result); + + $collection = FixtureApplication::getCollection(); + + $result = $collection->searchById( + '1b3f18e5-c12d-4063-bf27-d77c2558ea1a' + ); + + $this->assertNull($result); + } + public function testSearchByApiKey(): void { $collection = FixtureApplication::getCollection(); From 8ba946f151b01ecf23c592513f5a71e0806a2492 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Wed, 21 Sep 2022 09:46:40 +0200 Subject: [PATCH 30/42] Refacto ApplicationId --- component/Domain/DataStructure/AccessToken.php | 8 ++++---- component/Domain/DataStructure/Application.php | 10 +++++----- .../Value/{IdApplication.php => ApplicationId.php} | 2 +- .../DataStructure/Value/CollectionApplication.php | 6 +++--- component/Domain/Port/Application.php | 4 ++-- component/Domain/Service/Application.php | 8 ++++---- component/Fixture/DataStructure/Application.php | 4 ++-- component/Fixture/Port/Application.php | 4 ++-- test/Domain/DataStructure/ApplicationTest.php | 6 +++--- 9 files changed, 26 insertions(+), 26 deletions(-) rename component/Domain/DataStructure/Value/{IdApplication.php => ApplicationId.php} (57%) diff --git a/component/Domain/DataStructure/AccessToken.php b/component/Domain/DataStructure/AccessToken.php index 308d8db..5ae25f6 100644 --- a/component/Domain/DataStructure/AccessToken.php +++ b/component/Domain/DataStructure/AccessToken.php @@ -9,7 +9,7 @@ }; use Phant\Auth\Domain\DataStructure\Value\{ Expire, - IdApplication, + ApplicationId, Jwt, SslKey, }; @@ -53,11 +53,11 @@ public function check(SslKey $sslKey, Application $application): bool $payload = (new Jwt($this->value))->decode($sslKey->getPublic()); - $idApplication = $payload[ self::PAYLOAD_KEY_APP ]->id ?? null; + $ApplicationId = $payload[ self::PAYLOAD_KEY_APP ]->id ?? null; - if (!$idApplication) return false; + if (!$ApplicationId) return false; - if (!$application->isHisId(new IdApplication($idApplication))) return false; + if (!$application->isHisId(new ApplicationId($ApplicationId))) return false; } catch (\Exception $e) { return false; diff --git a/component/Domain/DataStructure/Application.php b/component/Domain/DataStructure/Application.php index 363f298..70e97c5 100644 --- a/component/Domain/DataStructure/Application.php +++ b/component/Domain/DataStructure/Application.php @@ -6,25 +6,25 @@ use Phant\Auth\Domain\DataStructure\Value\{ ApiKey, ApplicationName, - IdApplication, + ApplicationId, Logo, }; final class Application extends \Phant\DataStructure\Abstract\Entity { - public IdApplication $id; + public ApplicationId $id; public ApplicationName $name; public ?Logo $logo; public ApiKey $apiKey; public function __construct( - null|string|IdApplication $id, + null|string|ApplicationId $id, null|string|ApplicationName $name, null|string|Logo $logo, string|ApiKey $apiKey ) { - if (is_string($id)) $id = new IdApplication($id); + if (is_string($id)) $id = new ApplicationId($id); if (is_string($name)) $name = new ApplicationName($name); if (is_string($logo)) $logo = new Logo($logo); @@ -39,7 +39,7 @@ public function isHisApiKey(ApiKey $apiKey): bool return ((string)$this->apiKey === (string)$apiKey); } - public function isHisId(IdApplication $id): bool + public function isHisId(ApplicationId $id): bool { return ((string)$this->id === (string)$id); } diff --git a/component/Domain/DataStructure/Value/IdApplication.php b/component/Domain/DataStructure/Value/ApplicationId.php similarity index 57% rename from component/Domain/DataStructure/Value/IdApplication.php rename to component/Domain/DataStructure/Value/ApplicationId.php index 46ab8cc..dcce19b 100644 --- a/component/Domain/DataStructure/Value/IdApplication.php +++ b/component/Domain/DataStructure/Value/ApplicationId.php @@ -3,6 +3,6 @@ namespace Phant\Auth\Domain\DataStructure\Value; -final class IdApplication extends \Phant\DataStructure\Id\Uuid +final class ApplicationId extends \Phant\DataStructure\Id\Uuid { } diff --git a/component/Domain/DataStructure/Value/CollectionApplication.php b/component/Domain/DataStructure/Value/CollectionApplication.php index 1c75579..2e5c595 100644 --- a/component/Domain/DataStructure/Value/CollectionApplication.php +++ b/component/Domain/DataStructure/Value/CollectionApplication.php @@ -6,7 +6,7 @@ use Phant\Auth\Domain\DataStructure\Application; use Phant\Auth\Domain\DataStructure\Value\{ ApiKey, - IdApplication, + ApplicationId, }; final class CollectionApplication extends \Phant\DataStructure\Abstract\Collection @@ -16,9 +16,9 @@ public function addApplication(Application $entity) parent::addItem($entity); } - public function searchById(string|IdApplication $id): ?Application + public function searchById(string|ApplicationId $id): ?Application { - if (is_string($id)) $id = new IdApplication($id); + if (is_string($id)) $id = new ApplicationId($id); foreach ($this->itemsIterator() as $entity) { if ($entity->isHisId($id)) return $entity; diff --git a/component/Domain/Port/Application.php b/component/Domain/Port/Application.php index 29e46a6..3f60c7a 100644 --- a/component/Domain/Port/Application.php +++ b/component/Domain/Port/Application.php @@ -7,13 +7,13 @@ use Phant\Auth\Domain\DataStructure\Value\{ ApiKey, CollectionApplication, - IdApplication, + ApplicationId, }; interface Application { public function set(EntityApplication $application): void; - public function get(IdApplication $id): EntityApplication; + public function get(ApplicationId $id): EntityApplication; public function getFromApiKey(ApiKey $apiKey): EntityApplication; public function getList(): CollectionApplication; } diff --git a/component/Domain/Service/Application.php b/component/Domain/Service/Application.php index 1a0964f..feed3cf 100644 --- a/component/Domain/Service/Application.php +++ b/component/Domain/Service/Application.php @@ -9,7 +9,7 @@ use Phant\Auth\Domain\DataStructure\Value\{ ApiKey, ApplicationName, - IdApplication, + ApplicationId, Logo, }; @@ -27,7 +27,7 @@ public function __construct( public function add(string $name, ?string $logo = null): EntityApplication { $application = new EntityApplication( - IdApplication::generate(), + ApplicationId::generate(), new ApplicationName($name), $logo ? new Logo($logo) : null, ApiKey::generate() @@ -43,9 +43,9 @@ public function set(EntityApplication $application): void $this->repository->set($application); } - public function get(string|IdApplication $id): EntityApplication + public function get(string|ApplicationId $id): EntityApplication { - if (is_string($id)) $id = new IdApplication($id); + if (is_string($id)) $id = new ApplicationId($id); return $this->repository->get($id); } diff --git a/component/Fixture/DataStructure/Application.php b/component/Fixture/DataStructure/Application.php index 39b0fbe..d87d269 100644 --- a/component/Fixture/DataStructure/Application.php +++ b/component/Fixture/DataStructure/Application.php @@ -8,7 +8,7 @@ ApiKey, ApplicationName, CollectionApplication, - IdApplication, + ApplicationId, Logo, }; @@ -58,7 +58,7 @@ public static function getCollection(): CollectionApplication private static function buildFromDatas(array $datas): EntityApplication { return new EntityApplication( - new IdApplication($datas['id']), + new ApplicationId($datas['id']), new ApplicationName($datas['name']), new Logo($datas['logo']), new ApiKey($datas['api_key']) diff --git a/component/Fixture/Port/Application.php b/component/Fixture/Port/Application.php index 5e2b9fb..0e79cd0 100644 --- a/component/Fixture/Port/Application.php +++ b/component/Fixture/Port/Application.php @@ -7,7 +7,7 @@ use Phant\Auth\Domain\DataStructure\Value\{ ApiKey, CollectionApplication, - IdApplication, + ApplicationId, }; use Psr\SimpleCache\CacheInterface; @@ -29,7 +29,7 @@ public function set(EntityApplication $application): void $this->cache->set((string)$application->id, $application); } - public function get(IdApplication $id): EntityApplication + public function get(ApplicationId $id): EntityApplication { $entity = $this->cache->get((string)$id); if ($entity) return $entity; diff --git a/test/Domain/DataStructure/ApplicationTest.php b/test/Domain/DataStructure/ApplicationTest.php index 9ea1fe2..9aeeae1 100644 --- a/test/Domain/DataStructure/ApplicationTest.php +++ b/test/Domain/DataStructure/ApplicationTest.php @@ -7,7 +7,7 @@ use Phant\Auth\Domain\DataStructure\Value\{ ApiKey, ApplicationName, - IdApplication, + ApplicationId, Logo, }; @@ -25,7 +25,7 @@ public function setUp(): void public function testConstruct(): void { $entity = new Application( - IdApplication::generate(), + ApplicationId::generate(), new ApplicationName('Foo bar'), new Logo('https://domain.ext/file.ext'), ApiKey::generate() @@ -68,7 +68,7 @@ public function testIsHisId(): void public function testIsHisIdInvalid(): void { $result = $this->fixture->isHisId( - IdApplication::generate() + ApplicationId::generate() ); $this->assertIsBool($result); From 10e8d552c155d6600b876a4c963887c54dc48197 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Wed, 21 Sep 2022 09:47:29 +0200 Subject: [PATCH 31/42] Refacto ApplicationLogo --- component/Domain/DataStructure/Application.php | 8 ++++---- .../DataStructure/Value/{Logo.php => ApplicationLogo.php} | 2 +- component/Domain/Service/Application.php | 4 ++-- component/Fixture/DataStructure/Application.php | 4 ++-- test/Domain/DataStructure/ApplicationTest.php | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) rename component/Domain/DataStructure/Value/{Logo.php => ApplicationLogo.php} (56%) diff --git a/component/Domain/DataStructure/Application.php b/component/Domain/DataStructure/Application.php index 70e97c5..6045d30 100644 --- a/component/Domain/DataStructure/Application.php +++ b/component/Domain/DataStructure/Application.php @@ -7,26 +7,26 @@ ApiKey, ApplicationName, ApplicationId, - Logo, + ApplicationLogo, }; final class Application extends \Phant\DataStructure\Abstract\Entity { public ApplicationId $id; public ApplicationName $name; - public ?Logo $logo; + public ?ApplicationLogo $logo; public ApiKey $apiKey; public function __construct( null|string|ApplicationId $id, null|string|ApplicationName $name, - null|string|Logo $logo, + null|string|ApplicationLogo $logo, string|ApiKey $apiKey ) { if (is_string($id)) $id = new ApplicationId($id); if (is_string($name)) $name = new ApplicationName($name); - if (is_string($logo)) $logo = new Logo($logo); + if (is_string($logo)) $logo = new ApplicationLogo($logo); $this->id = $id; $this->name = $name; diff --git a/component/Domain/DataStructure/Value/Logo.php b/component/Domain/DataStructure/Value/ApplicationLogo.php similarity index 56% rename from component/Domain/DataStructure/Value/Logo.php rename to component/Domain/DataStructure/Value/ApplicationLogo.php index 847fdcd..27de747 100644 --- a/component/Domain/DataStructure/Value/Logo.php +++ b/component/Domain/DataStructure/Value/ApplicationLogo.php @@ -3,6 +3,6 @@ namespace Phant\Auth\Domain\DataStructure\Value; -final class Logo extends \Phant\DataStructure\Web\Url +final class ApplicationLogo extends \Phant\DataStructure\Web\Url { } diff --git a/component/Domain/Service/Application.php b/component/Domain/Service/Application.php index feed3cf..82b3243 100644 --- a/component/Domain/Service/Application.php +++ b/component/Domain/Service/Application.php @@ -10,7 +10,7 @@ ApiKey, ApplicationName, ApplicationId, - Logo, + ApplicationLogo, }; final class Application @@ -29,7 +29,7 @@ public function add(string $name, ?string $logo = null): EntityApplication $application = new EntityApplication( ApplicationId::generate(), new ApplicationName($name), - $logo ? new Logo($logo) : null, + $logo ? new ApplicationLogo($logo) : null, ApiKey::generate() ); diff --git a/component/Fixture/DataStructure/Application.php b/component/Fixture/DataStructure/Application.php index d87d269..190a181 100644 --- a/component/Fixture/DataStructure/Application.php +++ b/component/Fixture/DataStructure/Application.php @@ -9,7 +9,7 @@ ApplicationName, CollectionApplication, ApplicationId, - Logo, + ApplicationLogo, }; final class Application @@ -60,7 +60,7 @@ private static function buildFromDatas(array $datas): EntityApplication return new EntityApplication( new ApplicationId($datas['id']), new ApplicationName($datas['name']), - new Logo($datas['logo']), + new ApplicationLogo($datas['logo']), new ApiKey($datas['api_key']) ); } diff --git a/test/Domain/DataStructure/ApplicationTest.php b/test/Domain/DataStructure/ApplicationTest.php index 9aeeae1..62b6d44 100644 --- a/test/Domain/DataStructure/ApplicationTest.php +++ b/test/Domain/DataStructure/ApplicationTest.php @@ -8,7 +8,7 @@ ApiKey, ApplicationName, ApplicationId, - Logo, + ApplicationLogo, }; use Phant\Auth\Fixture\DataStructure\Application as FixtureApplication; @@ -27,7 +27,7 @@ public function testConstruct(): void $entity = new Application( ApplicationId::generate(), new ApplicationName('Foo bar'), - new Logo('https://domain.ext/file.ext'), + new ApplicationLogo('https://domain.ext/file.ext'), ApiKey::generate() ); From de941754831aa084bf5e6008e98d8629845bf909 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Wed, 21 Sep 2022 09:48:59 +0200 Subject: [PATCH 32/42] Refacto UserEmailAddress --- component/Domain/DataStructure/User.php | 8 ++++---- .../Value/{EmailAddress.php => UserEmailAddress.php} | 2 +- component/Fixture/DataStructure/User.php | 4 ++-- test/Domain/DataStructure/UserTest.php | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) rename component/Domain/DataStructure/Value/{EmailAddress.php => UserEmailAddress.php} (53%) diff --git a/component/Domain/DataStructure/User.php b/component/Domain/DataStructure/User.php index c1dd189..d7c42ff 100644 --- a/component/Domain/DataStructure/User.php +++ b/component/Domain/DataStructure/User.php @@ -4,7 +4,7 @@ namespace Phant\Auth\Domain\DataStructure; use Phant\Auth\Domain\DataStructure\Value\{ - EmailAddress, + UserEmailAddress, Firstname, Lastname, Role, @@ -12,19 +12,19 @@ final class User extends \Phant\DataStructure\Abstract\Entity { - public ?EmailAddress $emailAddress; + public ?UserEmailAddress $emailAddress; public ?Lastname $lastname; public ?Firstname $firstname; public ?Role $role; public function __construct( - null|string|EmailAddress $emailAddress, + null|string|UserEmailAddress $emailAddress, null|string|Lastname $lastname, null|string|Firstname $firstname, null|Role $role = null ) { - if (is_string($emailAddress)) $emailAddress = new EmailAddress($emailAddress); + if (is_string($emailAddress)) $emailAddress = new UserEmailAddress($emailAddress); if (is_string($lastname)) $lastname = new Lastname($lastname); if (is_string($firstname)) $firstname = new Firstname($firstname); diff --git a/component/Domain/DataStructure/Value/EmailAddress.php b/component/Domain/DataStructure/Value/UserEmailAddress.php similarity index 53% rename from component/Domain/DataStructure/Value/EmailAddress.php rename to component/Domain/DataStructure/Value/UserEmailAddress.php index e8e2d19..a2bf7fb 100644 --- a/component/Domain/DataStructure/Value/EmailAddress.php +++ b/component/Domain/DataStructure/Value/UserEmailAddress.php @@ -3,6 +3,6 @@ namespace Phant\Auth\Domain\DataStructure\Value; -final class EmailAddress extends \Phant\DataStructure\Web\EmailAddress +final class UserEmailAddress extends \Phant\DataStructure\Web\EmailAddress { } diff --git a/component/Fixture/DataStructure/User.php b/component/Fixture/DataStructure/User.php index f3f6feb..7cae7c7 100644 --- a/component/Fixture/DataStructure/User.php +++ b/component/Fixture/DataStructure/User.php @@ -5,7 +5,7 @@ use Phant\Auth\Domain\DataStructure\User as EntityUser; use Phant\Auth\Domain\DataStructure\Value\{ - EmailAddress, + UserEmailAddress, Firstname, Lastname, Role, @@ -16,7 +16,7 @@ final class User public static function get(): EntityUser { return new EntityUser( - new EmailAddress('john.doe@domain.ext'), + new UserEmailAddress('john.doe@domain.ext'), new Lastname('DOE'), new Firstname('John'), null diff --git a/test/Domain/DataStructure/UserTest.php b/test/Domain/DataStructure/UserTest.php index 14ec72e..5c5fd73 100644 --- a/test/Domain/DataStructure/UserTest.php +++ b/test/Domain/DataStructure/UserTest.php @@ -5,7 +5,7 @@ use Phant\Auth\Domain\DataStructure\User; use Phant\Auth\Domain\DataStructure\Value\{ - EmailAddress, + UserEmailAddress, Firstname, Lastname, Role, From c82b1e77c168aa6df1ccc18b7b0bbe54f4ed7884 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Wed, 21 Sep 2022 09:49:30 +0200 Subject: [PATCH 33/42] Refacto UserRole --- component/Domain/DataStructure/User.php | 6 +++--- .../Domain/DataStructure/Value/{Role.php => UserRole.php} | 2 +- component/Fixture/DataStructure/User.php | 2 +- test/Domain/DataStructure/UserTest.php | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) rename component/Domain/DataStructure/Value/{Role.php => UserRole.php} (56%) diff --git a/component/Domain/DataStructure/User.php b/component/Domain/DataStructure/User.php index d7c42ff..a41e14f 100644 --- a/component/Domain/DataStructure/User.php +++ b/component/Domain/DataStructure/User.php @@ -7,7 +7,7 @@ UserEmailAddress, Firstname, Lastname, - Role, + UserRole, }; final class User extends \Phant\DataStructure\Abstract\Entity @@ -15,13 +15,13 @@ final class User extends \Phant\DataStructure\Abstract\Entity public ?UserEmailAddress $emailAddress; public ?Lastname $lastname; public ?Firstname $firstname; - public ?Role $role; + public ?UserRole $role; public function __construct( null|string|UserEmailAddress $emailAddress, null|string|Lastname $lastname, null|string|Firstname $firstname, - null|Role $role = null + null|UserRole $role = null ) { if (is_string($emailAddress)) $emailAddress = new UserEmailAddress($emailAddress); diff --git a/component/Domain/DataStructure/Value/Role.php b/component/Domain/DataStructure/Value/UserRole.php similarity index 56% rename from component/Domain/DataStructure/Value/Role.php rename to component/Domain/DataStructure/Value/UserRole.php index 45ed736..9510c06 100644 --- a/component/Domain/DataStructure/Value/Role.php +++ b/component/Domain/DataStructure/Value/UserRole.php @@ -3,6 +3,6 @@ namespace Phant\Auth\Domain\DataStructure\Value; -abstract class Role extends \Phant\DataStructure\Abstract\Enum +abstract class UserRole extends \Phant\DataStructure\Abstract\Enum { } diff --git a/component/Fixture/DataStructure/User.php b/component/Fixture/DataStructure/User.php index 7cae7c7..a74aac5 100644 --- a/component/Fixture/DataStructure/User.php +++ b/component/Fixture/DataStructure/User.php @@ -8,7 +8,7 @@ UserEmailAddress, Firstname, Lastname, - Role, + UserRole, }; final class User diff --git a/test/Domain/DataStructure/UserTest.php b/test/Domain/DataStructure/UserTest.php index 5c5fd73..0baa3e2 100644 --- a/test/Domain/DataStructure/UserTest.php +++ b/test/Domain/DataStructure/UserTest.php @@ -8,7 +8,7 @@ UserEmailAddress, Firstname, Lastname, - Role, + UserRole, }; use Phant\Auth\Fixture\DataStructure\User as FixtureUser; From d6eaecdec0f2ddab754697d6d924cdfd7d64c3a0 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Wed, 21 Sep 2022 09:50:06 +0200 Subject: [PATCH 34/42] Refacto UserFirstname --- component/Domain/DataStructure/User.php | 8 ++++---- .../Value/{Firstname.php => UserFirstname.php} | 2 +- component/Fixture/DataStructure/User.php | 4 ++-- test/Domain/DataStructure/UserTest.php | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) rename component/Domain/DataStructure/Value/{Firstname.php => UserFirstname.php} (54%) diff --git a/component/Domain/DataStructure/User.php b/component/Domain/DataStructure/User.php index a41e14f..77ed1f1 100644 --- a/component/Domain/DataStructure/User.php +++ b/component/Domain/DataStructure/User.php @@ -5,7 +5,7 @@ use Phant\Auth\Domain\DataStructure\Value\{ UserEmailAddress, - Firstname, + UserFirstname, Lastname, UserRole, }; @@ -14,19 +14,19 @@ final class User extends \Phant\DataStructure\Abstract\Entity { public ?UserEmailAddress $emailAddress; public ?Lastname $lastname; - public ?Firstname $firstname; + public ?UserFirstname $firstname; public ?UserRole $role; public function __construct( null|string|UserEmailAddress $emailAddress, null|string|Lastname $lastname, - null|string|Firstname $firstname, + null|string|UserFirstname $firstname, null|UserRole $role = null ) { if (is_string($emailAddress)) $emailAddress = new UserEmailAddress($emailAddress); if (is_string($lastname)) $lastname = new Lastname($lastname); - if (is_string($firstname)) $firstname = new Firstname($firstname); + if (is_string($firstname)) $firstname = new UserFirstname($firstname); $this->emailAddress = $emailAddress; $this->lastname = $lastname; diff --git a/component/Domain/DataStructure/Value/Firstname.php b/component/Domain/DataStructure/Value/UserFirstname.php similarity index 54% rename from component/Domain/DataStructure/Value/Firstname.php rename to component/Domain/DataStructure/Value/UserFirstname.php index f60bbf9..4283b47 100644 --- a/component/Domain/DataStructure/Value/Firstname.php +++ b/component/Domain/DataStructure/Value/UserFirstname.php @@ -3,6 +3,6 @@ namespace Phant\Auth\Domain\DataStructure\Value; -final class Firstname extends \Phant\DataStructure\Person\Firstname +final class UserFirstname extends \Phant\DataStructure\Person\Firstname { } diff --git a/component/Fixture/DataStructure/User.php b/component/Fixture/DataStructure/User.php index a74aac5..2189b04 100644 --- a/component/Fixture/DataStructure/User.php +++ b/component/Fixture/DataStructure/User.php @@ -6,7 +6,7 @@ use Phant\Auth\Domain\DataStructure\User as EntityUser; use Phant\Auth\Domain\DataStructure\Value\{ UserEmailAddress, - Firstname, + UserFirstname, Lastname, UserRole, }; @@ -18,7 +18,7 @@ public static function get(): EntityUser return new EntityUser( new UserEmailAddress('john.doe@domain.ext'), new Lastname('DOE'), - new Firstname('John'), + new UserFirstname('John'), null ); } diff --git a/test/Domain/DataStructure/UserTest.php b/test/Domain/DataStructure/UserTest.php index 0baa3e2..52eb477 100644 --- a/test/Domain/DataStructure/UserTest.php +++ b/test/Domain/DataStructure/UserTest.php @@ -6,7 +6,7 @@ use Phant\Auth\Domain\DataStructure\User; use Phant\Auth\Domain\DataStructure\Value\{ UserEmailAddress, - Firstname, + UserFirstname, Lastname, UserRole, }; From be19fa69a746b068164f720d572aec9229c8cfab Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Wed, 21 Sep 2022 10:28:06 +0200 Subject: [PATCH 35/42] Refacto value objects --- .../Domain/DataStructure/AccessToken.php | 12 +- .../{Value => AccessToken}/Expire.php | 2 +- .../Domain/DataStructure/AccessToken/Id.php | 8 ++ .../{Value => AccessToken}/Jwt.php | 2 +- .../Domain/DataStructure/Application.php | 34 ++--- .../{Value => Application}/ApiKey.php | 2 +- .../Collection.php} | 12 +- .../Domain/DataStructure/Application/Id.php | 8 ++ .../Domain/DataStructure/Application/Logo.php | 8 ++ .../Name.php} | 4 +- .../Domain/DataStructure/RequestAccess.php | 35 +++-- .../{Value => RequestAccess}/AuthMethod.php | 2 +- .../Domain/DataStructure/RequestAccess/Id.php | 8 ++ .../{Value => RequestAccess}/Otp.php | 2 +- .../State.php} | 18 +-- .../DataStructure/RequestAccess/Token.php | 8 ++ .../DataStructure/RequestAccessFromApiKey.php | 12 +- .../DataStructure/RequestAccessFromOtp.php | 10 +- .../RequestAccessFromThirdParty.php | 10 +- .../DataStructure/{Value => }/SslKey.php | 4 +- component/Domain/DataStructure/User.php | 24 ++-- .../DataStructure/User/EmailAddress.php | 8 ++ .../Domain/DataStructure/User/Firstname.php | 8 ++ .../{Value => User}/Lastname.php | 2 +- component/Domain/DataStructure/User/Role.php | 8 ++ .../DataStructure/Value/ApplicationId.php | 8 -- .../DataStructure/Value/ApplicationLogo.php | 8 -- .../DataStructure/Value/IdRequestAccess.php | 8 -- .../Value/RequestAccessToken.php | 8 -- .../DataStructure/Value/UserEmailAddress.php | 8 -- .../DataStructure/Value/UserFirstname.php | 8 -- .../Domain/DataStructure/Value/UserRole.php | 8 -- component/Domain/Port/Application.php | 10 +- component/Domain/Port/RequestAccess.php | 7 +- component/Domain/Port/UserNotification.php | 6 +- component/Domain/Service/AccessToken.php | 12 +- component/Domain/Service/Application.php | 18 +-- component/Domain/Service/RequestAccess.php | 20 +-- .../Service/RequestAccessFromApiKey.php | 14 +- .../Domain/Service/RequestAccessFromOtp.php | 22 +-- .../Service/RequestAccessFromThirdParty.php | 18 +-- .../Fixture/DataStructure/AccessToken.php | 2 +- .../Fixture/DataStructure/Application.php | 20 +-- .../DataStructure/RequestAccessFromApiKey.php | 10 +- .../DataStructure/RequestAccessFromOtp.php | 12 +- .../RequestAccessFromThirdParty.php | 10 +- .../DataStructure/{Value => }/SslKey.php | 4 +- component/Fixture/DataStructure/User.php | 12 +- component/Fixture/Port/Application.php | 10 +- component/Fixture/Port/RequestAccess.php | 4 +- component/Fixture/Port/UserNotification.php | 6 +- component/Fixture/Service/AccessToken.php | 2 +- component/Fixture/Service/RequestAccess.php | 2 +- test/Domain/DataStructure/AccessTokenTest.php | 4 +- .../{Value => Application}/ApiKeyTest.php | 4 +- .../CollectionTest.php} | 8 +- .../DataStructure/Application/NameTest.php | 26 ++++ test/Domain/DataStructure/ApplicationTest.php | 16 +-- .../AuthMethodTest.php | 4 +- .../{Value => RequestAccess}/OtpTest.php | 4 +- .../DataStructure/RequestAccess/StateTest.php | 127 ++++++++++++++++++ .../RequestAccessFromApiKeyTest.php | 6 +- .../RequestAccessFromOtpTest.php | 6 +- .../RequestAccessFromThirdPartyTest.php | 6 +- .../DataStructure/RequestAccessTest.php | 30 ++--- .../DataStructure/{Value => }/SslKeyTest.php | 6 +- test/Domain/DataStructure/UserTest.php | 8 +- .../Value/ApplicationNameTest.php | 26 ---- .../Value/RequestAccessStateTest.php | 127 ------------------ test/Domain/Service/AccessTokenTest.php | 8 +- .../Service/RequestAccessFromApiKeyTest.php | 2 +- .../Service/RequestAccessFromOtpTest.php | 8 +- .../RequestAccessFromThirdPartyTest.php | 8 +- test/Domain/Service/RequestAccessTest.php | 4 +- 74 files changed, 486 insertions(+), 480 deletions(-) rename component/Domain/DataStructure/{Value => AccessToken}/Expire.php (64%) create mode 100644 component/Domain/DataStructure/AccessToken/Id.php rename component/Domain/DataStructure/{Value => AccessToken}/Jwt.php (62%) rename component/Domain/DataStructure/{Value => Application}/ApiKey.php (93%) rename component/Domain/DataStructure/{Value/CollectionApplication.php => Application/Collection.php} (64%) create mode 100644 component/Domain/DataStructure/Application/Id.php create mode 100644 component/Domain/DataStructure/Application/Logo.php rename component/Domain/DataStructure/{Value/ApplicationName.php => Application/Name.php} (57%) rename component/Domain/DataStructure/{Value => RequestAccess}/AuthMethod.php (88%) create mode 100644 component/Domain/DataStructure/RequestAccess/Id.php rename component/Domain/DataStructure/{Value => RequestAccess}/Otp.php (91%) rename component/Domain/DataStructure/{Value/RequestAccessState.php => RequestAccess/State.php} (55%) create mode 100644 component/Domain/DataStructure/RequestAccess/Token.php rename component/Domain/DataStructure/{Value => }/SslKey.php (90%) create mode 100644 component/Domain/DataStructure/User/EmailAddress.php create mode 100644 component/Domain/DataStructure/User/Firstname.php rename component/Domain/DataStructure/{Value => User}/Lastname.php (67%) create mode 100644 component/Domain/DataStructure/User/Role.php delete mode 100644 component/Domain/DataStructure/Value/ApplicationId.php delete mode 100644 component/Domain/DataStructure/Value/ApplicationLogo.php delete mode 100644 component/Domain/DataStructure/Value/IdRequestAccess.php delete mode 100644 component/Domain/DataStructure/Value/RequestAccessToken.php delete mode 100644 component/Domain/DataStructure/Value/UserEmailAddress.php delete mode 100644 component/Domain/DataStructure/Value/UserFirstname.php delete mode 100644 component/Domain/DataStructure/Value/UserRole.php rename component/Fixture/DataStructure/{Value => }/SslKey.php (96%) rename test/Domain/DataStructure/{Value => Application}/ApiKeyTest.php (85%) rename test/Domain/DataStructure/{Value/CollectionApplicationTest.php => Application/CollectionTest.php} (84%) create mode 100644 test/Domain/DataStructure/Application/NameTest.php rename test/Domain/DataStructure/{Value => RequestAccess}/AuthMethodTest.php (81%) rename test/Domain/DataStructure/{Value => RequestAccess}/OtpTest.php (89%) create mode 100644 test/Domain/DataStructure/RequestAccess/StateTest.php rename test/Domain/DataStructure/{Value => }/SslKeyTest.php (89%) delete mode 100644 test/Domain/DataStructure/Value/ApplicationNameTest.php delete mode 100644 test/Domain/DataStructure/Value/RequestAccessStateTest.php diff --git a/component/Domain/DataStructure/AccessToken.php b/component/Domain/DataStructure/AccessToken.php index 5ae25f6..946590d 100644 --- a/component/Domain/DataStructure/AccessToken.php +++ b/component/Domain/DataStructure/AccessToken.php @@ -5,13 +5,13 @@ use Phant\Auth\Domain\DataStructure\{ Application, + SslKey, User, }; -use Phant\Auth\Domain\DataStructure\Value\{ +use Phant\Auth\Domain\DataStructure\AccessToken\{ Expire, - ApplicationId, + Id, Jwt, - SslKey, }; use Phant\Auth\Domain\Serialize\{ Application as SerializeApplication, @@ -53,11 +53,11 @@ public function check(SslKey $sslKey, Application $application): bool $payload = (new Jwt($this->value))->decode($sslKey->getPublic()); - $ApplicationId = $payload[ self::PAYLOAD_KEY_APP ]->id ?? null; + $id = $payload[ self::PAYLOAD_KEY_APP ]->id ?? null; - if (!$ApplicationId) return false; + if (!$id) return false; - if (!$application->isHisId(new ApplicationId($ApplicationId))) return false; + if (!$application->isHisId($id)) return false; } catch (\Exception $e) { return false; diff --git a/component/Domain/DataStructure/Value/Expire.php b/component/Domain/DataStructure/AccessToken/Expire.php similarity index 64% rename from component/Domain/DataStructure/Value/Expire.php rename to component/Domain/DataStructure/AccessToken/Expire.php index 0ef1c62..d698c2a 100644 --- a/component/Domain/DataStructure/Value/Expire.php +++ b/component/Domain/DataStructure/AccessToken/Expire.php @@ -1,7 +1,7 @@ id = $id; $this->name = $name; @@ -34,13 +34,17 @@ public function __construct( $this->apiKey = $apiKey; } - public function isHisApiKey(ApiKey $apiKey): bool + public function isHisApiKey(string|ApiKey $apiKey): bool { + if (is_string($apiKey)) $apiKey = new ApiKey($apiKey); + return ((string)$this->apiKey === (string)$apiKey); } - public function isHisId(ApplicationId $id): bool + public function isHisId(string|Id $id): bool { + if (is_string($id)) $id = new Id($id); + return ((string)$this->id === (string)$id); } } diff --git a/component/Domain/DataStructure/Value/ApiKey.php b/component/Domain/DataStructure/Application/ApiKey.php similarity index 93% rename from component/Domain/DataStructure/Value/ApiKey.php rename to component/Domain/DataStructure/Application/ApiKey.php index 5332523..af25c8a 100644 --- a/component/Domain/DataStructure/Value/ApiKey.php +++ b/component/Domain/DataStructure/Application/ApiKey.php @@ -1,7 +1,7 @@ itemsIterator() as $entity) { if ($entity->isHisId($id)) return $entity; diff --git a/component/Domain/DataStructure/Application/Id.php b/component/Domain/DataStructure/Application/Id.php new file mode 100644 index 0000000..821fcdc --- /dev/null +++ b/component/Domain/DataStructure/Application/Id.php @@ -0,0 +1,8 @@ +expiration = time() + $lifetime; } - public function getId(): IdRequestAccess + public function getId(): Id { return $this->id; } @@ -86,12 +85,12 @@ public function getAuthMethod(): AuthMethod return $this->authMethod; } - public function canBeSetStateTo(RequestAccessState $state): bool + public function canBeSetStateTo(State $state): bool { return $this->state->canBeSetTo($state); } - public function setState(RequestAccessState $state): self + public function setState(State $state): self { if (!$this->state->canBeSetTo($state)) { throw new NotAuthorized('State can be set to set to : ' . $state); @@ -102,12 +101,12 @@ public function setState(RequestAccessState $state): self return $this; } - public function getState(): RequestAccessState + public function getState(): State { return $this->state; } - public function tokenizeId(SslKey $sslKey): RequestAccessToken + public function tokenizeId(SslKey $sslKey): Token { $id = (string)$this->id; @@ -120,10 +119,10 @@ public function tokenizeId(SslKey $sslKey): RequestAccessToken $token = strtr(base64_encode($token), '+/=', '._-'); - return new RequestAccessToken($token); + return new Token($token); } - public static function untokenizeId(RequestAccessToken $token, SslKey $sslKey): IdRequestAccess + public static function untokenizeId(Token $token, SslKey $sslKey): Id { $token = base64_decode(strtr((string)$token, '._-', '+/=')); @@ -138,6 +137,6 @@ public static function untokenizeId(RequestAccessToken $token, SslKey $sslKey): $id = $datas[ self::TOKEN_PAYLOAD_ID ]; - return new IdRequestAccess($id); + return new Id($id); } } diff --git a/component/Domain/DataStructure/Value/AuthMethod.php b/component/Domain/DataStructure/RequestAccess/AuthMethod.php similarity index 88% rename from component/Domain/DataStructure/Value/AuthMethod.php rename to component/Domain/DataStructure/RequestAccess/AuthMethod.php index 82a5d89..fad7350 100644 --- a/component/Domain/DataStructure/Value/AuthMethod.php +++ b/component/Domain/DataStructure/RequestAccess/AuthMethod.php @@ -1,7 +1,7 @@ getValue()) { - case RequestAccessState::REQUESTED : + case State::REQUESTED : break; - case RequestAccessState::REFUSED : + case State::REFUSED : - return ($this->value == RequestAccessState::REQUESTED); + return ($this->value == State::REQUESTED); - case RequestAccessState::VERIFIED : + case State::VERIFIED : - return ($this->value == RequestAccessState::REQUESTED); + return ($this->value == State::REQUESTED); - case RequestAccessState::GRANTED : + case State::GRANTED : - return ($this->value == RequestAccessState::VERIFIED); + return ($this->value == State::VERIFIED); } diff --git a/component/Domain/DataStructure/RequestAccess/Token.php b/component/Domain/DataStructure/RequestAccess/Token.php new file mode 100644 index 0000000..30263ff --- /dev/null +++ b/component/Domain/DataStructure/RequestAccess/Token.php @@ -0,0 +1,8 @@ +emailAddress = $emailAddress; $this->lastname = $lastname; diff --git a/component/Domain/DataStructure/User/EmailAddress.php b/component/Domain/DataStructure/User/EmailAddress.php new file mode 100644 index 0000000..920fbc8 --- /dev/null +++ b/component/Domain/DataStructure/User/EmailAddress.php @@ -0,0 +1,8 @@ +canBeSetStateTo(new RequestAccessState(RequestAccessState::GRANTED))) { + if (!$requestAccess->canBeSetStateTo(new State(State::GRANTED))) { throw new NotAuthorized('The access request is invalid'); } @@ -64,7 +62,7 @@ public function getFromRequestAccessToken(RequestAccess $requestAccess, int $lif // Change state $this->serviceRequestAccess->set( $requestAccess - ->setState(new RequestAccessState(RequestAccessState::GRANTED)) + ->setState(new State(State::GRANTED)) ); return $accessToken; diff --git a/component/Domain/Service/Application.php b/component/Domain/Service/Application.php index 82b3243..f3b70a5 100644 --- a/component/Domain/Service/Application.php +++ b/component/Domain/Service/Application.php @@ -6,11 +6,11 @@ use Phant\Auth\Domain\Port\Application as PortApplication; use Phant\Auth\Domain\DataStructure\Application as EntityApplication; -use Phant\Auth\Domain\DataStructure\Value\{ +use Phant\Auth\Domain\DataStructure\Application\{ ApiKey, - ApplicationName, - ApplicationId, - ApplicationLogo, + Name, + Id, + Logo, }; final class Application @@ -27,9 +27,9 @@ public function __construct( public function add(string $name, ?string $logo = null): EntityApplication { $application = new EntityApplication( - ApplicationId::generate(), - new ApplicationName($name), - $logo ? new ApplicationLogo($logo) : null, + Id::generate(), + new Name($name), + $logo ? new Logo($logo) : null, ApiKey::generate() ); @@ -43,9 +43,9 @@ public function set(EntityApplication $application): void $this->repository->set($application); } - public function get(string|ApplicationId $id): EntityApplication + public function get(string|Id $id): EntityApplication { - if (is_string($id)) $id = new ApplicationId($id); + if (is_string($id)) $id = new Id($id); return $this->repository->get($id); } diff --git a/component/Domain/Service/RequestAccess.php b/component/Domain/Service/RequestAccess.php index e6f936e..bdf63ae 100644 --- a/component/Domain/Service/RequestAccess.php +++ b/component/Domain/Service/RequestAccess.php @@ -5,12 +5,14 @@ use Phant\Auth\Domain\Port\RequestAccess as PortRequestAccess; -use Phant\Auth\Domain\DataStructure\RequestAccess as EntityRequestAccess; -use Phant\Auth\Domain\DataStructure\Value\{ - IdRequestAccess, - RequestAccessToken, +use Phant\Auth\Domain\DataStructure\{ + RequestAccess as EntityRequestAccess, SslKey, }; +use Phant\Auth\Domain\DataStructure\RequestAccess\{ + Id, + Token, +}; final class RequestAccess { @@ -31,21 +33,21 @@ public function set(EntityRequestAccess $requestAccess): void $this->repository->set($requestAccess); } - public function get(string|IdRequestAccess $id): EntityRequestAccess + public function get(string|Id $id): EntityRequestAccess { - if (is_string($id)) $id = new IdRequestAccess($id); + if (is_string($id)) $id = new Id($id); return $this->repository->get($id); } - public function getToken(EntityRequestAccess $requestAccess): RequestAccessToken + public function getToken(EntityRequestAccess $requestAccess): Token { return $requestAccess->tokenizeId($this->sslKey); } - public function getFromToken(string|RequestAccessToken $token): EntityRequestAccess + public function getFromToken(string|Token $token): EntityRequestAccess { - if (is_string($token)) $token = new IdRequestAccess($token); + if (is_string($token)) $token = new Id($token); $id = EntityRequestAccess::untokenizeId($token, $this->sslKey); diff --git a/component/Domain/Service/RequestAccessFromApiKey.php b/component/Domain/Service/RequestAccessFromApiKey.php index c766ec2..8ae2513 100644 --- a/component/Domain/Service/RequestAccessFromApiKey.php +++ b/component/Domain/Service/RequestAccessFromApiKey.php @@ -15,11 +15,11 @@ RequestAccessFromApiKey as EntityRequestAccessFromApiKey, User, }; -use Phant\Auth\Domain\DataStructure\Value\{ - ApiKey, - IdRequestAccess, - RequestAccessState, - RequestAccessToken, +use Phant\Auth\Domain\DataStructure\Application\ApiKey; +use Phant\Auth\Domain\DataStructure\RequestAccess\{ + Id, + State, + Token, }; final class RequestAccessFromApiKey @@ -55,11 +55,11 @@ public function getAccessToken(string|ApiKey $apiKey, int $lifetime = self::LIFE $requestAccess->setApplication($application); - $requestAccess->setState(new RequestAccessState(RequestAccessState::VERIFIED)); + $requestAccess->setState(new State(State::VERIFIED)); $this->serviceRequestAccess->set($requestAccess); - $accessToken = $this->serviceAccessToken->getFromRequestAccessToken($requestAccess); + $accessToken = $this->serviceAccessToken->getFromToken($requestAccess); return $accessToken; } diff --git a/component/Domain/Service/RequestAccessFromOtp.php b/component/Domain/Service/RequestAccessFromOtp.php index 2505576..c1ddad9 100644 --- a/component/Domain/Service/RequestAccessFromOtp.php +++ b/component/Domain/Service/RequestAccessFromOtp.php @@ -15,11 +15,11 @@ RequestAccessFromOtp as EntityRequestAccessFromOtp, User, }; -use Phant\Auth\Domain\DataStructure\Value\{ - IdRequestAccess, +use Phant\Auth\Domain\DataStructure\RequestAccess\{ + Id, Otp, - RequestAccessState, - RequestAccessToken, + State, + Token, }; final class RequestAccessFromOtp @@ -41,7 +41,7 @@ public function __construct( $this->userNotification = $userNotification; } - public function generate(Application $application, User $user, int $numberOfAttemptsLimit = 3, int $lifetime = self::LIFETIME): RequestAccessToken + public function generate(Application $application, User $user, int $numberOfAttemptsLimit = 3, int $lifetime = self::LIFETIME): Token { $requestAccess = $this->build($application, $user, $numberOfAttemptsLimit, $lifetime); @@ -54,7 +54,7 @@ public function generate(Application $application, User $user, int $numberOfAtte return $requestAccessToken; } - public function verify(RequestAccessToken $requestAccessToken, string|Otp $otp): bool + public function verify(Token $requestAccessToken, string|Otp $otp): bool { $requestAccess = $this->serviceRequestAccess->getFromToken($requestAccessToken); @@ -62,30 +62,30 @@ public function verify(RequestAccessToken $requestAccessToken, string|Otp $otp): if ( ! $requestAccess->checkOtp($otp)) { - $requestAccess->setState(new RequestAccessState(RequestAccessState::REFUSED)); + $requestAccess->setState(new State(State::REFUSED)); return false; } - $requestAccess->setState(new RequestAccessState(RequestAccessState::VERIFIED)); + $requestAccess->setState(new State(State::VERIFIED)); $this->serviceRequestAccess->set($requestAccess); return true; } - public function getNumberOfRemainingAttempts(RequestAccessToken $requestAccessToken): int + public function getNumberOfRemainingAttempts(Token $requestAccessToken): int { $requestAccess = $this->serviceRequestAccess->getFromToken($requestAccessToken); return $requestAccess->getNumberOfRemainingAttempts($requestAccess); } - public function getAccessToken(RequestAccessToken $requestAccessToken): ?AccessToken + public function getAccessToken(Token $requestAccessToken): ?AccessToken { $requestAccess = $this->serviceRequestAccess->getFromToken($requestAccessToken); - $accessToken = $this->serviceAccessToken->getFromRequestAccessToken($requestAccess); + $accessToken = $this->serviceAccessToken->getFromToken($requestAccess); return $accessToken; } diff --git a/component/Domain/Service/RequestAccessFromThirdParty.php b/component/Domain/Service/RequestAccessFromThirdParty.php index 4e4406b..d29df93 100644 --- a/component/Domain/Service/RequestAccessFromThirdParty.php +++ b/component/Domain/Service/RequestAccessFromThirdParty.php @@ -14,10 +14,10 @@ RequestAccessFromThirdParty as EntityRequestAccessFromThirdParty, User, }; -use Phant\Auth\Domain\DataStructure\Value\{ - IdRequestAccess, - RequestAccessState, - RequestAccessToken, +use Phant\Auth\Domain\DataStructure\RequestAccess\{ + Id, + State, + Token, }; final class RequestAccessFromThirdParty @@ -36,7 +36,7 @@ public function __construct( $this->serviceAccessToken = $serviceAccessToken; } - public function generate(Application $application, int $lifetime = self::LIFETIME): RequestAccessToken + public function generate(Application $application, int $lifetime = self::LIFETIME): Token { $requestAccess = $this->build($application, $lifetime); @@ -47,21 +47,21 @@ public function generate(Application $application, int $lifetime = self::LIFETIM return $requestAccessToken; } - public function setStatus(RequestAccessToken $requestAccessToken, User $user, bool $isAuthorized): void + public function setStatus(Token $requestAccessToken, User $user, bool $isAuthorized): void { $requestAccess = $this->serviceRequestAccess->getFromToken($requestAccessToken); $requestAccess->setUser($user); - $requestAccess->setState(new RequestAccessState($isAuthorized ? RequestAccessState::VERIFIED : RequestAccessState::REFUSED)); + $requestAccess->setState(new State($isAuthorized ? State::VERIFIED : State::REFUSED)); $this->serviceRequestAccess->set($requestAccess); } - public function getAccessToken(RequestAccessToken $requestAccessToken): ?AccessToken + public function getAccessToken(Token $requestAccessToken): ?AccessToken { $requestAccess = $this->serviceRequestAccess->getFromToken($requestAccessToken); - $accessToken = $this->serviceAccessToken->getFromRequestAccessToken($requestAccess); + $accessToken = $this->serviceAccessToken->getFromToken($requestAccess); return $accessToken; } diff --git a/component/Fixture/DataStructure/AccessToken.php b/component/Fixture/DataStructure/AccessToken.php index 011fa6e..a20be1a 100644 --- a/component/Fixture/DataStructure/AccessToken.php +++ b/component/Fixture/DataStructure/AccessToken.php @@ -7,9 +7,9 @@ use Phant\Auth\Fixture\DataStructure\{ Application as FixtureApplication, + SslKey as FixtureSslKey, User as FixtureUser, }; -use Phant\Auth\Fixture\DataStructure\Value\SslKey as FixtureSslKey; final class AccessToken { diff --git a/component/Fixture/DataStructure/Application.php b/component/Fixture/DataStructure/Application.php index 190a181..35dbc68 100644 --- a/component/Fixture/DataStructure/Application.php +++ b/component/Fixture/DataStructure/Application.php @@ -4,12 +4,12 @@ namespace Phant\Auth\Fixture\DataStructure; use Phant\Auth\Domain\DataStructure\Application as EntityApplication; -use Phant\Auth\Domain\DataStructure\Value\{ +use Phant\Auth\Domain\DataStructure\Application\{ ApiKey, - ApplicationName, - CollectionApplication, - ApplicationId, - ApplicationLogo, + Collection, + Id, + Logo, + Name, }; final class Application @@ -42,9 +42,9 @@ public static function get(): EntityApplication return self::buildFromDatas($datas); } - public static function getCollection(): CollectionApplication + public static function getCollection(): Collection { - $collection = new CollectionApplication(); + $collection = new Collection(); foreach (self::DATAS as $datas) { $collection->addApplication( @@ -58,9 +58,9 @@ public static function getCollection(): CollectionApplication private static function buildFromDatas(array $datas): EntityApplication { return new EntityApplication( - new ApplicationId($datas['id']), - new ApplicationName($datas['name']), - new ApplicationLogo($datas['logo']), + new Id($datas['id']), + new Name($datas['name']), + new Logo($datas['logo']), new ApiKey($datas['api_key']) ); } diff --git a/component/Fixture/DataStructure/RequestAccessFromApiKey.php b/component/Fixture/DataStructure/RequestAccessFromApiKey.php index 5f2284b..c72a2f3 100644 --- a/component/Fixture/DataStructure/RequestAccessFromApiKey.php +++ b/component/Fixture/DataStructure/RequestAccessFromApiKey.php @@ -4,15 +4,15 @@ namespace Phant\Auth\Fixture\DataStructure; use Phant\Auth\Domain\DataStructure\RequestAccessFromApiKey as EntityRequestAccessFromApiKey; -use Phant\Auth\Domain\DataStructure\Value\RequestAccessState; +use Phant\Auth\Domain\DataStructure\RequestAccess\State; use Phant\Auth\Fixture\DataStructure\Application as FixtureApplication; final class RequestAccessFromApiKey { - public static function get(?RequestAccessState $state = null, int $lifetime = 300): EntityRequestAccessFromApiKey + public static function get(?State $state = null, int $lifetime = 300): EntityRequestAccessFromApiKey { - if (is_null($state)) $state = new RequestAccessState(RequestAccessState::REQUESTED); + if (is_null($state)) $state = new State(State::REQUESTED); return new EntityRequestAccessFromApiKey( FixtureApplication::get()->apiKey, @@ -20,7 +20,7 @@ public static function get(?RequestAccessState $state = null, int $lifetime = 30 ); } - public static function getExpired(?RequestAccessState $state = null): EntityRequestAccessFromApiKey + public static function getExpired(?State $state = null): EntityRequestAccessFromApiKey { return self::get($state, -9999); } @@ -29,6 +29,6 @@ public static function getVerified(): EntityRequestAccessFromApiKey { return (self::get()) ->setApplication(FixtureApplication::get()) - ->setState(new RequestAccessState(RequestAccessState::VERIFIED)); + ->setState(new State(State::VERIFIED)); } } diff --git a/component/Fixture/DataStructure/RequestAccessFromOtp.php b/component/Fixture/DataStructure/RequestAccessFromOtp.php index f892ddc..5db7a3d 100644 --- a/component/Fixture/DataStructure/RequestAccessFromOtp.php +++ b/component/Fixture/DataStructure/RequestAccessFromOtp.php @@ -4,9 +4,9 @@ namespace Phant\Auth\Fixture\DataStructure; use Phant\Auth\Domain\DataStructure\RequestAccessFromOtp as EntityRequestAccessFromOtp; -use Phant\Auth\Domain\DataStructure\Value\{ +use Phant\Auth\Domain\DataStructure\RequestAccess\{ Otp, - RequestAccessState, + State, }; use Phant\Auth\Fixture\DataStructure\Application as FixtureApplication; @@ -14,9 +14,9 @@ final class RequestAccessFromOtp { - public static function get(?RequestAccessState $state = null, int $numberOfAttemptsLimit = 3, int $lifetime = 900): EntityRequestAccessFromOtp + public static function get(?State $state = null, int $numberOfAttemptsLimit = 3, int $lifetime = 900): EntityRequestAccessFromOtp { - if (is_null($state)) $state = new RequestAccessState(RequestAccessState::REQUESTED); + if (is_null($state)) $state = new State(State::REQUESTED); return new EntityRequestAccessFromOtp( FixtureApplication::get(), @@ -26,7 +26,7 @@ public static function get(?RequestAccessState $state = null, int $numberOfAttem ); } - public static function getExpired(?RequestAccessState $state = null, int $numberOfAttemptsLimit = 3): EntityRequestAccessFromOtp + public static function getExpired(?State $state = null, int $numberOfAttemptsLimit = 3): EntityRequestAccessFromOtp { return self::get($state, $numberOfAttemptsLimit, -9999); } @@ -34,6 +34,6 @@ public static function getExpired(?RequestAccessState $state = null, int $number public static function getVerified(): EntityRequestAccessFromOtp { return (self::get()) - ->setState(new RequestAccessState(RequestAccessState::VERIFIED)); + ->setState(new State(State::VERIFIED)); } } diff --git a/component/Fixture/DataStructure/RequestAccessFromThirdParty.php b/component/Fixture/DataStructure/RequestAccessFromThirdParty.php index 4cb6f29..0a48a35 100644 --- a/component/Fixture/DataStructure/RequestAccessFromThirdParty.php +++ b/component/Fixture/DataStructure/RequestAccessFromThirdParty.php @@ -4,16 +4,16 @@ namespace Phant\Auth\Fixture\DataStructure; use Phant\Auth\Domain\DataStructure\RequestAccessFromThirdParty as EntityRequestAccessFromThirdParty; -use Phant\Auth\Domain\DataStructure\Value\RequestAccessState; +use Phant\Auth\Domain\DataStructure\RequestAccess\State; use Phant\Auth\Fixture\DataStructure\Application as FixtureApplication; use Phant\Auth\Fixture\DataStructure\User as FixtureUser; final class RequestAccessFromThirdParty { - public static function get(?RequestAccessState $state = null, int $lifetime = 900): EntityRequestAccessFromThirdParty + public static function get(?State $state = null, int $lifetime = 900): EntityRequestAccessFromThirdParty { - if (is_null($state)) $state = new RequestAccessState(RequestAccessState::REQUESTED); + if (is_null($state)) $state = new State(State::REQUESTED); return new EntityRequestAccessFromThirdParty( FixtureApplication::get(), @@ -21,7 +21,7 @@ public static function get(?RequestAccessState $state = null, int $lifetime = 90 ); } - public static function getExpired(?RequestAccessState $state = null): EntityRequestAccessFromThirdParty + public static function getExpired(?State $state = null): EntityRequestAccessFromThirdParty { return self::get($state, -9999); } @@ -30,6 +30,6 @@ public static function getVerified(): EntityRequestAccessFromThirdParty { return (self::get()) ->setUser(FixtureUser::get()) - ->setState(new RequestAccessState(RequestAccessState::VERIFIED)); + ->setState(new State(State::VERIFIED)); } } diff --git a/component/Fixture/DataStructure/Value/SslKey.php b/component/Fixture/DataStructure/SslKey.php similarity index 96% rename from component/Fixture/DataStructure/Value/SslKey.php rename to component/Fixture/DataStructure/SslKey.php index af3fa49..5f2a561 100644 --- a/component/Fixture/DataStructure/Value/SslKey.php +++ b/component/Fixture/DataStructure/SslKey.php @@ -1,9 +1,9 @@ cache->set((string)$application->id, $application); } - public function get(ApplicationId $id): EntityApplication + public function get(Id $id): EntityApplication { $entity = $this->cache->get((string)$id); if ($entity) return $entity; @@ -54,7 +54,7 @@ public function getFromApiKey(ApiKey $apiKey): EntityApplication throw new NotFound('Application not found from API key : ' . $apiKey); } - public function getList(): CollectionApplication + public function getList(): Collection { return FixtureApplication::getCollection(); } diff --git a/component/Fixture/Port/RequestAccess.php b/component/Fixture/Port/RequestAccess.php index 34fbad7..7b3c35e 100644 --- a/component/Fixture/Port/RequestAccess.php +++ b/component/Fixture/Port/RequestAccess.php @@ -4,7 +4,7 @@ namespace Phant\Auth\Fixture\Port; use Phant\Auth\Domain\DataStructure\RequestAccess as EntityRequestAccess; -use Phant\Auth\Domain\DataStructure\Value\IdRequestAccess; +use Phant\Auth\Domain\DataStructure\RequestAccess\Id; use Psr\SimpleCache\CacheInterface; use Phant\Auth\Fixture\DataStructure\RequestAccessFromOtp as FixtureRequestAccessFromOtp; @@ -25,7 +25,7 @@ public function set(EntityRequestAccess $requestAccess): void $this->cache->set((string)$requestAccess->getId(), $requestAccess); } - public function get(IdRequestAccess $id): EntityRequestAccess + public function get(Id $id): EntityRequestAccess { $entity = $this->cache->get((string)$id); if ($entity) return $entity; diff --git a/component/Fixture/Port/UserNotification.php b/component/Fixture/Port/UserNotification.php index ad6bde0..e710dbf 100644 --- a/component/Fixture/Port/UserNotification.php +++ b/component/Fixture/Port/UserNotification.php @@ -5,9 +5,9 @@ use Phant\Auth\Domain\DataStructure\RequestAccess; use Psr\SimpleCache\CacheInterface; -use Phant\Auth\Domain\DataStructure\Value\{ +use Phant\Auth\Domain\DataStructure\RequestAccess\{ Otp, - RequestAccessToken, + Token, }; final class UserNotification implements \Phant\Auth\Domain\Port\UserNotification @@ -19,7 +19,7 @@ public function __construct(CacheInterface $cache) $this->cache = $cache; } - public function sendOtpFromRequestAccess(RequestAccessToken $requestAccessToken, RequestAccess $requestAccess, Otp $otp): void + public function sendOtpFromRequestAccess(Token $requestAccessToken, RequestAccess $requestAccess, Otp $otp): void { $this->cache->set((string)$requestAccessToken, $otp); } diff --git a/component/Fixture/Service/AccessToken.php b/component/Fixture/Service/AccessToken.php index c41345a..2705231 100644 --- a/component/Fixture/Service/AccessToken.php +++ b/component/Fixture/Service/AccessToken.php @@ -5,7 +5,7 @@ use Phant\Auth\Domain\Service\AccessToken as ServiceAccessToken; -use Phant\Auth\Fixture\DataStructure\Value\SslKey as FixtureSslKey; +use Phant\Auth\Fixture\DataStructure\SslKey as FixtureSslKey; use Phant\Auth\Fixture\Service\RequestAccess as FixtureServiceRequestAccess; final class AccessToken diff --git a/component/Fixture/Service/RequestAccess.php b/component/Fixture/Service/RequestAccess.php index c37b514..844bf41 100644 --- a/component/Fixture/Service/RequestAccess.php +++ b/component/Fixture/Service/RequestAccess.php @@ -6,7 +6,7 @@ use Phant\Auth\Domain\Service\RequestAccess as ServiceRequestAccess; use Phant\Cache\SimpleCache; -use Phant\Auth\Fixture\DataStructure\Value\SslKey as FixtureSslKey; +use Phant\Auth\Fixture\DataStructure\SslKey as FixtureSslKey; use Phant\Auth\Fixture\Port\RequestAccess as FixtureRepositoryRequestAccess; final class RequestAccess diff --git a/test/Domain/DataStructure/AccessTokenTest.php b/test/Domain/DataStructure/AccessTokenTest.php index 9dd144d..ef77325 100644 --- a/test/Domain/DataStructure/AccessTokenTest.php +++ b/test/Domain/DataStructure/AccessTokenTest.php @@ -4,14 +4,14 @@ namespace Test\Domain\DataStructure; use Phant\Auth\Domain\DataStructure\AccessToken; -use Phant\Auth\Domain\DataStructure\Value\Expire; +use Phant\Auth\Domain\DataStructure\AccessToken\Expire; use Phant\Auth\Fixture\DataStructure\{ AccessToken as FixtureAccessToken, Application as FixtureApplication, + SslKey as FixtureSslKey, User as FixtureUser, }; -use Phant\Auth\Fixture\DataStructure\Value\SslKey as FixtureSslKey; final class AccessTokenTest extends \PHPUnit\Framework\TestCase { diff --git a/test/Domain/DataStructure/Value/ApiKeyTest.php b/test/Domain/DataStructure/Application/ApiKeyTest.php similarity index 85% rename from test/Domain/DataStructure/Value/ApiKeyTest.php rename to test/Domain/DataStructure/Application/ApiKeyTest.php index 5a1c8bb..31caabd 100644 --- a/test/Domain/DataStructure/Value/ApiKeyTest.php +++ b/test/Domain/DataStructure/Application/ApiKeyTest.php @@ -1,9 +1,9 @@ assertEquals(0, $collection->getNbItems()); diff --git a/test/Domain/DataStructure/Application/NameTest.php b/test/Domain/DataStructure/Application/NameTest.php new file mode 100644 index 0000000..b7377b5 --- /dev/null +++ b/test/Domain/DataStructure/Application/NameTest.php @@ -0,0 +1,26 @@ +assertIsObject($result); + $this->assertInstanceOf(Name::class, $result); + } + + public function testConstructFail(): void + { + $this->expectException(NotCompliant::class); + + new Name('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'); + } +} diff --git a/test/Domain/DataStructure/ApplicationTest.php b/test/Domain/DataStructure/ApplicationTest.php index 62b6d44..cf5c6d8 100644 --- a/test/Domain/DataStructure/ApplicationTest.php +++ b/test/Domain/DataStructure/ApplicationTest.php @@ -4,11 +4,11 @@ namespace Test\Domain\DataStructure; use Phant\Auth\Domain\DataStructure\Application; -use Phant\Auth\Domain\DataStructure\Value\{ +use Phant\Auth\Domain\DataStructure\Application\{ ApiKey, - ApplicationName, - ApplicationId, - ApplicationLogo, + Name, + Id, + Logo, }; use Phant\Auth\Fixture\DataStructure\Application as FixtureApplication; @@ -25,9 +25,9 @@ public function setUp(): void public function testConstruct(): void { $entity = new Application( - ApplicationId::generate(), - new ApplicationName('Foo bar'), - new ApplicationLogo('https://domain.ext/file.ext'), + Id::generate(), + new Name('Foo bar'), + new Logo('https://domain.ext/file.ext'), ApiKey::generate() ); @@ -68,7 +68,7 @@ public function testIsHisId(): void public function testIsHisIdInvalid(): void { $result = $this->fixture->isHisId( - ApplicationId::generate() + Id::generate() ); $this->assertIsBool($result); diff --git a/test/Domain/DataStructure/Value/AuthMethodTest.php b/test/Domain/DataStructure/RequestAccess/AuthMethodTest.php similarity index 81% rename from test/Domain/DataStructure/Value/AuthMethodTest.php rename to test/Domain/DataStructure/RequestAccess/AuthMethodTest.php index ad14911..6b98c77 100644 --- a/test/Domain/DataStructure/Value/AuthMethodTest.php +++ b/test/Domain/DataStructure/RequestAccess/AuthMethodTest.php @@ -1,9 +1,9 @@ canBeSetTo(State::REQUESTED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + + + $result = (new State(State::REQUESTED)) + ->canBeSetTo(State::REFUSED); + + $this->assertIsBool($result); + $this->assertEquals(true, $result); + + + $result = (new State(State::REQUESTED)) + ->canBeSetTo(State::VERIFIED); + + $this->assertIsBool($result); + $this->assertEquals(true, $result); + + + $result = (new State(State::REQUESTED)) + ->canBeSetTo(State::GRANTED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + + + // Refused to ... + $result = (new State(State::REFUSED)) + ->canBeSetTo(State::REQUESTED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + + + $result = (new State(State::REFUSED)) + ->canBeSetTo(State::REFUSED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + + + $result = (new State(State::REFUSED)) + ->canBeSetTo(State::VERIFIED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + + + $result = (new State(State::REFUSED)) + ->canBeSetTo(State::GRANTED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + + + // Verified to ... + $result = (new State(State::VERIFIED)) + ->canBeSetTo(State::REQUESTED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + + + $result = (new State(State::VERIFIED)) + ->canBeSetTo(State::REFUSED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + + + $result = (new State(State::VERIFIED)) + ->canBeSetTo(State::VERIFIED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + + + $result = (new State(State::VERIFIED)) + ->canBeSetTo(State::GRANTED); + + $this->assertIsBool($result); + $this->assertEquals(true, $result); + + + // Granted to ... + $result = (new State(State::GRANTED)) + ->canBeSetTo(State::REQUESTED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + + + $result = (new State(State::GRANTED)) + ->canBeSetTo(State::REFUSED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + + + $result = (new State(State::GRANTED)) + ->canBeSetTo(State::VERIFIED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + + + $result = (new State(State::GRANTED)) + ->canBeSetTo(State::GRANTED); + + $this->assertIsBool($result); + $this->assertEquals(false, $result); + } +} diff --git a/test/Domain/DataStructure/RequestAccessFromApiKeyTest.php b/test/Domain/DataStructure/RequestAccessFromApiKeyTest.php index 44bb65b..1985461 100644 --- a/test/Domain/DataStructure/RequestAccessFromApiKeyTest.php +++ b/test/Domain/DataStructure/RequestAccessFromApiKeyTest.php @@ -4,10 +4,10 @@ namespace Test\Domain\DataStructure; use Phant\Auth\Domain\DataStructure\RequestAccessFromApiKey; -use Phant\Auth\Domain\DataStructure\Value\{ - IdRequestAccess, +use Phant\Auth\Domain\DataStructure\RequestAccess\{ + Id, Otp, - RequestAccessState, + State, }; use Phant\Auth\Fixture\DataStructure\{ diff --git a/test/Domain/DataStructure/RequestAccessFromOtpTest.php b/test/Domain/DataStructure/RequestAccessFromOtpTest.php index fad8623..07082f5 100644 --- a/test/Domain/DataStructure/RequestAccessFromOtpTest.php +++ b/test/Domain/DataStructure/RequestAccessFromOtpTest.php @@ -4,10 +4,10 @@ namespace Test\Domain\DataStructure; use Phant\Auth\Domain\DataStructure\RequestAccessFromOtp; -use Phant\Auth\Domain\DataStructure\Value\{ - IdRequestAccess, +use Phant\Auth\Domain\DataStructure\RequestAccess\{ + Id, Otp, - RequestAccessState, + State, }; use Phant\Auth\Fixture\DataStructure\{ diff --git a/test/Domain/DataStructure/RequestAccessFromThirdPartyTest.php b/test/Domain/DataStructure/RequestAccessFromThirdPartyTest.php index 7e1cdeb..3c2565c 100644 --- a/test/Domain/DataStructure/RequestAccessFromThirdPartyTest.php +++ b/test/Domain/DataStructure/RequestAccessFromThirdPartyTest.php @@ -4,9 +4,9 @@ namespace Test\Domain\DataStructure; use Phant\Auth\Domain\DataStructure\RequestAccessFromThirdParty; -use Phant\Auth\Domain\DataStructure\Value\{ - IdRequestAccess, - RequestAccessState, +use Phant\Auth\Domain\DataStructure\RequestAccess\{ + Id, + State, }; use Phant\Auth\Fixture\DataStructure\{ diff --git a/test/Domain/DataStructure/RequestAccessTest.php b/test/Domain/DataStructure/RequestAccessTest.php index a49b2f2..7dc1dc5 100644 --- a/test/Domain/DataStructure/RequestAccessTest.php +++ b/test/Domain/DataStructure/RequestAccessTest.php @@ -8,21 +8,19 @@ RequestAccessFromApiKey, User, }; -use Phant\Auth\Domain\DataStructure\Value\{ +use Phant\Auth\Domain\DataStructure\RequestAccess\{ AuthMethod, - IdRequestAccess, + Id, Otp, - RequestAccessState, - RequestAccessToken, + State, + Token, }; use Phant\Auth\Fixture\DataStructure\{ Application as FixtureApplication, RequestAccessFromApiKey as FixtureRequestAccessFromApiKey, - User as FixtureUser, -}; -use Phant\Auth\Fixture\DataStructure\Value\{ SslKey as FixtureSslKey, + User as FixtureUser, }; use Phant\Error\NotAuthorized; @@ -42,7 +40,7 @@ public function testGetId(): void $value = $this->fixture->getId(); $this->assertIsObject($value); - $this->assertInstanceOf(IdRequestAccess::class, $value); + $this->assertInstanceOf(Id::class, $value); } public function testGetApplication(): void @@ -110,12 +108,12 @@ public function testGetState(): void $value = $this->fixture->getState(); $this->assertIsObject($value); - $this->assertInstanceOf(RequestAccessState::class, $value); + $this->assertInstanceOf(State::class, $value); } public function testCanBeSetStateTo(): void { - $result = $this->fixture->canBeSetStateTo(new RequestAccessState(RequestAccessState::VERIFIED)); + $result = $this->fixture->canBeSetStateTo(new State(State::VERIFIED)); $this->assertIsBool($result); $this->assertEquals(true, $result); @@ -123,21 +121,21 @@ public function testCanBeSetStateTo(): void public function testSetState(): void { - $entity = $this->fixture->setState(new RequestAccessState(RequestAccessState::VERIFIED)); + $entity = $this->fixture->setState(new State(State::VERIFIED)); $this->assertIsObject($entity); $this->assertInstanceOf(RequestAccessFromApiKey::class, $entity); $this->assertIsObject($entity->getState()); - $this->assertInstanceOf(RequestAccessState::class, $entity->getState()); - $this->assertEquals(new RequestAccessState(RequestAccessState::VERIFIED), $entity->getState()); + $this->assertInstanceOf(State::class, $entity->getState()); + $this->assertEquals(new State(State::VERIFIED), $entity->getState()); } public function testSetStateInvalid(): void { $this->expectException(NotAuthorized::class); - $entity = $this->fixture->setState(new RequestAccessState(RequestAccessState::REQUESTED)); + $entity = $this->fixture->setState(new State(State::REQUESTED)); } public function testTokenizeIdAndUntokenizeId(): void @@ -145,12 +143,12 @@ public function testTokenizeIdAndUntokenizeId(): void $result = $this->fixture->tokenizeId(FixtureSslKey::get()); $this->assertIsObject($result); - $this->assertInstanceOf(RequestAccessToken::class, $result); + $this->assertInstanceOf(Token::class, $result); $entity = $this->fixture->untokenizeId($result, FixtureSslKey::get()); $this->assertIsObject($entity); - $this->assertInstanceOf(IdRequestAccess::class, $entity); + $this->assertInstanceOf(Id::class, $entity); } public function testTokenizeIdInvalid(): void diff --git a/test/Domain/DataStructure/Value/SslKeyTest.php b/test/Domain/DataStructure/SslKeyTest.php similarity index 89% rename from test/Domain/DataStructure/Value/SslKeyTest.php rename to test/Domain/DataStructure/SslKeyTest.php index efbbc21..d8dccbf 100644 --- a/test/Domain/DataStructure/Value/SslKeyTest.php +++ b/test/Domain/DataStructure/SslKeyTest.php @@ -1,10 +1,10 @@ assertIsObject($result); - $this->assertInstanceOf(ApplicationName::class, $result); - } - - public function testConstructFail(): void - { - $this->expectException(NotCompliant::class); - - new ApplicationName('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'); - } -} diff --git a/test/Domain/DataStructure/Value/RequestAccessStateTest.php b/test/Domain/DataStructure/Value/RequestAccessStateTest.php deleted file mode 100644 index b74c2d7..0000000 --- a/test/Domain/DataStructure/Value/RequestAccessStateTest.php +++ /dev/null @@ -1,127 +0,0 @@ -canBeSetTo(RequestAccessState::REQUESTED); - - $this->assertIsBool($result); - $this->assertEquals(false, $result); - - - $result = (new RequestAccessState(RequestAccessState::REQUESTED)) - ->canBeSetTo(RequestAccessState::REFUSED); - - $this->assertIsBool($result); - $this->assertEquals(true, $result); - - - $result = (new RequestAccessState(RequestAccessState::REQUESTED)) - ->canBeSetTo(RequestAccessState::VERIFIED); - - $this->assertIsBool($result); - $this->assertEquals(true, $result); - - - $result = (new RequestAccessState(RequestAccessState::REQUESTED)) - ->canBeSetTo(RequestAccessState::GRANTED); - - $this->assertIsBool($result); - $this->assertEquals(false, $result); - - - // Refused to ... - $result = (new RequestAccessState(RequestAccessState::REFUSED)) - ->canBeSetTo(RequestAccessState::REQUESTED); - - $this->assertIsBool($result); - $this->assertEquals(false, $result); - - - $result = (new RequestAccessState(RequestAccessState::REFUSED)) - ->canBeSetTo(RequestAccessState::REFUSED); - - $this->assertIsBool($result); - $this->assertEquals(false, $result); - - - $result = (new RequestAccessState(RequestAccessState::REFUSED)) - ->canBeSetTo(RequestAccessState::VERIFIED); - - $this->assertIsBool($result); - $this->assertEquals(false, $result); - - - $result = (new RequestAccessState(RequestAccessState::REFUSED)) - ->canBeSetTo(RequestAccessState::GRANTED); - - $this->assertIsBool($result); - $this->assertEquals(false, $result); - - - // Verified to ... - $result = (new RequestAccessState(RequestAccessState::VERIFIED)) - ->canBeSetTo(RequestAccessState::REQUESTED); - - $this->assertIsBool($result); - $this->assertEquals(false, $result); - - - $result = (new RequestAccessState(RequestAccessState::VERIFIED)) - ->canBeSetTo(RequestAccessState::REFUSED); - - $this->assertIsBool($result); - $this->assertEquals(false, $result); - - - $result = (new RequestAccessState(RequestAccessState::VERIFIED)) - ->canBeSetTo(RequestAccessState::VERIFIED); - - $this->assertIsBool($result); - $this->assertEquals(false, $result); - - - $result = (new RequestAccessState(RequestAccessState::VERIFIED)) - ->canBeSetTo(RequestAccessState::GRANTED); - - $this->assertIsBool($result); - $this->assertEquals(true, $result); - - - // Granted to ... - $result = (new RequestAccessState(RequestAccessState::GRANTED)) - ->canBeSetTo(RequestAccessState::REQUESTED); - - $this->assertIsBool($result); - $this->assertEquals(false, $result); - - - $result = (new RequestAccessState(RequestAccessState::GRANTED)) - ->canBeSetTo(RequestAccessState::REFUSED); - - $this->assertIsBool($result); - $this->assertEquals(false, $result); - - - $result = (new RequestAccessState(RequestAccessState::GRANTED)) - ->canBeSetTo(RequestAccessState::VERIFIED); - - $this->assertIsBool($result); - $this->assertEquals(false, $result); - - - $result = (new RequestAccessState(RequestAccessState::GRANTED)) - ->canBeSetTo(RequestAccessState::GRANTED); - - $this->assertIsBool($result); - $this->assertEquals(false, $result); - } -} diff --git a/test/Domain/Service/AccessTokenTest.php b/test/Domain/Service/AccessTokenTest.php index eb1bf6c..e83a091 100644 --- a/test/Domain/Service/AccessTokenTest.php +++ b/test/Domain/Service/AccessTokenTest.php @@ -44,9 +44,9 @@ public function testCheck(): void $this->assertEquals(true, $value); } - public function testGetFromRequestAccessToken(): void + public function testGetFromToken(): void { - $entity = $this->service->getFromRequestAccessToken( + $entity = $this->service->getFromToken( FixtureRequestAccessFromOtp::getVerified() ); @@ -54,11 +54,11 @@ public function testGetFromRequestAccessToken(): void $this->assertInstanceOf(AccessToken::class, $entity); } - public function testGetFromRequestAccessTokenInvalid(): void + public function testGetFromTokenInvalid(): void { $this->expectException(NotAuthorized::class); - $entity = $this->service->getFromRequestAccessToken( + $entity = $this->service->getFromToken( FixtureRequestAccessFromOtp::get() ); } diff --git a/test/Domain/Service/RequestAccessFromApiKeyTest.php b/test/Domain/Service/RequestAccessFromApiKeyTest.php index 14e47f3..f103fc4 100644 --- a/test/Domain/Service/RequestAccessFromApiKeyTest.php +++ b/test/Domain/Service/RequestAccessFromApiKeyTest.php @@ -3,7 +3,7 @@ namespace Test\Domain\Service; use Phant\Auth\Domain\DataStructure\AccessToken; -use Phant\Auth\Domain\DataStructure\Value\ApiKey; +use Phant\Auth\Domain\DataStructure\Application\ApiKey; use Phant\Auth\Domain\Service\RequestAccessFromApiKey as ServiceRequestAccessFromApiKey; use Phant\Auth\Fixture\DataStructure\Application as FixtureApplication; diff --git a/test/Domain/Service/RequestAccessFromOtpTest.php b/test/Domain/Service/RequestAccessFromOtpTest.php index 7042d3c..e15163d 100644 --- a/test/Domain/Service/RequestAccessFromOtpTest.php +++ b/test/Domain/Service/RequestAccessFromOtpTest.php @@ -7,8 +7,8 @@ AccessToken, RequestAccessFromOtp, }; -use Phant\Auth\Domain\DataStructure\Value\{ - RequestAccessToken, +use Phant\Auth\Domain\DataStructure\RequestAccess\{ + Token, }; use Phant\Auth\Domain\Service\RequestAccessFromOtp as ServiceRequestAccessFromOtp; @@ -28,7 +28,7 @@ final class RequestAccessFromOtpTest extends \PHPUnit\Framework\TestCase { protected ServiceRequestAccessFromOtp $service; - protected RequestAccessToken $fixture; + protected Token $fixture; protected SimpleCache $cache; public function setUp(): void @@ -44,7 +44,7 @@ public function setUp(): void public function testGenerate(): void { $this->assertIsObject($this->fixture); - $this->assertInstanceOf(RequestAccessToken::class, $this->fixture); + $this->assertInstanceOf(Token::class, $this->fixture); } public function testGenerateInvalid(): void diff --git a/test/Domain/Service/RequestAccessFromThirdPartyTest.php b/test/Domain/Service/RequestAccessFromThirdPartyTest.php index e5173d6..bcc8dde 100644 --- a/test/Domain/Service/RequestAccessFromThirdPartyTest.php +++ b/test/Domain/Service/RequestAccessFromThirdPartyTest.php @@ -7,8 +7,8 @@ AccessToken, RequestAccessFromThirdParty, }; -use Phant\Auth\Domain\DataStructure\Value\{ - RequestAccessToken, +use Phant\Auth\Domain\DataStructure\RequestAccess\{ + Token, }; use Phant\Auth\Domain\Service\RequestAccessFromThirdParty as ServiceRequestAccessFromThirdParty; @@ -26,7 +26,7 @@ final class RequestAccessFromThirdPartyTest extends \PHPUnit\Framework\TestCase { protected ServiceRequestAccessFromThirdParty $service; - protected RequestAccessToken $fixture; + protected Token $fixture; public function setUp(): void { @@ -39,7 +39,7 @@ public function setUp(): void public function testGenerate(): void { $this->assertIsObject($this->fixture); - $this->assertInstanceOf(RequestAccessToken::class, $this->fixture); + $this->assertInstanceOf(Token::class, $this->fixture); } public function testSetStatus(): void diff --git a/test/Domain/Service/RequestAccessTest.php b/test/Domain/Service/RequestAccessTest.php index a6d6c16..af54bba 100644 --- a/test/Domain/Service/RequestAccessTest.php +++ b/test/Domain/Service/RequestAccessTest.php @@ -4,7 +4,7 @@ namespace Test\Domain\Service; use Phant\Auth\Domain\DataStructure\RequestAccessFromOtp; -use Phant\Auth\Domain\DataStructure\Value\RequestAccessToken; +use Phant\Auth\Domain\DataStructure\RequestAccess\Token; use Phant\Auth\Domain\Service\RequestAccess as ServiceRequestAccess; use Phant\Auth\Fixture\DataStructure\RequestAccessFromOtp as FixtureRequestAccessFromOtp; @@ -55,7 +55,7 @@ public function testGetToken(): void ); $this->assertIsObject($value); - $this->assertInstanceOf(RequestAccessToken::class, $value); + $this->assertInstanceOf(Token::class, $value); } public function testGetFromToken(): void From 3c5cd3bfb6e694599c449a22420ef1194205d878 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Wed, 21 Sep 2022 11:05:04 +0200 Subject: [PATCH 36/42] Refacto OTP Sender --- README.md | 10 +++++----- .../Port/{UserNotification.php => OtpSender.php} | 4 ++-- component/Domain/Service/RequestAccessFromOtp.php | 10 +++++----- .../Port/{UserNotification.php => OtpSender.php} | 4 ++-- component/Fixture/Service/RequestAccessFromOtp.php | 4 ++-- test/Domain/Service/RequestAccessFromOtpTest.php | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) rename component/Domain/Port/{UserNotification.php => OtpSender.php} (57%) rename component/Fixture/Port/{UserNotification.php => OtpSender.php} (67%) diff --git a/README.md b/README.md index ad12353..2fe1c59 100644 --- a/README.md +++ b/README.md @@ -107,19 +107,19 @@ Process : 8. The application requests an access token, 9. The service provides an access token. -The OTP is sent to user by your own UserNotification service (e-mail, SMS, etc.). +The OTP is sent to user by your own OtpSender service (e-mail, SMS, etc.). ```php use Phant\Auth\Domain\Service\RequestAccessFromOtp as ServiceRequestAccessFromOtp; use Phant\Auth\Domain\DataStructure\Application; use Phant\Auth\Domain\DataStructure\User; -use App\UserNotification; +use App\OtpSender; // Config $repositoryApplication = new RepositoryApplication(); -$userNotification = new UserNotification(); +$OtpSender = new OtpSender(); // Build services @@ -127,7 +127,7 @@ $userNotification = new UserNotification(); $serviceRequestAccessFromOtp = new ServiceRequestAccessFromOtp( $serviceRequestAccess, $serviceAccessToken, - $userNotification + $OtpSender ); @@ -192,7 +192,7 @@ use App\RepositoryRequestAccess; // Config $repositoryApplication = new RepositoryApplication(); -$userNotification = new UserNotification(); +$OtpSender = new OtpSender(); // Build services diff --git a/component/Domain/Port/UserNotification.php b/component/Domain/Port/OtpSender.php similarity index 57% rename from component/Domain/Port/UserNotification.php rename to component/Domain/Port/OtpSender.php index b9dc820..609f163 100644 --- a/component/Domain/Port/UserNotification.php +++ b/component/Domain/Port/OtpSender.php @@ -9,7 +9,7 @@ Token, }; -interface UserNotification +interface OtpSender { - public function sendOtpFromRequestAccess(Token $requestAccessToken, RequestAccess $requestAccess, Otp $otp): void; + public function send(Token $requestAccessToken, RequestAccess $requestAccess, Otp $otp): void; } diff --git a/component/Domain/Service/RequestAccessFromOtp.php b/component/Domain/Service/RequestAccessFromOtp.php index c1ddad9..2a9279d 100644 --- a/component/Domain/Service/RequestAccessFromOtp.php +++ b/component/Domain/Service/RequestAccessFromOtp.php @@ -8,7 +8,7 @@ RequestAccess as ServiceRequestAccess, }; -use Phant\Auth\Domain\Port\UserNotification; +use Phant\Auth\Domain\Port\OtpSender; use Phant\Auth\Domain\DataStructure\{ AccessToken, Application, @@ -28,17 +28,17 @@ final class RequestAccessFromOtp protected ServiceRequestAccess $serviceRequestAccess; protected ServiceAccessToken $serviceAccessToken; - protected UserNotification $userNotification; + protected OtpSender $OtpSender; public function __construct( ServiceRequestAccess $serviceRequestAccess, ServiceAccessToken $serviceAccessToken, - UserNotification $userNotification + OtpSender $OtpSender ) { $this->serviceRequestAccess = $serviceRequestAccess; $this->serviceAccessToken = $serviceAccessToken; - $this->userNotification = $userNotification; + $this->otpSender = $OtpSender; } public function generate(Application $application, User $user, int $numberOfAttemptsLimit = 3, int $lifetime = self::LIFETIME): Token @@ -47,7 +47,7 @@ public function generate(Application $application, User $user, int $numberOfAtte $requestAccessToken = $this->serviceRequestAccess->getToken($requestAccess); - $this->userNotification->sendOtpFromRequestAccess($requestAccessToken, $requestAccess, $requestAccess->getOtp()); + $this->otpSender->send($requestAccessToken, $requestAccess, $requestAccess->getOtp()); $this->serviceRequestAccess->set($requestAccess); diff --git a/component/Fixture/Port/UserNotification.php b/component/Fixture/Port/OtpSender.php similarity index 67% rename from component/Fixture/Port/UserNotification.php rename to component/Fixture/Port/OtpSender.php index e710dbf..54802bd 100644 --- a/component/Fixture/Port/UserNotification.php +++ b/component/Fixture/Port/OtpSender.php @@ -10,7 +10,7 @@ Token, }; -final class UserNotification implements \Phant\Auth\Domain\Port\UserNotification +final class OtpSender implements \Phant\Auth\Domain\Port\OtpSender { protected CacheInterface $cache; @@ -19,7 +19,7 @@ public function __construct(CacheInterface $cache) $this->cache = $cache; } - public function sendOtpFromRequestAccess(Token $requestAccessToken, RequestAccess $requestAccess, Otp $otp): void + public function send(Token $requestAccessToken, RequestAccess $requestAccess, Otp $otp): void { $this->cache->set((string)$requestAccessToken, $otp); } diff --git a/component/Fixture/Service/RequestAccessFromOtp.php b/component/Fixture/Service/RequestAccessFromOtp.php index 5239dde..31b4f68 100644 --- a/component/Fixture/Service/RequestAccessFromOtp.php +++ b/component/Fixture/Service/RequestAccessFromOtp.php @@ -5,7 +5,7 @@ use Phant\Auth\Domain\Service\RequestAccessFromOtp as ServiceRequestAccessFromOtp; -use Phant\Auth\Fixture\Port\UserNotification as FixtureRepositoryUserNotification; +use Phant\Auth\Fixture\Port\OtpSender as FixtureRepositoryOtpSender; use Phant\Auth\Fixture\Service\{ AccessToken as FixtureServiceAccessToken, RequestAccess as FixtureServiceRequestAccess, @@ -19,7 +19,7 @@ public function __invoke(): ServiceRequestAccessFromOtp return new ServiceRequestAccessFromOtp( (new FixtureServiceRequestAccess())(), (new FixtureServiceAccessToken())(), - new FixtureRepositoryUserNotification( + new FixtureRepositoryOtpSender( new SimpleCache(realpath(__DIR__ . '/../../../test/storage/'), 'user-notification') ) ); diff --git a/test/Domain/Service/RequestAccessFromOtpTest.php b/test/Domain/Service/RequestAccessFromOtpTest.php index e15163d..d5e2876 100644 --- a/test/Domain/Service/RequestAccessFromOtpTest.php +++ b/test/Domain/Service/RequestAccessFromOtpTest.php @@ -17,7 +17,7 @@ User as FixtureUser, RequestAccessFromOtp as FixtureRequestAccessFromOtp, }; -use Phant\Auth\Fixture\Port\UserNotification as FixturePortUserNotification; +use Phant\Auth\Fixture\Port\OtpSender as FixturePortOtpSender; use Phant\Auth\Fixture\Service\{ RequestAccessFromOtp as FixtureServiceRequestAccessFromOtp, }; From 5df0ae2e82d7239223dd4a5c70b3068288b377ca Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Wed, 21 Sep 2022 11:06:00 +0200 Subject: [PATCH 37/42] Doc --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2fe1c59..54d938d 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ For each use case the following setup is required. ```php use Phant\Auth\Domain\Service\AccessToken as ServiceAccessToken; use Phant\Auth\Domain\Service\RequestAccess as ServiceRequestAccess; -use Phant\Auth\FixtDomainure\DataStructure\Value\SslKey; +use Phant\Auth\FixtDomainure\DataStructure\SslKey; use App\RepositoryRequestAccess; @@ -255,7 +255,7 @@ For each use case the following setup is required. ```php use Phant\Auth\Domain\Service\AccessToken as ServiceAccessToken; use Phant\Auth\Domain\Service\RequestAccess as ServiceRequestAccess; -use Phant\Auth\FixtDomainure\DataStructure\Value\SslKey; +use Phant\Auth\FixtDomainure\DataStructure\SslKey; use App\RepositoryRequestAccess; From 418ba4ab8fc2f50745e950c4bbfa9b52587757af Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Wed, 21 Sep 2022 11:06:37 +0200 Subject: [PATCH 38/42] Doc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 54d938d..d27bb2f 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ For each use case the following setup is required. ```php use Phant\Auth\Domain\Service\AccessToken as ServiceAccessToken; use Phant\Auth\Domain\Service\RequestAccess as ServiceRequestAccess; -use Phant\Auth\FixtDomainure\DataStructure\SslKey; +use Phant\Auth\Domain\DataStructure\SslKey; use App\RepositoryRequestAccess; From 20052596d5ecfb894c396ae97d02865731f92ac9 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Wed, 21 Sep 2022 11:20:01 +0200 Subject: [PATCH 39/42] Request access get lifetime & expiration --- component/Domain/DataStructure/RequestAccess.php | 14 ++++++++++++++ test/Domain/DataStructure/RequestAccessTest.php | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/component/Domain/DataStructure/RequestAccess.php b/component/Domain/DataStructure/RequestAccess.php index 4ad473c..a5061c0 100644 --- a/component/Domain/DataStructure/RequestAccess.php +++ b/component/Domain/DataStructure/RequestAccess.php @@ -20,6 +20,7 @@ abstract class RequestAccess extends \Phant\DataStructure\Abstract\Entity { + const TOKEN_PAYLOAD_LIFETIME = 'lifetime'; const TOKEN_PAYLOAD_EXPIRATION = 'expiration'; const TOKEN_PAYLOAD_ID = 'request_access_id'; @@ -28,6 +29,7 @@ abstract class RequestAccess extends \Phant\DataStructure\Abstract\Entity protected ?User $user; protected AuthMethod $authMethod; protected State $state; + protected int $lifetime; protected int $expiration; public function __construct( @@ -44,6 +46,7 @@ public function __construct( $this->user = $user; $this->authMethod = $authMethod; $this->state = $state; + $this->lifetime = $lifetime; $this->expiration = time() + $lifetime; } @@ -106,11 +109,22 @@ public function getState(): State return $this->state; } + public function getLifetime(): int + { + return $this->lifetime; + } + + public function getExpiration(): int + { + return $this->expiration; + } + public function tokenizeId(SslKey $sslKey): Token { $id = (string)$this->id; $datas = json_encode([ + self::TOKEN_PAYLOAD_LIFETIME => $this->lifetime, self::TOKEN_PAYLOAD_EXPIRATION => $this->expiration, self::TOKEN_PAYLOAD_ID => $id, ]); diff --git a/test/Domain/DataStructure/RequestAccessTest.php b/test/Domain/DataStructure/RequestAccessTest.php index 7dc1dc5..cd76425 100644 --- a/test/Domain/DataStructure/RequestAccessTest.php +++ b/test/Domain/DataStructure/RequestAccessTest.php @@ -138,6 +138,20 @@ public function testSetStateInvalid(): void $entity = $this->fixture->setState(new State(State::REQUESTED)); } + public function testGetLifetime(): void + { + $value = $this->fixture->getLifetime(); + + $this->assertIsInt($value); + } + + public function testGetExpiration(): void + { + $value = $this->fixture->getExpiration(); + + $this->assertIsInt($value); + } + public function testTokenizeIdAndUntokenizeId(): void { $result = $this->fixture->tokenizeId(FixtureSslKey::get()); From 83edaf2e771e9302e0c34083c011e3fb11f68cb8 Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Wed, 21 Sep 2022 11:49:00 +0200 Subject: [PATCH 40/42] Refacto request access token interface --- component/Domain/Service/RequestAccessFromOtp.php | 12 +++++++++--- .../Domain/Service/RequestAccessFromThirdParty.php | 8 ++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/component/Domain/Service/RequestAccessFromOtp.php b/component/Domain/Service/RequestAccessFromOtp.php index 2a9279d..198aa57 100644 --- a/component/Domain/Service/RequestAccessFromOtp.php +++ b/component/Domain/Service/RequestAccessFromOtp.php @@ -54,8 +54,10 @@ public function generate(Application $application, User $user, int $numberOfAtte return $requestAccessToken; } - public function verify(Token $requestAccessToken, string|Otp $otp): bool + public function verify(string|Token $requestAccessToken, string|Otp $otp): bool { + if (is_string($requestAccessToken)) $requestAccessToken = new Token($requestAccessToken); + $requestAccess = $this->serviceRequestAccess->getFromToken($requestAccessToken); if (is_string($otp)) $otp = new Otp($otp); @@ -74,15 +76,19 @@ public function verify(Token $requestAccessToken, string|Otp $otp): bool return true; } - public function getNumberOfRemainingAttempts(Token $requestAccessToken): int + public function getNumberOfRemainingAttempts(string|Token $requestAccessToken): int { + if (is_string($requestAccessToken)) $requestAccessToken = new Token($requestAccessToken); + $requestAccess = $this->serviceRequestAccess->getFromToken($requestAccessToken); return $requestAccess->getNumberOfRemainingAttempts($requestAccess); } - public function getAccessToken(Token $requestAccessToken): ?AccessToken + public function getAccessToken(string|Token $requestAccessToken): ?AccessToken { + if (is_string($requestAccessToken)) $requestAccessToken = new Token($requestAccessToken); + $requestAccess = $this->serviceRequestAccess->getFromToken($requestAccessToken); $accessToken = $this->serviceAccessToken->getFromToken($requestAccess); diff --git a/component/Domain/Service/RequestAccessFromThirdParty.php b/component/Domain/Service/RequestAccessFromThirdParty.php index d29df93..15b134e 100644 --- a/component/Domain/Service/RequestAccessFromThirdParty.php +++ b/component/Domain/Service/RequestAccessFromThirdParty.php @@ -47,8 +47,10 @@ public function generate(Application $application, int $lifetime = self::LIFETIM return $requestAccessToken; } - public function setStatus(Token $requestAccessToken, User $user, bool $isAuthorized): void + public function setStatus(string|Token $requestAccessToken, User $user, bool $isAuthorized): void { + if (is_string($requestAccessToken)) $requestAccessToken = new Token($requestAccessToken); + $requestAccess = $this->serviceRequestAccess->getFromToken($requestAccessToken); $requestAccess->setUser($user); @@ -57,8 +59,10 @@ public function setStatus(Token $requestAccessToken, User $user, bool $isAuthori $this->serviceRequestAccess->set($requestAccess); } - public function getAccessToken(Token $requestAccessToken): ?AccessToken + public function getAccessToken(string|Token $requestAccessToken): ?AccessToken { + if (is_string($requestAccessToken)) $requestAccessToken = new Token($requestAccessToken); + $requestAccess = $this->serviceRequestAccess->getFromToken($requestAccessToken); $accessToken = $this->serviceAccessToken->getFromToken($requestAccess); From c90009af7c5f79958d7887405de6fee16abfcd3e Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Wed, 21 Sep 2022 12:59:27 +0200 Subject: [PATCH 41/42] Request access third party with callback URL --- .../RequestAccess/CallbackUrl.php | 8 ++++++++ .../RequestAccessFromThirdParty.php | 11 +++++++++++ .../Service/RequestAccessFromThirdParty.php | 19 ++++++++++++++++--- .../RequestAccessFromThirdParty.php | 6 +++++- .../RequestAccessFromThirdPartyTest.php | 10 ++++++++++ .../RequestAccessFromThirdPartyTest.php | 14 +++++++++++++- 6 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 component/Domain/DataStructure/RequestAccess/CallbackUrl.php diff --git a/component/Domain/DataStructure/RequestAccess/CallbackUrl.php b/component/Domain/DataStructure/RequestAccess/CallbackUrl.php new file mode 100644 index 0000000..15c1007 --- /dev/null +++ b/component/Domain/DataStructure/RequestAccess/CallbackUrl.php @@ -0,0 +1,8 @@ +callbackUrl = $callbackUrl; + } + + public function getCallbackUrl(): CallbackUrl + { + return $this->callbackUrl; } } diff --git a/component/Domain/Service/RequestAccessFromThirdParty.php b/component/Domain/Service/RequestAccessFromThirdParty.php index 15b134e..f3d7632 100644 --- a/component/Domain/Service/RequestAccessFromThirdParty.php +++ b/component/Domain/Service/RequestAccessFromThirdParty.php @@ -15,6 +15,7 @@ User, }; use Phant\Auth\Domain\DataStructure\RequestAccess\{ + CallbackUrl, Id, State, Token, @@ -36,9 +37,11 @@ public function __construct( $this->serviceAccessToken = $serviceAccessToken; } - public function generate(Application $application, int $lifetime = self::LIFETIME): Token + public function generate(Application $application, string|CallbackUrl $callbackUrl, int $lifetime = self::LIFETIME): Token { - $requestAccess = $this->build($application, $lifetime); + if (is_string($callbackUrl)) $callbackUrl = new CallbackUrl($callbackUrl); + + $requestAccess = $this->build($application, $callbackUrl, $lifetime); $requestAccessToken = $this->serviceRequestAccess->getToken($requestAccess); @@ -59,6 +62,15 @@ public function setStatus(string|Token $requestAccessToken, User $user, bool $is $this->serviceRequestAccess->set($requestAccess); } + public function getCallbackUrl(string|Token $requestAccessToken): CallbackUrl + { + if (is_string($requestAccessToken)) $requestAccessToken = new Token($requestAccessToken); + + $requestAccess = $this->serviceRequestAccess->getFromToken($requestAccessToken); + + return $requestAccess->getCallbackUrl(); + } + public function getAccessToken(string|Token $requestAccessToken): ?AccessToken { if (is_string($requestAccessToken)) $requestAccessToken = new Token($requestAccessToken); @@ -70,10 +82,11 @@ public function getAccessToken(string|Token $requestAccessToken): ?AccessToken return $accessToken; } - private function build(Application $application, int $lifetime): EntityRequestAccessFromThirdParty + private function build(Application $application, CallbackUrl $callbackUrl, int $lifetime): EntityRequestAccessFromThirdParty { return new EntityRequestAccessFromThirdParty( $application, + $callbackUrl, $lifetime ); } diff --git a/component/Fixture/DataStructure/RequestAccessFromThirdParty.php b/component/Fixture/DataStructure/RequestAccessFromThirdParty.php index 0a48a35..3622053 100644 --- a/component/Fixture/DataStructure/RequestAccessFromThirdParty.php +++ b/component/Fixture/DataStructure/RequestAccessFromThirdParty.php @@ -4,7 +4,10 @@ namespace Phant\Auth\Fixture\DataStructure; use Phant\Auth\Domain\DataStructure\RequestAccessFromThirdParty as EntityRequestAccessFromThirdParty; -use Phant\Auth\Domain\DataStructure\RequestAccess\State; +use Phant\Auth\Domain\DataStructure\RequestAccess\{ + CallbackUrl, + State, +}; use Phant\Auth\Fixture\DataStructure\Application as FixtureApplication; use Phant\Auth\Fixture\DataStructure\User as FixtureUser; @@ -17,6 +20,7 @@ public static function get(?State $state = null, int $lifetime = 900): EntityReq return new EntityRequestAccessFromThirdParty( FixtureApplication::get(), + new CallbackUrl('https://domain.ext/path'), $lifetime ); } diff --git a/test/Domain/DataStructure/RequestAccessFromThirdPartyTest.php b/test/Domain/DataStructure/RequestAccessFromThirdPartyTest.php index 3c2565c..7a76d44 100644 --- a/test/Domain/DataStructure/RequestAccessFromThirdPartyTest.php +++ b/test/Domain/DataStructure/RequestAccessFromThirdPartyTest.php @@ -5,6 +5,7 @@ use Phant\Auth\Domain\DataStructure\RequestAccessFromThirdParty; use Phant\Auth\Domain\DataStructure\RequestAccess\{ + CallbackUrl, Id, State, }; @@ -27,10 +28,19 @@ public function testConstruct(): void { $entity = new RequestAccessFromThirdParty( FixtureApplication::get(), + new CallbackUrl('https://domain.ext/path'), 900 ); $this->assertIsObject($entity); $this->assertInstanceOf(RequestAccessFromThirdParty::class, $entity); } + + public function testGetCallbackUrl(): void + { + $value = $this->fixture->getCallbackUrl(); + + $this->assertIsObject($value); + $this->assertInstanceOf(CallbackUrl::class, $value); + } } diff --git a/test/Domain/Service/RequestAccessFromThirdPartyTest.php b/test/Domain/Service/RequestAccessFromThirdPartyTest.php index bcc8dde..7bc1283 100644 --- a/test/Domain/Service/RequestAccessFromThirdPartyTest.php +++ b/test/Domain/Service/RequestAccessFromThirdPartyTest.php @@ -8,6 +8,7 @@ RequestAccessFromThirdParty, }; use Phant\Auth\Domain\DataStructure\RequestAccess\{ + CallbackUrl, Token, }; use Phant\Auth\Domain\Service\RequestAccessFromThirdParty as ServiceRequestAccessFromThirdParty; @@ -32,7 +33,8 @@ public function setUp(): void { $this->service = (new FixtureServiceRequestAccessFromThirdParty())(); $this->fixture = $this->service->generate( - FixtureApplication::get() + FixtureApplication::get(), + 'https://domain.ext/path' ); } @@ -69,6 +71,16 @@ public function testSetStatusToken(): void $this->assertInstanceOf(AccessToken::class, $entity); } + public function testGetCallbackUrl(): void + { + $value = $this->service->getCallbackUrl( + $this->fixture + ); + + $this->assertIsObject($value); + $this->assertInstanceOf(CallbackUrl::class, $value); + } + public function testGetAccessTokenInvalid(): void { $this->expectException(NotAuthorized::class); From 825a908856b277f53b3e55cc463459c3809e20ef Mon Sep 17 00:00:00 2001 From: Lenny ROUANET Date: Wed, 21 Sep 2022 14:08:13 +0200 Subject: [PATCH 42/42] Doc --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d27bb2f..61b36bf 100644 --- a/README.md +++ b/README.md @@ -211,7 +211,10 @@ $application = new Application( 'https://domain.ext/image.ext' ); -$requestAccessToken = $serviceRequestAccessFromThirdParty->generate($application); +$requestAccessToken = $serviceRequestAccessFromThirdParty->generate( + $application, + 'https://domain.ext/callback/url' +); // Request third party auth with requestAccessToken