diff --git a/composer.json b/composer.json index cbcf77d3..97841117 100644 --- a/composer.json +++ b/composer.json @@ -48,6 +48,7 @@ "symfony/http-foundation": "^6.1", "symfony/http-kernel": "^6.1", "symfony/monolog-bundle": "^3.8", + "symfony/security-bundle": "^6.1", "symfony/twig-bundle": "^6.1", "symfony/uid": "^6.1", "symfony/validator": "^6.1", diff --git a/composer.lock b/composer.lock index 1ca521bd..37d84567 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0e1a45b7d6070dffd8b6398e7286d722", + "content-hash": "0a143e405f68316705db39775f052d4c", "packages": [ { "name": "doctrine/annotations", @@ -4904,6 +4904,78 @@ ], "time": "2022-05-10T14:24:36+00:00" }, + { + "name": "symfony/password-hasher", + "version": "v6.1.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/password-hasher.git", + "reference": "264894821636b77bb8282db6ec33b8b07b7a0678" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/password-hasher/zipball/264894821636b77bb8282db6ec33b8b07b7a0678", + "reference": "264894821636b77bb8282db6ec33b8b07b7a0678", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "conflict": { + "symfony/security-core": "<5.4" + }, + "require-dev": { + "symfony/console": "^5.4|^6.0", + "symfony/security-core": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PasswordHasher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Robin Chalas", + "email": "robin.chalas@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides password hashing utilities", + "homepage": "https://symfony.com", + "keywords": [ + "hashing", + "password" + ], + "support": { + "source": "https://github.com/symfony/password-hasher/tree/v6.1.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-20T14:45:06+00:00" + }, { "name": "symfony/polyfill-ctype", "version": "v1.26.0", @@ -5475,6 +5547,174 @@ ], "time": "2022-05-24T11:49:31+00:00" }, + { + "name": "symfony/property-access", + "version": "v6.1.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-access.git", + "reference": "25108ee9b62d6ef0815007d9c7cf6a7ba40bb7c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-access/zipball/25108ee9b62d6ef0815007d9c7cf6a7ba40bb7c5", + "reference": "25108ee9b62d6ef0815007d9c7cf6a7ba40bb7c5", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/property-info": "^5.4|^6.0" + }, + "require-dev": { + "symfony/cache": "^5.4|^6.0" + }, + "suggest": { + "psr/cache-implementation": "To cache access methods." + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyAccess\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides functions to read and write from/to an object or array using a simple string notation", + "homepage": "https://symfony.com", + "keywords": [ + "access", + "array", + "extraction", + "index", + "injection", + "object", + "property", + "property path", + "reflection" + ], + "support": { + "source": "https://github.com/symfony/property-access/tree/v6.1.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-06-27T17:24:16+00:00" + }, + { + "name": "symfony/property-info", + "version": "v6.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-info.git", + "reference": "f28d0db9d2687f81d68d0dc6b2e42817647f5d64" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-info/zipball/f28d0db9d2687f81d68d0dc6b2e42817647f5d64", + "reference": "f28d0db9d2687f81d68d0dc6b2e42817647f5d64", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/string": "^5.4|^6.0" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "<5.2", + "phpdocumentor/type-resolver": "<1.5.1", + "symfony/dependency-injection": "<5.4" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4", + "phpdocumentor/reflection-docblock": "^5.2", + "phpstan/phpdoc-parser": "^1.0", + "symfony/cache": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/serializer": "^5.4|^6.0" + }, + "suggest": { + "phpdocumentor/reflection-docblock": "To use the PHPDoc", + "psr/cache-implementation": "To cache results", + "symfony/doctrine-bridge": "To use Doctrine metadata", + "symfony/serializer": "To use Serializer metadata" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyInfo\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "dunglas@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Extracts information about PHP class' properties using metadata of popular sources", + "homepage": "https://symfony.com", + "keywords": [ + "doctrine", + "phpdoc", + "property", + "symfony", + "type", + "validator" + ], + "support": { + "source": "https://github.com/symfony/property-info/tree/v6.1.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-07T08:04:03+00:00" + }, { "name": "symfony/routing", "version": "v6.1.3", @@ -5563,6 +5803,351 @@ ], "time": "2022-07-20T15:00:40+00:00" }, + { + "name": "symfony/security-bundle", + "version": "v6.1.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-bundle.git", + "reference": "1410129e36e5d0cf4bde73f4ed5d9e18acff06b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-bundle/zipball/1410129e36e5d0cf4bde73f4ed5d9e18acff06b3", + "reference": "1410129e36e5d0cf4bde73f4ed5d9e18acff06b3", + "shasum": "" + }, + "require": { + "composer-runtime-api": ">=2.1", + "ext-xml": "*", + "php": ">=8.1", + "symfony/config": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/event-dispatcher": "^5.4|^6.0", + "symfony/http-foundation": "^5.4|^6.0", + "symfony/http-kernel": "^5.4|^6.0", + "symfony/password-hasher": "^5.4|^6.0", + "symfony/security-core": "^5.4|^6.0", + "symfony/security-csrf": "^5.4|^6.0", + "symfony/security-http": "^5.4|^6.0" + }, + "conflict": { + "symfony/browser-kit": "<5.4", + "symfony/console": "<5.4", + "symfony/framework-bundle": "<5.4", + "symfony/ldap": "<5.4", + "symfony/twig-bundle": "<5.4" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4", + "symfony/asset": "^5.4|^6.0", + "symfony/browser-kit": "^5.4|^6.0", + "symfony/console": "^5.4|^6.0", + "symfony/css-selector": "^5.4|^6.0", + "symfony/dom-crawler": "^5.4|^6.0", + "symfony/expression-language": "^5.4|^6.0", + "symfony/form": "^5.4|^6.0", + "symfony/framework-bundle": "^5.4|^6.0", + "symfony/ldap": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0", + "symfony/rate-limiter": "^5.4|^6.0", + "symfony/serializer": "^5.4|^6.0", + "symfony/translation": "^5.4|^6.0", + "symfony/twig-bridge": "^5.4|^6.0", + "symfony/twig-bundle": "^5.4|^6.0", + "symfony/validator": "^5.4|^6.0", + "symfony/yaml": "^5.4|^6.0", + "twig/twig": "^2.13|^3.0.4" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\SecurityBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration of the Security component into the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-bundle/tree/v6.1.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-20T13:46:29+00:00" + }, + { + "name": "symfony/security-core", + "version": "v6.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-core.git", + "reference": "e42fb611d1a36e6e1e34f8cd715cea108a39cad5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-core/zipball/e42fb611d1a36e6e1e34f8cd715cea108a39cad5", + "reference": "e42fb611d1a36e6e1e34f8cd715cea108a39cad5", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/event-dispatcher-contracts": "^1.1|^2|^3", + "symfony/password-hasher": "^5.4|^6.0", + "symfony/service-contracts": "^1.1.6|^2|^3" + }, + "conflict": { + "symfony/event-dispatcher": "<5.4", + "symfony/http-foundation": "<5.4", + "symfony/ldap": "<5.4", + "symfony/security-guard": "<5.4", + "symfony/validator": "<5.4" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "psr/container": "^1.1|^2.0", + "psr/log": "^1|^2|^3", + "symfony/cache": "^5.4|^6.0", + "symfony/event-dispatcher": "^5.4|^6.0", + "symfony/expression-language": "^5.4|^6.0", + "symfony/http-foundation": "^5.4|^6.0", + "symfony/ldap": "^5.4|^6.0", + "symfony/translation": "^5.4|^6.0", + "symfony/validator": "^5.4|^6.0" + }, + "suggest": { + "psr/container-implementation": "To instantiate the Security class", + "symfony/event-dispatcher": "", + "symfony/expression-language": "For using the expression voter", + "symfony/http-foundation": "", + "symfony/ldap": "For using LDAP integration", + "symfony/validator": "For using the user password constraint" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Core\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - Core Library", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-core/tree/v6.1.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-02T08:30:52+00:00" + }, + { + "name": "symfony/security-csrf", + "version": "v6.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-csrf.git", + "reference": "b44d74295a5651298de8c2760ba50bef3b97f34b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-csrf/zipball/b44d74295a5651298de8c2760ba50bef3b97f34b", + "reference": "b44d74295a5651298de8c2760ba50bef3b97f34b", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/security-core": "^5.4|^6.0" + }, + "conflict": { + "symfony/http-foundation": "<5.4" + }, + "require-dev": { + "symfony/http-foundation": "^5.4|^6.0" + }, + "suggest": { + "symfony/http-foundation": "For using the class SessionTokenStorage." + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Csrf\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - CSRF Library", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-csrf/tree/v6.1.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-14T12:53:54+00:00" + }, + { + "name": "symfony/security-http", + "version": "v6.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-http.git", + "reference": "789492510f7127035da8bb5dbb4fb745970e2348" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-http/zipball/789492510f7127035da8bb5dbb4fb745970e2348", + "reference": "789492510f7127035da8bb5dbb4fb745970e2348", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/http-foundation": "^5.4|^6.0", + "symfony/http-kernel": "^6.1", + "symfony/polyfill-mbstring": "~1.0", + "symfony/property-access": "^5.4|^6.0", + "symfony/security-core": "^5.4.7|^6.0" + }, + "conflict": { + "symfony/event-dispatcher": "<5.4.9|>=6,<6.0.9", + "symfony/security-bundle": "<5.4", + "symfony/security-csrf": "<5.4" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/cache": "^5.4|^6.0", + "symfony/rate-limiter": "^5.4|^6.0", + "symfony/routing": "^5.4|^6.0", + "symfony/security-csrf": "^5.4|^6.0", + "symfony/translation": "^5.4|^6.0" + }, + "suggest": { + "symfony/routing": "For using the HttpUtils class to create sub-requests, redirect the user, and match URLs", + "symfony/security-csrf": "For using tokens to protect authentication/logout attempts" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Http\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - HTTP Integration", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-http/tree/v6.1.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-01T16:55:12+00:00" + }, { "name": "symfony/service-contracts", "version": "v3.1.1", diff --git a/config/web-interface/config.yml b/config/web-interface/config.yml index 2d5cefa0..21913c7e 100644 --- a/config/web-interface/config.yml +++ b/config/web-interface/config.yml @@ -1,10 +1,5 @@ imports: - - { resource: services/console.yml } - - { resource: services/consumer.yml } - - { resource: services/controller.yml } - - { resource: services/event_listener.yml } - - { resource: services/integration.yml } - - { resource: services/persistence.yml } + - { resource: services/ } # The framework configuration belongs here, because when we transition to the microservice approach, # the other contexts don't have the concept of a session. @@ -16,3 +11,16 @@ framework: twig: paths: "%kernel.project_dir%/src/WebInterface/Presentation/Http/View": web-interface + +security: + providers: + user_provider: + id: 'web-interface.security.user_provider' + firewalls: + dev: + pattern: ^/(_(profiler|wdt)|css|images|js)/ + security: false + main: + pattern: ^/ + custom_authenticators: + - 'web-interface.security.arrival_authenticator' diff --git a/config/web-interface/services/controller.yml b/config/web-interface/services/controller.yml index ffe28019..ae76ca2c 100644 --- a/config/web-interface/services/controller.yml +++ b/config/web-interface/services/controller.yml @@ -5,6 +5,7 @@ services: arguments: - '@twig' - '@web-interface.connect-four-service' + - '@web-interface.security' tags: - 'controller.service_arguments' @@ -12,6 +13,7 @@ services: class: Gaming\WebInterface\Presentation\Http\ChatController arguments: - '@web-interface.chat-service' + - '@web-interface.security' tags: - 'controller.service_arguments' @@ -19,6 +21,7 @@ services: class: Gaming\WebInterface\Presentation\Http\ConnectFourController arguments: - '@web-interface.connect-four-service' + - '@web-interface.security' tags: - 'controller.service_arguments' @@ -26,5 +29,6 @@ services: class: Gaming\WebInterface\Presentation\Http\IdentityController arguments: - '@web-interface.identity-service' + - '@web-interface.security' tags: - 'controller.service_arguments' diff --git a/config/web-interface/services/event_listener.yml b/config/web-interface/services/event_listener.yml deleted file mode 100644 index db013c37..00000000 --- a/config/web-interface/services/event_listener.yml +++ /dev/null @@ -1,9 +0,0 @@ -services: - - web-interface.assign-user-id-on-kernel-request: - class: Gaming\WebInterface\Infrastructure\EventListener\AssignUserIdOnKernelRequest - public: false - arguments: - - '@web-interface.identity-service' - tags: - - { name: kernel.event_listener, event: kernel.request } diff --git a/config/web-interface/services/security.yml b/config/web-interface/services/security.yml new file mode 100644 index 00000000..0e712a5b --- /dev/null +++ b/config/web-interface/services/security.yml @@ -0,0 +1,17 @@ +services: + + web-interface.security: + class: Gaming\WebInterface\Infrastructure\Security\Security + arguments: + - '@security.token_storage' + + web-interface.security.user_provider: + class: Gaming\WebInterface\Infrastructure\Security\UserProvider + public: false + + web-interface.security.arrival_authenticator: + class: Gaming\WebInterface\Infrastructure\Security\ArrivalAuthenticator + public: false + arguments: + - '@web-interface.identity-service' + - '@security.token_storage' diff --git a/src/Kernel.php b/src/Kernel.php index 44046779..10cc9421 100644 --- a/src/Kernel.php +++ b/src/Kernel.php @@ -11,6 +11,7 @@ use Symfony\Bundle\DebugBundle\DebugBundle; use Symfony\Bundle\FrameworkBundle\FrameworkBundle; use Symfony\Bundle\MonologBundle\MonologBundle; +use Symfony\Bundle\SecurityBundle\SecurityBundle; use Symfony\Bundle\TwigBundle\TwigBundle; use Symfony\Bundle\WebProfilerBundle\WebProfilerBundle; use Symfony\Component\Config\Loader\LoaderInterface; @@ -31,7 +32,8 @@ public function registerBundles(): array new MareinLockDoctrineMigrationsBundle(), new MareinStandardHeadersCsrfBundle(), new TwigBundle(), - new MonologBundle() + new MonologBundle(), + new SecurityBundle() ]; if ($this->getEnvironment() === 'dev') { diff --git a/src/WebInterface/Infrastructure/EventListener/AssignUserIdOnKernelRequest.php b/src/WebInterface/Infrastructure/EventListener/AssignUserIdOnKernelRequest.php deleted file mode 100644 index 9d32e9ed..00000000 --- a/src/WebInterface/Infrastructure/EventListener/AssignUserIdOnKernelRequest.php +++ /dev/null @@ -1,36 +0,0 @@ -identityService = $identityService; - } - - public function onKernelRequest(RequestEvent $event): void - { - if (!$event->isMainRequest()) { - return; - } - - $request = $event->getRequest(); - $session = $request->getSession(); - - if (!$session->has('user')) { - // todo Create user only when it's really needed. - // Currently, a new user is created in the identity context for each visitor of this website. - // In the future, a new user must only be created when it performs an action where an identity is necessary. - // For example: open a game, sign up etc. - $session->set('user', $this->identityService->arrive()['userId']); - } - } -} diff --git a/src/WebInterface/Infrastructure/Security/ArrivalAuthenticator.php b/src/WebInterface/Infrastructure/Security/ArrivalAuthenticator.php new file mode 100644 index 00000000..c2a66d92 --- /dev/null +++ b/src/WebInterface/Infrastructure/Security/ArrivalAuthenticator.php @@ -0,0 +1,53 @@ +tokenStorage->getToken() === null; + } + + public function authenticate(Request $request): Passport + { + return new SelfValidatingPassport( + new UserBadge( + $this->identityService->arrive()['userId'] + ) + ); + } + + public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response + { + return null; + } + + public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response + { + throw $exception; + } +} diff --git a/src/WebInterface/Infrastructure/Security/Security.php b/src/WebInterface/Infrastructure/Security/Security.php new file mode 100644 index 00000000..1f4cc94d --- /dev/null +++ b/src/WebInterface/Infrastructure/Security/Security.php @@ -0,0 +1,24 @@ +tokenStorage->getToken()?->getUser() ?? new User( + (new NilUuid())->toRfc4122() + ); + } +} diff --git a/src/WebInterface/Infrastructure/Security/User.php b/src/WebInterface/Infrastructure/Security/User.php new file mode 100644 index 00000000..3dc3fdd6 --- /dev/null +++ b/src/WebInterface/Infrastructure/Security/User.php @@ -0,0 +1,29 @@ +userIdentifier; + } +} diff --git a/src/WebInterface/Infrastructure/Security/UserProvider.php b/src/WebInterface/Infrastructure/Security/UserProvider.php new file mode 100644 index 00000000..358a96b1 --- /dev/null +++ b/src/WebInterface/Infrastructure/Security/UserProvider.php @@ -0,0 +1,26 @@ +loadUserByIdentifier($user->getUserIdentifier()); + } + + public function supportsClass(string $class) + { + return $class === User::class; + } + + public function loadUserByIdentifier(string $identifier): UserInterface + { + return new User($identifier); + } +} diff --git a/src/WebInterface/Presentation/Http/ChatController.php b/src/WebInterface/Presentation/Http/ChatController.php index 4cac8925..b90c785e 100644 --- a/src/WebInterface/Presentation/Http/ChatController.php +++ b/src/WebInterface/Presentation/Http/ChatController.php @@ -5,16 +5,16 @@ namespace Gaming\WebInterface\Presentation\Http; use Gaming\WebInterface\Application\ChatService; +use Gaming\WebInterface\Infrastructure\Security\Security; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; final class ChatController { - private ChatService $chatService; - - public function __construct(ChatService $chatService) - { - $this->chatService = $chatService; + public function __construct( + private readonly ChatService $chatService, + private readonly Security $security + ) { } public function writeMessageAction(Request $request, string $chatId): JsonResponse @@ -22,7 +22,7 @@ public function writeMessageAction(Request $request, string $chatId): JsonRespon return new JsonResponse( $this->chatService->writeMessage( $chatId, - (string)$request->getSession()->get('user'), + $this->security->getUser()->getUserIdentifier(), (string)$request->request->get('message') ) ); @@ -34,7 +34,7 @@ public function messagesAction(Request $request, string $chatId): JsonResponse [ 'messages' => $this->chatService->messages( $chatId, - (string)$request->getSession()->get('user'), + $this->security->getUser()->getUserIdentifier(), 0, 10000 ) diff --git a/src/WebInterface/Presentation/Http/ConnectFourController.php b/src/WebInterface/Presentation/Http/ConnectFourController.php index 3f1484b6..8aed8247 100644 --- a/src/WebInterface/Presentation/Http/ConnectFourController.php +++ b/src/WebInterface/Presentation/Http/ConnectFourController.php @@ -5,16 +5,16 @@ namespace Gaming\WebInterface\Presentation\Http; use Gaming\WebInterface\Application\ConnectFourService; +use Gaming\WebInterface\Infrastructure\Security\Security; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; final class ConnectFourController { - private ConnectFourService $connectFourService; - - public function __construct(ConnectFourService $connectFourService) - { - $this->connectFourService = $connectFourService; + public function __construct( + private readonly ConnectFourService $connectFourService, + private readonly Security $security + ) { } public function showAction(string $gameId): JsonResponse @@ -28,7 +28,7 @@ public function openAction(Request $request): JsonResponse { return new JsonResponse( $this->connectFourService->open( - (string)$request->getSession()->get('user') + $this->security->getUser()->getUserIdentifier() ) ); } @@ -38,7 +38,7 @@ public function joinAction(Request $request, string $gameId): JsonResponse return new JsonResponse( $this->connectFourService->join( $gameId, - (string)$request->getSession()->get('user') + $this->security->getUser()->getUserIdentifier() ) ); } @@ -48,7 +48,7 @@ public function abortAction(Request $request, string $gameId): JsonResponse return new JsonResponse( $this->connectFourService->abort( $gameId, - (string)$request->getSession()->get('user') + $this->security->getUser()->getUserIdentifier() ) ); } @@ -58,7 +58,7 @@ public function resignAction(Request $request, string $gameId): JsonResponse return new JsonResponse( $this->connectFourService->resign( $gameId, - (string)$request->getSession()->get('user') + $this->security->getUser()->getUserIdentifier() ) ); } @@ -68,7 +68,7 @@ public function moveAction(Request $request, string $gameId): JsonResponse return new JsonResponse( $this->connectFourService->move( $gameId, - (string)$request->getSession()->get('user'), + $this->security->getUser()->getUserIdentifier(), (int)$request->request->get('column', -1) ) ); diff --git a/src/WebInterface/Presentation/Http/IdentityController.php b/src/WebInterface/Presentation/Http/IdentityController.php index cad4b9c7..becaacbb 100644 --- a/src/WebInterface/Presentation/Http/IdentityController.php +++ b/src/WebInterface/Presentation/Http/IdentityController.php @@ -5,23 +5,23 @@ namespace Gaming\WebInterface\Presentation\Http; use Gaming\WebInterface\Application\IdentityService; +use Gaming\WebInterface\Infrastructure\Security\Security; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; final class IdentityController { - private IdentityService $identityService; - - public function __construct(IdentityService $identityService) - { - $this->identityService = $identityService; + public function __construct( + private readonly IdentityService $identityService, + private readonly Security $security + ) { } public function signUpAction(Request $request): JsonResponse { return new JsonResponse( $this->identityService->signUp( - (string)$request->getSession()->get('user'), + $this->security->getUser()->getUserIdentifier(), (string)$request->request->get('username', uniqid()), (string)$request->request->get('password', 'password') ) diff --git a/src/WebInterface/Presentation/Http/PageController.php b/src/WebInterface/Presentation/Http/PageController.php index 61b5e116..5ea42148 100644 --- a/src/WebInterface/Presentation/Http/PageController.php +++ b/src/WebInterface/Presentation/Http/PageController.php @@ -5,22 +5,18 @@ namespace Gaming\WebInterface\Presentation\Http; use Gaming\WebInterface\Application\ConnectFourService; +use Gaming\WebInterface\Infrastructure\Security\Security; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Twig\Environment; final class PageController { - private Environment $twig; - - private ConnectFourService $connectFourService; - public function __construct( - Environment $twig, - ConnectFourService $connectFourService + private readonly Environment $twig, + private readonly ConnectFourService $connectFourService, + private readonly Security $security ) { - $this->twig = $twig; - $this->connectFourService = $connectFourService; } public function lobbyAction(): Response @@ -29,7 +25,8 @@ public function lobbyAction(): Response $this->twig->render('@web-interface/lobby.html.twig', [ 'maximumNumberOfGamesInList' => 10, 'openGames' => $this->connectFourService->openGames()['games'], - 'runningGames' => $this->connectFourService->runningGames() + 'runningGames' => $this->connectFourService->runningGames(), + 'user' => $this->security->getUser() ]) ); } @@ -48,7 +45,7 @@ public function profileAction(Request $request): Response return new Response( $this->twig->render('@web-interface/profile.html.twig', [ 'games' => $this->connectFourService->gamesByPlayer( - (string)$request->getSession()->get('user') + $this->security->getUser()->getUserIdentifier() )['games'] ]) ); diff --git a/src/WebInterface/Presentation/Http/View/lobby.html.twig b/src/WebInterface/Presentation/Http/View/lobby.html.twig index b2577b9e..b59d33fb 100644 --- a/src/WebInterface/Presentation/Http/View/lobby.html.twig +++ b/src/WebInterface/Presentation/Http/View/lobby.html.twig @@ -13,7 +13,7 @@