From fb6665668bbd86b2cc278f3fd42b0278f7ddb994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Thu, 24 Apr 2025 12:26:42 +0200 Subject: [PATCH] feat: encrypted user passwords --- composer.json | 1 + composer.lock | 63 ++++++++++++++++++- config/secret/.gitignore | 2 + config/services.yaml | 9 +++ src/BusProNet/Security/Authenticator.php | 8 ++- src/BusProNet/Security/User.php | 4 +- src/BusProNet/Security/UserProvider.php | 21 +++++-- src/Command/GenerateKeysCommand.php | 25 ++++++++ src/Controller/Booking/DownloadController.php | 39 ++++++++---- src/Controller/Booking/EditController.php | 43 +++++++------ src/Controller/Booking/IndexController.php | 20 +++--- src/Controller/PersonalDataController.php | 40 ++++++------ src/Controller/Traits/BookingDataTrait.php | 28 +++++++++ src/Controller/Traits/CredentialsTrait.php | 16 +++++ src/Security/Crypt.php | 41 ++++++++++++ src/Security/Voter/BookingVoter.php | 11 ++-- 16 files changed, 292 insertions(+), 79 deletions(-) create mode 100644 config/secret/.gitignore create mode 100644 src/Command/GenerateKeysCommand.php create mode 100644 src/Controller/Traits/BookingDataTrait.php create mode 100644 src/Controller/Traits/CredentialsTrait.php create mode 100644 src/Security/Crypt.php diff --git a/composer.json b/composer.json index 99fd2da..a8887d2 100644 --- a/composer.json +++ b/composer.json @@ -20,6 +20,7 @@ "nesbot/carbon": "^3.8", "phpdocumentor/reflection-docblock": "^5.6", "phpstan/phpdoc-parser": "^2.0", + "spatie/crypto": "^2.1", "symfony/apache-pack": "^1.0", "symfony/asset": "6.4.*", "symfony/console": "6.4.*", diff --git a/composer.lock b/composer.lock index 6a51025..80b42a2 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": "75a72111cb05768e7e978a7161b2e0e5", + "content-hash": "6fcf6eb198ed84c9f95609ce613497e0", "packages": [ { "name": "carbonphp/carbon-doctrine-types", @@ -2962,6 +2962,67 @@ }, "time": "2024-09-11T13:17:53+00:00" }, + { + "name": "spatie/crypto", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/spatie/crypto.git", + "reference": "9bda7d690ffa6a8884a8af69da2dba942bbac4eb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/crypto/zipball/9bda7d690ffa6a8884a8af69da2dba942bbac4eb", + "reference": "9bda7d690ffa6a8884a8af69da2dba942bbac4eb", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "php": "^7.4|^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", + "symfony/var-dumper": "^5.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\Crypto\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Encrypting and signing data using private/public keys", + "homepage": "https://github.com/spatie/crypto", + "keywords": [ + "crypto", + "spatie" + ], + "support": { + "source": "https://github.com/spatie/crypto/tree/2.1.0" + }, + "funding": [ + { + "url": "https://github.com/sponsors/spatie", + "type": "github" + }, + { + "url": "https://spatie.be/open-source/support-us", + "type": "other" + } + ], + "time": "2024-06-20T08:24:56+00:00" + }, { "name": "symfony/apache-pack", "version": "v1.0.1", diff --git a/config/secret/.gitignore b/config/secret/.gitignore new file mode 100644 index 0000000..469eb5d --- /dev/null +++ b/config/secret/.gitignore @@ -0,0 +1,2 @@ +*.key +!.gitignore diff --git a/config/services.yaml b/config/services.yaml index f57043e..9b65a0a 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -5,6 +5,7 @@ # https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration parameters: travel_info_base_url: '%env(APP_TRAVEL_INFO_BASE_URL)%' + path_to_keys: '%kernel.project_dir%/config/secret' services: # default configuration for services in *this* file @@ -51,3 +52,11 @@ services: - name: knp_menu.menu_builder method: createMainMenu alias: main + + App\Command\GenerateKeysCommand: + arguments: + $path: '%path_to_keys%' + + App\Security\Crypt: + arguments: + $path: '%path_to_keys%' diff --git a/src/BusProNet/Security/Authenticator.php b/src/BusProNet/Security/Authenticator.php index f7e266f..20bb7c4 100644 --- a/src/BusProNet/Security/Authenticator.php +++ b/src/BusProNet/Security/Authenticator.php @@ -4,9 +4,9 @@ namespace App\BusProNet\Security; use App\BusProNet\ApiClient; use App\BusProNet\Exception\ApiClientException; -use App\BusProNet\Exception\ResponseParserException; use App\BusProNet\Model\CrmAttributes; use App\BusProNet\Model\PersonalData; +use App\Security\Crypt; use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; @@ -27,6 +27,7 @@ class Authenticator extends AbstractLoginFormAuthenticator implements Authentica public function __construct( private readonly UrlGeneratorInterface $urlGenerator, private readonly ApiClient $apiClient, + private readonly Crypt $crypt, private readonly LoggerInterface $logger, ) { } @@ -46,7 +47,7 @@ class Authenticator extends AbstractLoginFormAuthenticator implements Authentica try { $response = $this->apiClient->getPersonalData($email, $password); - } catch (ApiClientException|ResponseParserException $e) { + } catch (ApiClientException $e) { throw new CustomUserMessageAuthenticationException($e->getMessage()); } @@ -60,7 +61,8 @@ class Authenticator extends AbstractLoginFormAuthenticator implements Authentica new UserBadge($email, function () use ($email, $password, $response, $request) { $crmAttributes = $this->apiClient->getCrmAttributes($email, $password); $roles = $this->collectRoles($crmAttributes); - $user = new User($email, $response->personId, $response->addressId, $password, $roles); + $encryptedPassword = $this->crypt->encrypt($password); + $user = new User($email, $response->personId, $response->addressId, $encryptedPassword, $roles); $request->getSession()->set('bpn_user', $user); diff --git a/src/BusProNet/Security/User.php b/src/BusProNet/Security/User.php index 82fe15a..0f59d51 100644 --- a/src/BusProNet/Security/User.php +++ b/src/BusProNet/Security/User.php @@ -40,7 +40,7 @@ class User implements UserInterface return ['ROLE_USER', ...$this->roles]; } - public function eraseCredentials() + public function eraseCredentials(): void { } @@ -48,4 +48,4 @@ class User implements UserInterface { return $this->email; } -} \ No newline at end of file +} diff --git a/src/BusProNet/Security/UserProvider.php b/src/BusProNet/Security/UserProvider.php index b8d1c6e..f2862f5 100644 --- a/src/BusProNet/Security/UserProvider.php +++ b/src/BusProNet/Security/UserProvider.php @@ -5,6 +5,8 @@ namespace App\BusProNet\Security; use App\BusProNet\ApiClient; use App\BusProNet\Exception\ApiClientException; use App\BusProNet\Model\PersonalData; +use App\Controller\Traits\CredentialsTrait; +use App\Security\Crypt; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Security\Core\Exception\UserNotFoundException; use Symfony\Component\Security\Core\User\UserInterface; @@ -12,14 +14,19 @@ use Symfony\Component\Security\Core\User\UserProviderInterface; class UserProvider implements UserProviderInterface { - public function __construct(private readonly ApiClient $apiClient, private readonly RequestStack $requestStack) - { + use CredentialsTrait; + + public function __construct( + private readonly ApiClient $apiClient, + private readonly RequestStack $requestStack, + private readonly Crypt $crypt, + ) { } public function refreshUser(UserInterface $user): UserInterface { - if (null !== $activeUuser = $this->requestStack->getSession()->get('bpn_user')) { - return $activeUuser; + if (null !== $activeUser = $this->requestStack->getSession()->get('bpn_user')) { + return $activeUser; } return $this->loadUserByIdentifier($user->getUserIdentifier()); @@ -37,7 +44,9 @@ class UserProvider implements UserProviderInterface } try { - $response = $this->apiClient->getPersonalData($activeUser->getEmail(), $activeUser->getPassword()); + $email = $activeUser->getEmail(); + $password = $this->crypt->decrypt($activeUser->getPassword()); + $response = $this->apiClient->getPersonalData($email, $password); } catch (ApiClientException $e) { throw new UserNotFoundException(); } @@ -48,4 +57,4 @@ class UserProvider implements UserProviderInterface return $activeUser; } -} \ No newline at end of file +} diff --git a/src/Command/GenerateKeysCommand.php b/src/Command/GenerateKeysCommand.php new file mode 100644 index 0000000..8c85df5 --- /dev/null +++ b/src/Command/GenerateKeysCommand.php @@ -0,0 +1,25 @@ +generate($this->path.'/private.key', $this->path.'/public.key'); + + return Command::SUCCESS; + } +} diff --git a/src/Controller/Booking/DownloadController.php b/src/Controller/Booking/DownloadController.php index 2c99748..9353b98 100644 --- a/src/Controller/Booking/DownloadController.php +++ b/src/Controller/Booking/DownloadController.php @@ -5,22 +5,29 @@ namespace App\Controller\Booking; use App\BusProNet\ApiClient; use App\BusProNet\Exception\ApiClientException; use App\BusProNet\Model\Notification; +use App\BusProNet\Security\User; +use App\Controller\Traits\BookingDataTrait; +use App\Controller\Traits\CredentialsTrait; +use App\Security\Crypt; use Psr\Log\LoggerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Symfony\Bundle\SecurityBundle\Security; -use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\ResponseHeaderBag; use Symfony\Component\HttpFoundation\StreamedResponse; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Security\Http\Attribute\IsGranted; +use Symfony\Contracts\Cache\CacheInterface; use function Symfony\Component\String\u; class DownloadController extends AbstractController { + use CredentialsTrait; + use BookingDataTrait; + public function __construct( private readonly ApiClient $apiClient, - private readonly Security $security, + private readonly CacheInterface $cache, + private readonly Crypt $crypt, private readonly LoggerInterface $logger, ) { } @@ -38,13 +45,12 @@ class DownloadController extends AbstractController defaults: ['fileType' => 'invoice'] )] #[IsGranted("ROLE_USER")] - public function documents(int $id, string $fileType, Request $request): Response + public function documents(int $id, string $fileType): Response { - $bpnUser = $request->getSession()->get('bpn_user'); - - if (null === $bpnUser) { - return $this->security->logout(); - } + /** @var User $user */ + $user = $this->getUser(); + $email = $user->getEmail(); + $password = $this->crypt->decrypt($user->getPassword()); $type = match ($fileType) { 'documents' => 'Dokumentdruck', @@ -52,15 +58,26 @@ class DownloadController extends AbstractController }; $this->logger->info('Initiated document download', [ - 'email' => $bpnUser->getEmail(), + 'email' => $email, 'document_type' => $fileType, 'booking_id' => $id, ]); + // Fetch booking data via API and cache result for a short ttl to check permissions + $bookingData = $this->fetchBookingData($email, $password, $id); + + if (null === $bookingData || $bookingData instanceof Notification) { + $this->addFlash('error', 'Buchungsdaten nicht (mehr) verfügbar'); + + return $this->redirectToRoute('app_bookings'); + } + + $this->denyAccessUnlessGranted('VIEW', $bookingData); + try { $file = $this ->apiClient - ->getDocuments($bpnUser->getEmail(), $bpnUser->getPassword(), $id, $type); + ->getDocuments($email, $password, $id, $type); } catch (ApiClientException $e) { $file = null; } diff --git a/src/Controller/Booking/EditController.php b/src/Controller/Booking/EditController.php index 5c2f2f0..1526cd0 100644 --- a/src/Controller/Booking/EditController.php +++ b/src/Controller/Booking/EditController.php @@ -4,12 +4,15 @@ namespace App\Controller\Booking; use App\BusProNet\ApiClient; use App\BusProNet\Exception\ApiClientException; -use App\BusProNet\Exception\ResponseParserException; use App\BusProNet\Model\Notification; +use App\BusProNet\Security\User; use App\BusProNet\XmlLoader\PickupLoader; use App\BusProNet\XmlLoader\TravelLoader; +use App\Controller\Traits\BookingDataTrait; +use App\Controller\Traits\CredentialsTrait; use App\Form\BookingType; use App\Form\Model\BookingData; +use App\Security\Crypt; use Psr\Cache\InvalidArgumentException; use Psr\Log\LoggerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; @@ -19,16 +22,19 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Security\Http\Attribute\IsGranted; use Symfony\Contracts\Cache\CacheInterface; -use Symfony\Contracts\Cache\ItemInterface; class EditController extends AbstractController { + use CredentialsTrait; + use BookingDataTrait; + public function __construct( private readonly ApiClient $apiClient, private readonly TravelLoader $travelDataLoader, private readonly PickupLoader $pickupDataLoader, private readonly CacheInterface $cache, private readonly Security $security, + private readonly Crypt $crypt, private readonly LoggerInterface $logger, ) { } @@ -37,30 +43,22 @@ class EditController extends AbstractController #[IsGranted("ROLE_USER")] public function edit(int $id, Request $request): Response { - $bpnUser = $request->getSession()->get('bpn_user'); + /** @var User $user */ + $user = $this->getUser(); + $email = $user->getEmail(); + $password = $this->crypt->decrypt($user->getPassword()); - if (null === $bpnUser) { - return $this->security->logout(); - } + // Fetch original booking data via API and cache result for a short ttl + $bookingData = $this->fetchBookingData($email, $password, $id); - // Fetch original bookingData data via API and cache result for a short ttl - $cacheKey = sprintf('bpn_booking_%d', $id); - try { - $bookingData = $this->cache->get($cacheKey, function (ItemInterface $item) use ($bpnUser, $id) { - $item->expiresAfter(300); - - return $this->apiClient->getBooking($bpnUser->getEmail(), $bpnUser->getPassword(), $id); - }); - } catch (InvalidArgumentException $e) { - $bookingData = null; - } - - if (null === $bookingData) { + if (null === $bookingData || $bookingData instanceof Notification) { $this->addFlash('error', 'Buchungsdaten nicht (mehr) verfügbar'); return $this->redirectToRoute('app_bookings'); } + $this->denyAccessUnlessGranted('EDIT', $bookingData); + // Load according travel data $travelData = $this->travelDataLoader->loadById($bookingData->travelId); @@ -104,7 +102,7 @@ class EditController extends AbstractController if ($form->isSubmitted() && $form->isValid()) { $this->logger->info('Initiated booking update', [ - 'email' => $bpnUser->getEmail(), + 'email' => $email, 'booking_id' => $id, ]); @@ -117,12 +115,13 @@ class EditController extends AbstractController $this->addFlash('info', $response->message); } $this->logger->error('Booking update not successful', [ - 'email' => $bpnUser->getEmail(), + 'email' => $email, 'booking_id' => $id, 'message' => $response->message, ]); } else { try { + $cacheKey = sprintf('bpn_booking_%d', $id); $this->cache->delete($cacheKey); } catch (InvalidArgumentException $e) { } @@ -130,7 +129,7 @@ class EditController extends AbstractController $this->addFlash('success', 'Buchung erfolgreich aktualisiert'); $this->logger->info('Booking update successful', [ - 'email' => $bpnUser->getEmail(), + 'email' => $email, 'booking_id' => $id, ]); diff --git a/src/Controller/Booking/IndexController.php b/src/Controller/Booking/IndexController.php index c7241b7..180ee6c 100644 --- a/src/Controller/Booking/IndexController.php +++ b/src/Controller/Booking/IndexController.php @@ -6,10 +6,12 @@ use App\BusProNet\ApiClient; use App\BusProNet\Exception\ApiClientException; use App\BusProNet\Model\BaseData; use App\BusProNet\Model\Notification; +use App\BusProNet\Security\User; use App\BusProNet\XmlLoader\TravelLoader; +use App\Controller\Traits\CredentialsTrait; +use App\Security\Crypt; use Psr\Log\LoggerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; @@ -17,10 +19,12 @@ use Symfony\Component\Security\Http\Attribute\IsGranted; class IndexController extends AbstractController { + use CredentialsTrait; + public function __construct( private readonly ApiClient $apiClient, private readonly TravelLoader $travelDataLoader, - private readonly Security $security, + private readonly Crypt $crypt, private readonly LoggerInterface $logger, ) { } @@ -29,14 +33,13 @@ class IndexController extends AbstractController #[IsGranted("ROLE_USER")] public function index(Request $request): Response { - $bpnUser = $request->getSession()->get('bpn_user'); - - if (null === $bpnUser) { - return $this->security->logout(); - } + /** @var User $user */ + $user = $this->getUser(); + $email = $user->getEmail(); + $password = $this->crypt->decrypt($user->getPassword()); try { - $bookings = $this->apiClient->getBookings($bpnUser->getEmail(), $bpnUser->getPassword()); + $bookings = $this->apiClient->getBookings($email, $password); } catch (ApiClientException $e) { $this->addFlash('error', 'Buchungen nicht abrufbar'); $bookings = new BaseData([]); @@ -44,6 +47,7 @@ class IndexController extends AbstractController if ($bookings instanceof Notification) { $this->logger->error('Unable to fetch bookings data', [ + 'email' => $email, 'code' => $bookings->code, 'error' => $bookings->message, ]); diff --git a/src/Controller/PersonalDataController.php b/src/Controller/PersonalDataController.php index 3c717ed..8a4366d 100644 --- a/src/Controller/PersonalDataController.php +++ b/src/Controller/PersonalDataController.php @@ -6,10 +6,12 @@ use App\BusProNet\ApiClient; use App\BusProNet\Exception\ApiClientException; use App\BusProNet\Model\Notification; use App\BusProNet\Model\PersonalData; +use App\BusProNet\Security\User; +use App\Controller\Traits\CredentialsTrait; use App\Form\PersonalDataType; +use App\Security\Crypt; use Psr\Log\LoggerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; @@ -17,9 +19,11 @@ use Symfony\Component\Security\Http\Attribute\IsGranted; class PersonalDataController extends AbstractController { + use CredentialsTrait; + public function __construct( private readonly ApiClient $apiClient, - private readonly Security $security, + private readonly Crypt $crypt, private readonly LoggerInterface $logger, ) { } @@ -28,16 +32,15 @@ class PersonalDataController extends AbstractController #[IsGranted('ROLE_USER')] public function index(Request $request): Response { - $bpnUser = $request->getSession()->get('bpn_user'); - - if (null === $bpnUser) { - return $this->security->logout(); - } + /** @var User $user */ + $user = $this->getUser(); + $email = $user->getEmail(); + $password = $this->crypt->decrypt($user->getPassword()); try { $personalData = $this ->apiClient - ->getPersonalData($bpnUser->getEmail(), $bpnUser->getPassword()); + ->getPersonalData($email, $password); } catch (ApiClientException $e) { $this->addFlash('error', 'Deine persönlichen Daten konnten nicht abgerufen werden'); $personalData = new PersonalData(); @@ -61,10 +64,10 @@ class PersonalDataController extends AbstractController if ($personalDataForm->isSubmitted() && $personalDataForm->isValid()) { try { - $this->apiClient->updatePersonalData($bpnUser->getEmail(), $bpnUser->getPassword(), $personalData); + $this->apiClient->updatePersonalData($email, $password, $personalData); $this->addFlash('success', 'Deine persönlichen Daten wurden aktualisiert'); $this->logger->info('Updated personal data', [ - 'email' => $bpnUser->getEmail(), + 'email' => $user->getEmail(), ]); } catch (ApiClientException $e) { $this->addFlash('error', $e->getMessage()); @@ -81,18 +84,17 @@ class PersonalDataController extends AbstractController #[Route('/personal-data/newsletter', name: 'app_personal_data_newsletter', methods: ['POST'])] #[IsGranted('ROLE_USER')] - public function newsletter(Request $request): Response + public function newsletter(): Response { - $bpnUser = $request->getSession()->get('bpn_user'); - - if (null === $bpnUser) { - return $this->security->logout(); - } + /** @var User $user */ + $user = $this->getUser(); + $email = $user->getEmail(); + $password = $this->crypt->decrypt($user->getPassword()); try { $personalData = $this ->apiClient - ->getPersonalData($bpnUser->getEmail(), $bpnUser->getPassword()); + ->getPersonalData($email, $password); } catch (ApiClientException $e) { $this->addFlash('error', 'Deine persönlichen Daten konnten nicht abgerufen werden'); $personalData = new PersonalData(); @@ -101,10 +103,10 @@ class PersonalDataController extends AbstractController $personalData->communication->newsletter = !$personalData->communication->newsletter; try { - $this->apiClient->updateNewsletterRegistration($bpnUser->getEmail(), $bpnUser->getPassword(), $personalData); + $this->apiClient->updateNewsletterRegistration($email, $password, $personalData); $this->addFlash('success', 'Deine Anmeldung zum Newsletter wurde aktualisiert'); $this->logger->info('Updated newsletter registration', [ - 'email' => $bpnUser->getEmail(), + 'email' => $user->getEmail(), ]); } catch (ApiClientException $e) { $this->addFlash('error', $e->getMessage()); diff --git a/src/Controller/Traits/BookingDataTrait.php b/src/Controller/Traits/BookingDataTrait.php new file mode 100644 index 0000000..2476e51 --- /dev/null +++ b/src/Controller/Traits/BookingDataTrait.php @@ -0,0 +1,28 @@ +cache->get($cacheKey, function (ItemInterface $item) use ($email, $password, $id) { + $item->expiresAfter(300); + + return $this->apiClient->getBooking($email, $password, $id); + }); + } catch (InvalidArgumentException $e) { + $bookingData = null; + } + + return $bookingData; + } +} diff --git a/src/Controller/Traits/CredentialsTrait.php b/src/Controller/Traits/CredentialsTrait.php new file mode 100644 index 0000000..e9d2458 --- /dev/null +++ b/src/Controller/Traits/CredentialsTrait.php @@ -0,0 +1,16 @@ +decrypt($bpnUser->getPassword()); + } +} diff --git a/src/Security/Crypt.php b/src/Security/Crypt.php new file mode 100644 index 0000000..19ead9a --- /dev/null +++ b/src/Security/Crypt.php @@ -0,0 +1,41 @@ +path . '/private.key'); + + return $privateKey->encrypt($message); + } + + public function decrypt(string $message): string + { + $publicKey = PublicKey::fromFile($this->path . '/public.key'); + + return $publicKey->decrypt($message); + } + + public function sign(string $message): string + { + $privateKey = PrivateKey::fromFile($this->path . '/private.key'); + + return $privateKey->sign($message); + } + + public function verify(string $message, string $signature): bool + { + $publicKey = PublicKey::fromFile($this->path . '/public.key'); + + return $publicKey->verify($message, $signature); + } +} diff --git a/src/Security/Voter/BookingVoter.php b/src/Security/Voter/BookingVoter.php index 83c55ca..99262de 100644 --- a/src/Security/Voter/BookingVoter.php +++ b/src/Security/Voter/BookingVoter.php @@ -3,7 +3,7 @@ namespace App\Security\Voter; use App\BusProNet\Model\Booking; -use Symfony\Component\HttpFoundation\RequestStack; +use App\BusProNet\Security\User; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\Voter\Voter; @@ -12,10 +12,6 @@ class BookingVoter extends Voter public const VIEW = 'VIEW'; public const EDIT = 'EDIT'; - public function __construct(private readonly RequestStack $requestStack) - { - } - protected function supports(string $attribute, mixed $subject): bool { if (false === in_array($attribute, [self::VIEW, self::EDIT])) { @@ -27,7 +23,8 @@ class BookingVoter extends Voter protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool { - $bpnUser = $this->requestStack->getSession()->get('bpn_user'); + /** @var User $bpnUser */ + $bpnUser = $token->getUser(); if (null === $bpnUser) { return false; @@ -42,4 +39,4 @@ class BookingVoter extends Voter return $booking->isEditable(); } -} \ No newline at end of file +}