diff --git a/public/login.php b/public/login.php index 6a03841..12573bb 100644 --- a/public/login.php +++ b/public/login.php @@ -2,7 +2,9 @@ use Authentication\Value\ClearTextPassword; use Authentication\Value\EmailAddress; +use Infrastructure\Authentication\ReadModel\HardcodedIsUserBlocked; use Infrastructure\Authentication\Repository\FilesystemUsers; +use Infrastructure\Authentication\Service\SendNotifyOfIntrusionDetectionToStderr; require_once __DIR__ . '/../vendor/autoload.php'; @@ -19,11 +21,7 @@ $user = $users->get($email); -if (! $user->authenticate($password)) { - echo 'Nope'; - - return; -} +$user->authenticate($password, new HardcodedIsUserBlocked(), new SendNotifyOfIntrusionDetectionToStderr()); echo 'OK'; diff --git a/public/register.php b/public/register.php index c6ddfef..ead6b62 100644 --- a/public/register.php +++ b/public/register.php @@ -1,8 +1,9 @@ exists($email)) { - echo 'Already registered'; - - return; -} - -$users->store(new User($email, $password)); +$users->store(User::register($email, $password, new CheckRegisteredEmailFromRepository($users))); /** @var Notifier $notify */ // send email abstraction? diff --git a/src/Authentication/Aggregate/User.php b/src/Authentication/Aggregate/User.php new file mode 100644 index 0000000..553ea62 --- /dev/null +++ b/src/Authentication/Aggregate/User.php @@ -0,0 +1,53 @@ +email = $email; + $this->passwordHash = $password->makeHash(); + } + + public static function register( + EmailAddress $email, + ClearTextPassword $password, + EmailIsRegistered $emailIsRegistered + ) : self { + Assert::false($emailIsRegistered->__invoke($email)); + + return new self($email, $password); + } + + public function authenticate( + ClearTextPassword $password, + IsUserBlocked $blockedUsers, + NotifyOfIntrusionDetection $intrusionDetection + ) : void { + Assert::true($password->verify($this->passwordHash)); + + if ($blockedUsers->__invoke($this->email)) { + $intrusionDetection->__invoke($this->email); + + throw new \RuntimeException(sprintf( + 'User %s is blocked, and cannot authenticate', + $this->email->toString() + )); + } + } +} diff --git a/src/Authentication/Entity/User.php b/src/Authentication/Entity/User.php deleted file mode 100644 index bf346f1..0000000 --- a/src/Authentication/Entity/User.php +++ /dev/null @@ -1,27 +0,0 @@ -email = $email; - $this->passwordHash = $password->makeHash(); - } - - public function authenticate(ClearTextPassword $password) : bool - { - return $password->verify($this->passwordHash); - } -} diff --git a/src/Authentication/ReadModel/EmailIsRegistered.php b/src/Authentication/ReadModel/EmailIsRegistered.php new file mode 100644 index 0000000..e0c9e0b --- /dev/null +++ b/src/Authentication/ReadModel/EmailIsRegistered.php @@ -0,0 +1,10 @@ +users = $users; + } + + public function __invoke(EmailAddress $emailAddress) : bool + { + return $this->users->exists($emailAddress); + } +} diff --git a/src/Infrastructure/Authentication/ReadModel/HardcodedIsUserBlocked.php b/src/Infrastructure/Authentication/ReadModel/HardcodedIsUserBlocked.php new file mode 100644 index 0000000..fe52fdc --- /dev/null +++ b/src/Infrastructure/Authentication/ReadModel/HardcodedIsUserBlocked.php @@ -0,0 +1,16 @@ +toString() === 'trump@whitehouse.gov'; + } +} diff --git a/src/Infrastructure/Authentication/Repository/FilesystemUsers.php b/src/Infrastructure/Authentication/Repository/FilesystemUsers.php index 4374ad2..795f541 100644 --- a/src/Infrastructure/Authentication/Repository/FilesystemUsers.php +++ b/src/Infrastructure/Authentication/Repository/FilesystemUsers.php @@ -4,10 +4,11 @@ namespace Infrastructure\Authentication\Repository; -use Authentication\Entity\User; +use Authentication\Aggregate\User; use Authentication\Repository\Users; use Authentication\Value\EmailAddress; use Authentication\Value\PasswordHash; +use ReflectionProperty; final class FilesystemUsers implements Users { @@ -35,8 +36,8 @@ public function get(EmailAddress $emailAddress) : User /** @var User $user */ $user = (new \ReflectionClass(User::class))->newInstanceWithoutConstructor(); - $user->email = $emailAddress; - $user->passwordHash = PasswordHash::fromHash($existingUsers[$emailAddress->toString()]); + $this->reflectionEmail()->setValue($user, $emailAddress); + $this->reflectionPasswordHash()->setValue($user, PasswordHash::fromHash($existingUsers[$emailAddress->toString()])); return $user; } @@ -45,7 +46,9 @@ public function store(User $user) : void { $existingUsers = $this->existingUsers(); - $existingUsers[$user->email->toString()] = $user->passwordHash->toString(); + $existingUsers[ + $this->reflectionEmail()->getValue($user)->toString() + ] = $this->reflectionPasswordHash()->getValue($user)->toString(); file_put_contents($this->usersPath, json_encode($existingUsers)); } @@ -59,4 +62,23 @@ private function existingUsers() : array return json_decode($fileContentsReallyReally, true); } + + private function reflectionEmail() : ReflectionProperty + { + $reflectionEmail = new ReflectionProperty(User::class, 'email'); + + $reflectionEmail->setAccessible(true); + + return $reflectionEmail; + } + + private function reflectionPasswordHash() : ReflectionProperty + { + $reflectionEmail = new ReflectionProperty(User::class, 'passwordHash'); + + $reflectionEmail->setAccessible(true); + + return $reflectionEmail; + } + } diff --git a/src/Infrastructure/Authentication/Service/SendNotifyOfIntrusionDetectionToStderr.php b/src/Infrastructure/Authentication/Service/SendNotifyOfIntrusionDetectionToStderr.php new file mode 100644 index 0000000..202dad7 --- /dev/null +++ b/src/Infrastructure/Authentication/Service/SendNotifyOfIntrusionDetectionToStderr.php @@ -0,0 +1,19 @@ +toString() + )); + } +}