From 42f17db542f9f1b32b0e1157588394e298245a17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Fri, 12 Dec 2025 19:57:34 +0100 Subject: [PATCH] feat: extended oauth2 user info and refactored authenticator --- migrations/Version20251212162836.php | 31 +++++++++++++++++++ src/BusProNet/Model/CrmAttributes.php | 6 +--- src/BusProNet/Model/PersonalData.php | 5 ++- .../XmlParser/CrmAttributesResponseParser.php | 25 ++++++++++----- src/Controller/Api/UserinfoController.php | 3 ++ src/Entity/User.php | 15 +++++++++ src/Security/BpnAuthenticator.php | 30 +++--------------- 7 files changed, 75 insertions(+), 40 deletions(-) create mode 100644 migrations/Version20251212162836.php diff --git a/migrations/Version20251212162836.php b/migrations/Version20251212162836.php new file mode 100644 index 0000000..a8f6bf3 --- /dev/null +++ b/migrations/Version20251212162836.php @@ -0,0 +1,31 @@ +addSql('ALTER TABLE user ADD hotel_codes JSON NOT NULL COMMENT \'(DC2Type:json)\''); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE user DROP hotel_codes'); + } +} diff --git a/src/BusProNet/Model/CrmAttributes.php b/src/BusProNet/Model/CrmAttributes.php index 4233bd1..a03b5b2 100644 --- a/src/BusProNet/Model/CrmAttributes.php +++ b/src/BusProNet/Model/CrmAttributes.php @@ -14,10 +14,6 @@ class CrmAttributes { public ?array $selectionGroups = null; public ?array $crmActions = null; - public bool $admin = false; - public bool $manager = false; - public bool $houseManager = false; - public bool $teamer = false; - public ?string $hotelCode = null; + public array $hotelCodes = []; public array $roles = []; } diff --git a/src/BusProNet/Model/PersonalData.php b/src/BusProNet/Model/PersonalData.php index d811f3b..df0b06b 100644 --- a/src/BusProNet/Model/PersonalData.php +++ b/src/BusProNet/Model/PersonalData.php @@ -50,6 +50,7 @@ class PersonalData public Communication $communication; public array $roles = []; + public array $hotelCodes = []; public function __construct() { @@ -135,12 +136,13 @@ class PersonalData 'title' => $this->title, 'salutation' => $this->salutation, 'gender' => $this->gender, + 'date_of_birth' => $this->dateOfBirth?->format('Y-m-d'), 'nationality' => $this->nationality, 'address' => [ 'street' => $this->address->street, 'postcode' => $this->address->postCode, 'city' => $this->address->city, - 'disctrict' => $this->address->district, + 'district' => $this->address->district, 'country' => $this->address->country, ], 'communication' => [ @@ -149,6 +151,7 @@ class PersonalData 'phone' => $this->communication->phone, 'newsletter' => $this->communication->newsletter, ], + 'hotel_codes' => $this->hotelCodes, 'height' => $this->height, 'weight' => $this->weight, 'shoe_size' => $this->shoeSize, diff --git a/src/BusProNet/XmlParser/CrmAttributesResponseParser.php b/src/BusProNet/XmlParser/CrmAttributesResponseParser.php index 4b269dd..9930137 100644 --- a/src/BusProNet/XmlParser/CrmAttributesResponseParser.php +++ b/src/BusProNet/XmlParser/CrmAttributesResponseParser.php @@ -16,13 +16,14 @@ class CrmAttributesResponseParser private const BPN_CRM_ID_ADMIN = 1292; private const BPN_CRM_ID_MANAGER = 1293; private const BPN_CRM_ID_TEAMER = 1070; + private const BPN_DEFAULT_HOTEL_CODE = 'SSL'; public function parse(Crawler $result): CrmAttributes { $groups = []; $actions = []; $roles = []; - $hotelCode = null; + $hotelCodes = []; $result ->filterXPath('//selektionsmerkmale/selektionsgruppe') @@ -35,7 +36,7 @@ class CrmAttributesResponseParser $node ->filterXPath('//selektion') - ->each(function (Crawler $node) use (&$attributes, &$roles, &$hotelCode) { + ->each(function (Crawler $node) use (&$attributes, &$roles, &$hotelCodes) { $attribute = new CrmSelection(); $attribute->id = (int) $node->attr('id'); $attribute->label = $node->attr('bezeichnung'); @@ -44,10 +45,11 @@ class CrmAttributesResponseParser if (1 === preg_match('/^Hausleitung ([A-Z0-9]+)$/', $attribute->label, $matches) && true === $attribute->selected) { $roles[] = 'ROLE_HOUSE_MANAGER'; - $hotelCode = $matches[1]; + $hotelCodes[] = $matches[1]; } if (static::BPN_CRM_ID_ADMIN === $attribute->id && true === $attribute->selected) { $roles[] = 'ROLE_ADMIN'; + $roles[] = 'ROLE_HOUSE_MANAGER'; } if (static::BPN_CRM_ID_MANAGER === $attribute->id && true === $attribute->selected) { $roles[] = 'ROLE_MANAGER'; @@ -65,6 +67,13 @@ class CrmAttributesResponseParser }) ; + $roles = array_unique($roles); + + // Assign default role if none could be resolved + if (0 === count($roles)) { + $roles = ['ROLE_CUSTOMER']; + } + $result ->filterXPath('//crmaktionen/crmaktion') ->each(function (Crawler $node) use (&$actions) { @@ -80,15 +89,15 @@ class CrmAttributesResponseParser }) ; + if (true === in_array('ROLE_ADMIN', $roles, true)) { + $hotelCodes[] = static::BPN_DEFAULT_HOTEL_CODE; + } + $response = new CrmAttributes(); $response->selectionGroups = $groups; $response->crmActions = $actions; $response->roles = $roles; - $response->admin = in_array('ROLE_ADMIN', $roles); - $response->manager = in_array('ROLE_MANAGER', $roles); - $response->houseManager = in_array('ROLE_HOUSE_MANAGER', $roles); - $response->teamer = in_array('ROLE_TEAMER', $roles); - $response->hotelCode = $hotelCode; + $response->hotelCodes = $hotelCodes; return $response; } diff --git a/src/Controller/Api/UserinfoController.php b/src/Controller/Api/UserinfoController.php index 2e0f89c..9e2b395 100644 --- a/src/Controller/Api/UserinfoController.php +++ b/src/Controller/Api/UserinfoController.php @@ -54,6 +54,9 @@ class UserinfoController extends AbstractController // Patch current user's roles $data->roles = $user->getRoles(); + // Patch current user's hotel codes + $data->hotelCodes = $user->getHotelCodes(); + // extract userdata for resulting claims $userData = $this->getClaims($data, $scopes); diff --git a/src/Entity/User.php b/src/Entity/User.php index 7b8793e..c2fc179 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -29,6 +29,9 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface #[ORM\Column(type: 'json')] private array $roles = []; + #[ORM\Column(type: 'json')] + private array $hotelCodes = []; + #[ORM\Column(type: 'datetime_immutable', nullable: true)] private ?\DateTimeImmutable $lastLoginAt = null; @@ -102,6 +105,18 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface return $this; } + public function getHotelCodes(): array + { + return $this->hotelCodes; + } + + public function setHotelCodes(array $hotelCodes): static + { + $this->hotelCodes = $hotelCodes; + + return $this; + } + public function getLastLoginAt(): ?\DateTimeImmutable { return $this->lastLoginAt; diff --git a/src/Security/BpnAuthenticator.php b/src/Security/BpnAuthenticator.php index b90b188..3c28f51 100644 --- a/src/Security/BpnAuthenticator.php +++ b/src/Security/BpnAuthenticator.php @@ -4,7 +4,6 @@ namespace App\Security; use App\BusProNet\ApiClient; use App\BusProNet\Exception\ApiClientException; -use App\BusProNet\Model\CrmAttributes; use App\BusProNet\Model\PersonalData; use App\Entity\User; use Doctrine\ORM\EntityManagerInterface; @@ -79,7 +78,9 @@ class BpnAuthenticator extends AbstractLoginFormAuthenticator implements Authent throw new CustomUserMessageAuthenticationException($e->getMessage()); } - $roles = $this->collectRoles($crmAttributes); + $roles = $crmAttributes->roles; + $hotelCodes = $crmAttributes->hotelCodes; + $encryptedPassword = $this->crypt->encrypt($password); $userRepository = $this->entityManager->getRepository(User::class); @@ -94,6 +95,7 @@ class BpnAuthenticator extends AbstractLoginFormAuthenticator implements Authent ->setPersonId($personId) ->setAddressId($addressId) ->setRoles($roles) + ->setHotelCodes($hotelCodes) ->setLastLoginAt(new \DateTimeImmutable()) ; @@ -114,28 +116,4 @@ class BpnAuthenticator extends AbstractLoginFormAuthenticator implements Authent return new RedirectResponse($this->urlGenerator->generate('app_account')); } - - private function collectRoles(CrmAttributes $crmAttributes): array - { - // All users inherit the default role 'customer' - $roles = [ - 'ROLE_CUSTOMER', - ]; - - // Get user's base role from CRM attributes - if ($crmAttributes->admin) { - $roles[] = 'ROLE_ADMIN'; - } elseif ($crmAttributes->manager) { - $roles[] = 'ROLE_MANAGER'; - } elseif ($crmAttributes->houseManager) { - $roles[] = 'ROLE_HOUSE_MANAGER'; - } - - // All users can have role 'teamer' additionally - if ($crmAttributes->teamer) { - $roles[] = 'ROLE_TEAMER'; - } - - return $roles; - } }