diff --git a/src/web/backend/app/Guards/ApiGuard.php b/src/web/backend/app/Guards/ApiGuard.php index 5b1565d2bcf053f085d51b696665c87023e1a565..e881b2ba495f3ebd1bf8050e98a03b33f2cc94d5 100644 --- a/src/web/backend/app/Guards/ApiGuard.php +++ b/src/web/backend/app/Guards/ApiGuard.php @@ -10,6 +10,8 @@ use Illuminate\Http\Request; use Illuminate\Auth\GuardHelpers; use Illuminate\Contracts\Auth\Guard; use Illuminate\Contracts\Auth\Authenticatable; +use Source\UseCases\Token\Authenticate\AuthenticateUseCase; +use Source\UseCases\Token\Authenticate\TranslationPresenter; class ApiGuard implements Guard { use GuardHelpers; @@ -35,21 +37,25 @@ class ApiGuard implements Guard { */ protected string $storageKey; + protected AuthenticateUseCase $authenticator; + /** * Create a new authentication guard. * - * @param Request $request - * @param string $inputKey - * @param string $storageKey - * @return void + * @param AuthenticateUseCase $authenticator + * @param Request $request + * @param string $inputKey + * @param string $storageKey */ public function __construct( + AuthenticateUseCase $authenticator, Request $request, $inputKey = 'api_token', $storageKey = 'api_token') { $this->request = $request; $this->inputKey = $inputKey; $this->storageKey = $storageKey; + $this->authenticator = $authenticator; } /** @@ -135,10 +141,10 @@ class ApiGuard implements Guard { * @return Authenticatable|null */ public function retrieveByToken(string $token): ?Authenticatable { - $token = Token::where($this->storageKey, $token)->first(); - if ($token) { - return $token->user()->first(); - } - return null; + $presenter = new TranslationPresenter(); + + $this->authenticator->check($presenter, $token); + + return $presenter->getViewModel(); } } diff --git a/src/web/backend/app/Providers/AppServiceProvider.php b/src/web/backend/app/Providers/AppServiceProvider.php index 34288ac2fca83f287009317841998ad31de02385..91504283d8872dfa4949af40ab2ed367ba4d9734 100644 --- a/src/web/backend/app/Providers/AppServiceProvider.php +++ b/src/web/backend/app/Providers/AppServiceProvider.php @@ -3,14 +3,14 @@ namespace App\Providers; use Illuminate\Support\ServiceProvider; -use Source\UseCases\Users\GetUser\GetUserUseCase; use Source\Gateways\Users\UsersRepositoryServiceProvider; -use Source\UseCases\Users\GetAllUsers\GetAllUsersUseCase; +use Source\Gateways\Tokens\TokensRepositoryServiceProvider; use Source\UseCases\Users\GetUser\GetUserUseCaseServiceProvider; use Source\UseCases\Users\CreateUser\CreateUserUseCaseServiceProvider; use Source\UseCases\Users\DeleteUser\DeleteUserUseCaseServiceProvider; use Source\UseCases\Users\UpdateUser\UpdateUserUseCaseServiceProvider; use Source\UseCases\Users\GetAllUsers\GetAllUsersUseCaseServiceProvider; +use Source\UseCases\Token\Authenticate\AuthenticateUseCaseServiceProvider; class AppServiceProvider extends ServiceProvider { @@ -20,6 +20,7 @@ class AppServiceProvider extends ServiceProvider */ protected array $gatewayProviders = [ UsersRepositoryServiceProvider::class, + TokensRepositoryServiceProvider::class, ]; /** @@ -31,6 +32,8 @@ class AppServiceProvider extends ServiceProvider UpdateUserUseCaseServiceProvider::class, CreateUserUseCaseServiceProvider::class, GetAllUsersUseCaseServiceProvider::class, + + AuthenticateUseCaseServiceProvider::class, ]; /** diff --git a/src/web/backend/app/Providers/AuthServiceProvider.php b/src/web/backend/app/Providers/AuthServiceProvider.php index e3f6caf26972f6e3bb9e92e135971e1957f5dd41..df3a98fa43e08d4ca0ecea0acb64476128e72473 100644 --- a/src/web/backend/app/Providers/AuthServiceProvider.php +++ b/src/web/backend/app/Providers/AuthServiceProvider.php @@ -4,6 +4,7 @@ namespace App\Providers; use App\Guards\ApiGuard; use Illuminate\Support\Facades\Auth; +use Source\UseCases\Token\Authenticate\AuthenticateUseCase; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; class AuthServiceProvider extends ServiceProvider { @@ -28,7 +29,7 @@ class AuthServiceProvider extends ServiceProvider { Auth::extend( 'api', static function ($app, $name, array $config) { - return new ApiGuard($app['request']); + return new ApiGuard($app->make(AuthenticateUseCase::class), $app['request']); } ); } diff --git a/src/web/backend/app/User.php b/src/web/backend/app/User.php index 26555d6d82aa9150c3dd602510f5eb682a2a79ff..d64bbf7b0cdaa0f6ac39b35615c35ba67d7f89bd 100644 --- a/src/web/backend/app/User.php +++ b/src/web/backend/app/User.php @@ -9,6 +9,10 @@ use Illuminate\Foundation\Auth\User as Authenticatable; class User extends Authenticatable { use SoftDeletes; + protected $fillable = [ + '*', + ]; + /** * The attributes that should be cast to native types. * diff --git a/src/web/backend/src/Entities/User.php b/src/web/backend/src/Entities/User.php index de8b8b439887d06c3a57c600c2984ea2cb5be381..5b133489c3bbd12346333a7ce6ede2b2b7e67155 100644 --- a/src/web/backend/src/Entities/User.php +++ b/src/web/backend/src/Entities/User.php @@ -38,9 +38,9 @@ class User { protected string $email; /** - * @var string + * @var string|null */ - protected string $password; + protected ?string $password; /** * @var string @@ -81,7 +81,7 @@ class User { string $displayName, ?string $emplid, string $email, - string $password, + ?string $password, string $doorcode, ?Carbon $expiresAt, ?Carbon $createdAt, @@ -142,9 +142,9 @@ class User { } /** - * @return string + * @return string|null */ - public function getPassword(): string { + public function getPassword(): ?string { return $this->password; } @@ -196,6 +196,9 @@ class User { } public function matchCredentials(?string $email, ?string $password): bool { + if (!$password || !$email) { + return false; + } return $this->getEmail() === $email && $this->getPassword() === $password; } diff --git a/src/web/backend/src/Gateways/Tokens/LocalTokensRepository.php b/src/web/backend/src/Gateways/Tokens/LocalTokensRepository.php index 6e7769d48a6811b1970076976fcc7d88f738a6ed..62f7658ed13b739d686e4212dc9429bda50eefb9 100644 --- a/src/web/backend/src/Gateways/Tokens/LocalTokensRepository.php +++ b/src/web/backend/src/Gateways/Tokens/LocalTokensRepository.php @@ -10,6 +10,6 @@ use Source\Entities\Token; class LocalTokensRepository extends InMemoryTokensRepository { public function __construct() { $this->tokens[] = new Token(1, 1, 'token_string', 'basic token'); - $this->tokens[] = new Token(2, 420, 'expired token', Carbon::now()->subDays(3)); + $this->tokens[] = new Token(2, 420, 'expired_token', '', Carbon::now()->subDays(3)); } } diff --git a/src/web/backend/src/Gateways/Tokens/TokensRepository.php b/src/web/backend/src/Gateways/Tokens/TokensRepository.php index 3d6fb459f145a49bcf089be6624ba934492092d1..0bf7ba52a1f024f829756e7090a0863c0b3ae8a5 100644 --- a/src/web/backend/src/Gateways/Tokens/TokensRepository.php +++ b/src/web/backend/src/Gateways/Tokens/TokensRepository.php @@ -4,7 +4,6 @@ namespace Source\Gateways\Tokens; -use Source\Entities\User; use Source\Entities\Token; use Source\Exceptions\EntityNotFoundException; @@ -18,7 +17,7 @@ interface TokensRepository { /** * @param string $token - * @return User|null + * @return Token|null */ public function findByToken(string $token): ?Token; } diff --git a/src/web/backend/src/Gateways/Users/DatabaseUsersRepository.php b/src/web/backend/src/Gateways/Users/DatabaseUsersRepository.php index 6c6f7e09fc9b219c73a70fc55dc9a9d964f01a5b..065734129274cd5d12c94dd37a0cad54c2a248d7 100644 --- a/src/web/backend/src/Gateways/Users/DatabaseUsersRepository.php +++ b/src/web/backend/src/Gateways/Users/DatabaseUsersRepository.php @@ -107,6 +107,7 @@ class DatabaseUsersRepository implements UsersRepository { $dbUser->email = $user->getEmail(); $dbUser->password = bcrypt($user->getPassword()); $dbUser->doorcode = hash('sha256', $user->getDoorcode()); + $dbUser->expires_at = $user->getExpiresAt(); $dbUser->save(); diff --git a/src/web/backend/src/UseCases/Token/Authenticate/Authenticate.php b/src/web/backend/src/UseCases/Token/Authenticate/Authenticate.php new file mode 100644 index 0000000000000000000000000000000000000000..640185899e6eba29eabce66e2f60763652fe9a86 --- /dev/null +++ b/src/web/backend/src/UseCases/Token/Authenticate/Authenticate.php @@ -0,0 +1,46 @@ +tokens = $tokens; + $this->users = $users; + } + + + /** + * @inheritDoc + */ + public function check(Presenter $presenter, ?string $token): void { + if (!$token) { + return; + } + + $found = $this->tokens->findByToken($token); + + if (!$found) { + return; + } + + $response = new ResponseModel(); + + $user = $this->users->get($found->getUserId()); + + $response->setUser($user); + + $presenter->present($response); + } +} diff --git a/src/web/backend/src/UseCases/Token/Authenticate/AuthenticateUseCase.php b/src/web/backend/src/UseCases/Token/Authenticate/AuthenticateUseCase.php new file mode 100644 index 0000000000000000000000000000000000000000..7539e7587d93f3d9359726551129a261a10e0eab --- /dev/null +++ b/src/web/backend/src/UseCases/Token/Authenticate/AuthenticateUseCase.php @@ -0,0 +1,15 @@ +app->bind( + AuthenticateUseCase::class, + static function (Application $app) { + return new Authenticate($app->make(TokensRepository::class), $app->make(UsersRepository::class)); + } + ); + } + + /** + * Bootstrap any application services. + * + * @return void + */ + public function boot(): void { + } + + /** + * @return array + */ + public function provides() { + return [AuthenticateUseCase::class]; + } +} diff --git a/src/web/backend/src/UseCases/Token/Authenticate/Presenter.php b/src/web/backend/src/UseCases/Token/Authenticate/Presenter.php new file mode 100644 index 0000000000000000000000000000000000000000..bb2ddb080c976e63cd8b405b68053497cd534afd --- /dev/null +++ b/src/web/backend/src/UseCases/Token/Authenticate/Presenter.php @@ -0,0 +1,18 @@ +user = $user; + } + + /** + * @return User|null + */ + public function getUser(): ?User { + return $this->user; + } +} diff --git a/src/web/backend/src/UseCases/Token/Authenticate/TranslationPresenter.php b/src/web/backend/src/UseCases/Token/Authenticate/TranslationPresenter.php new file mode 100644 index 0000000000000000000000000000000000000000..1f12add73250a3c958cf84ef207c009ab26ddbb5 --- /dev/null +++ b/src/web/backend/src/UseCases/Token/Authenticate/TranslationPresenter.php @@ -0,0 +1,38 @@ +getUser(); + + if (!$user) { + return; + } + + $dbUser = new User(); + + $dbUser->id = $user->getId(); + $dbUser->email = $user->getEmail(); + $dbUser->first_name = $user->getFirstName(); + $dbUser->last_name = $user->getLastName(); + $dbUser->display_name = $user->getDisplayName(); + $dbUser->emplid = $user->getEmplid(); + $dbUser->created_at = $user->getCreatedAt(); + $dbUser->expires_at = $user->getExpiresAt(); + $dbUser->updated_at = $user->getUpdatedAt(); + + $this->viewModel = $dbUser; + } + + /** @inheritDoc */ + public function getViewModel(): ?User { + return $this->viewModel; + } +}