From b3cf600fcb0dde8f1eb7f1f3b5dd8c02f45a11e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Glawaty?= Date: Fri, 26 Jan 2024 05:42:28 +0100 Subject: [PATCH] Fixed Azure authenticator + External auth list - fixed Azure authenticator - fixed Doctrine mapping - added the list of external authentication on the user edit page --- config/model/user/infrastructure.neon | 3 ++ config/services.neon | 1 + .../OAuth/Azure/AzureAuthenticator.php | 15 ++++-- .../User/ValueObject/AuthProviderCode.php | 4 ++ .../Mapping/App.Domain.User.User.dcm.xml | 2 +- ...indExternalAuthenticationsQueryHandler.php | 51 +++++++++++++++++++ src/ReadModel/User/ExternalAuthView.php | 17 +++++++ .../User/FindExternalAuthenticationsQuery.php | 22 ++++++++ .../ExternalAuthListControl.php | 29 +++++++++++ ...xternalAuthListControlFactoryInterface.php | 10 ++++ .../ExternalAuthListTemplate.php | 14 +++++ .../templates/externalAuthListControl.latte | 26 ++++++++++ .../Presenter/EditUserPresenter.php | 10 ++++ .../templates/EditUser.default.latte | 10 +++- ...alAuthList_ExternalAuthListControl.cs.neon | 3 ++ ...alAuthList_ExternalAuthListControl.en.neon | 3 ++ ...Module_Presenter_EditUserPresenter.cs.neon | 1 + ...Module_Presenter_EditUserPresenter.en.neon | 1 + 18 files changed, 217 insertions(+), 5 deletions(-) create mode 100644 src/Infrastructure/User/Doctrine/ReadModel/FindExternalAuthenticationsQueryHandler.php create mode 100644 src/ReadModel/User/ExternalAuthView.php create mode 100644 src/ReadModel/User/FindExternalAuthenticationsQuery.php create mode 100644 src/Web/AdminModule/UserModule/Control/ExternalAuthList/ExternalAuthListControl.php create mode 100644 src/Web/AdminModule/UserModule/Control/ExternalAuthList/ExternalAuthListControlFactoryInterface.php create mode 100644 src/Web/AdminModule/UserModule/Control/ExternalAuthList/ExternalAuthListTemplate.php create mode 100644 src/Web/AdminModule/UserModule/Control/ExternalAuthList/templates/externalAuthListControl.latte create mode 100644 translations/App_Web_AdminModule_UserModule_Control_ExternalAuthList_ExternalAuthListControl.cs.neon create mode 100644 translations/App_Web_AdminModule_UserModule_Control_ExternalAuthList_ExternalAuthListControl.en.neon diff --git a/config/model/user/infrastructure.neon b/config/model/user/infrastructure.neon index 0697f672..1c015ea6 100644 --- a/config/model/user/infrastructure.neon +++ b/config/model/user/infrastructure.neon @@ -10,6 +10,9 @@ services: - autowired: no factory: App\Infrastructure\User\Doctrine\ReadModel\FindNotificationReceiversByTypeAndProjectIdsQueryHandler + - + autowired: no + factory: App\Infrastructure\User\Doctrine\ReadModel\FindExternalAuthenticationsQueryHandler # infra: doctrine mapping nettrine.orm.xml: diff --git a/config/services.neon b/config/services.neon index 2a6bc9e9..c07337d5 100644 --- a/config/services.neon +++ b/config/services.neon @@ -77,6 +77,7 @@ services: - App\Web\AdminModule\UserModule\Control\UserForm\UserFormControlFactoryInterface - App\Web\AdminModule\ProfileModule\Control\PasswordChange\PasswordChangeControlFactoryInterface - App\Web\AdminModule\UserModule\Control\NotificationPreferences\NotificationPreferencesControlFactoryInterface + - App\Web\AdminModule\UserModule\Control\ExternalAuthList\ExternalAuthListControlFactoryInterface # Web\AdminModule\CookieModule - App\Web\AdminModule\CookieModule\Control\CategoryList\CategoryListControlFactoryInterface diff --git a/src/Bridge/SixtyEightPublishers/OAuth/Azure/AzureAuthenticator.php b/src/Bridge/SixtyEightPublishers/OAuth/Azure/AzureAuthenticator.php index 96a3b849..c6110286 100644 --- a/src/Bridge/SixtyEightPublishers/OAuth/Azure/AzureAuthenticator.php +++ b/src/Bridge/SixtyEightPublishers/OAuth/Azure/AzureAuthenticator.php @@ -4,6 +4,8 @@ namespace App\Bridge\SixtyEightPublishers\OAuth\Azure; +use App\Application\Localization\ApplicationDateTimeZone; +use App\Application\Localization\Profiles; use App\Domain\User\Command\StoreExternalAuthenticationCommand; use App\Domain\User\RolesEnum; use App\ReadModel\User\UserView; @@ -30,6 +32,7 @@ public function __construct( private readonly CommandBusInterface $commandBus, private readonly QueryBusInterface $queryBus, private readonly LoggerInterface $logger, + private readonly Profiles $profiles, ) {} public function authenticate(string $flowName, AuthorizationResult $authorizationResult): IIdentity @@ -90,7 +93,7 @@ public function authenticate(string $flowName, AuthorizationResult $authorizatio ); $identity = IdentityDecorator::newInstance()->wakeupIdentity( - identity: Identity::createSleeping($userId), + identity: Identity::createSleeping(UserId::fromString($userId)), queryBus: $this->queryBus, ); @@ -114,7 +117,7 @@ private function createUser(ResourceOwnerInterface $resourceOwner, string $flowN $userData = $resourceOwner->toArray(); try { - $this->commandBus->dispatch(CreateUserCommand::create( + $command = CreateUserCommand::create( username: $username, password: null, emailAddress: $username, @@ -122,7 +125,13 @@ private function createUser(ResourceOwnerInterface $resourceOwner, string $flowN surname: $userData['family_name'] ?? '', roles: $roles, userId: $userId, - )); + ); + + $command = $command + ->withParam('profile', $this->profiles->active()->locale()) + ->withParam('timezone', ApplicationDateTimeZone::get()->getName()); + + $this->commandBus->dispatch($command); } catch (Throwable $e) { $this->logger->error(sprintf( 'Unable to create the user with oid %s via %s. %s', diff --git a/src/Domain/User/ValueObject/AuthProviderCode.php b/src/Domain/User/ValueObject/AuthProviderCode.php index 756e746c..26e7dc29 100644 --- a/src/Domain/User/ValueObject/AuthProviderCode.php +++ b/src/Domain/User/ValueObject/AuthProviderCode.php @@ -8,4 +8,8 @@ final class AuthProviderCode extends AbstractStringValueObject { + public function __toString(): string + { + return $this->value(); + } } diff --git a/src/Infrastructure/User/Doctrine/Mapping/App.Domain.User.User.dcm.xml b/src/Infrastructure/User/Doctrine/Mapping/App.Domain.User.User.dcm.xml index 2bb92a01..12b0582c 100644 --- a/src/Infrastructure/User/Doctrine/Mapping/App.Domain.User.User.dcm.xml +++ b/src/Infrastructure/User/Doctrine/Mapping/App.Domain.User.User.dcm.xml @@ -63,7 +63,7 @@ - + diff --git a/src/Infrastructure/User/Doctrine/ReadModel/FindExternalAuthenticationsQueryHandler.php b/src/Infrastructure/User/Doctrine/ReadModel/FindExternalAuthenticationsQueryHandler.php new file mode 100644 index 00000000..4501f22d --- /dev/null +++ b/src/Infrastructure/User/Doctrine/ReadModel/FindExternalAuthenticationsQueryHandler.php @@ -0,0 +1,51 @@ + + * @throws Exception + */ + public function __invoke(FindExternalAuthenticationsQuery $query): array + { + $rows = $this->connection->createQueryBuilder() + ->select('uea.user_id, uea.provider_code, uea.created_at, uea.resource_owner_id') + ->from('user_external_auth', 'uea') + ->join('uea', '"user"', 'u', 'u.id = uea.user_id AND u.deleted_at IS NULL') + ->where('uea.user_id = :userId') + ->orderBy('uea.created_at', 'DESC') + ->setParameters([ + 'userId' => $query->userId(), + ]) + ->fetchAllAssociative(); + + $result = []; + + foreach ($rows as $row) { + $result[] = new ExternalAuthView( + userId: $row['user_id'], + providerCode: $row['provider_code'], + createdAt: new DateTimeImmutable($row['created_at'], new DateTimeZone('UTC')), + resourceOwnerId: $row['resource_owner_id'], + ); + } + + return $result; + } +} diff --git a/src/ReadModel/User/ExternalAuthView.php b/src/ReadModel/User/ExternalAuthView.php new file mode 100644 index 00000000..1904c575 --- /dev/null +++ b/src/ReadModel/User/ExternalAuthView.php @@ -0,0 +1,17 @@ + $userId, + ]); + } + + public function userId(): string + { + return $this->getParam('user_id'); + } +} diff --git a/src/Web/AdminModule/UserModule/Control/ExternalAuthList/ExternalAuthListControl.php b/src/Web/AdminModule/UserModule/Control/ExternalAuthList/ExternalAuthListControl.php new file mode 100644 index 00000000..f3b665d1 --- /dev/null +++ b/src/Web/AdminModule/UserModule/Control/ExternalAuthList/ExternalAuthListControl.php @@ -0,0 +1,29 @@ +getTemplate(); + assert($template instanceof ExternalAuthListTemplate); + + $template->externalAuths = $this->queryBus->dispatch(FindExternalAuthenticationsQuery::create( + userId: $this->userId, + )); + } +} diff --git a/src/Web/AdminModule/UserModule/Control/ExternalAuthList/ExternalAuthListControlFactoryInterface.php b/src/Web/AdminModule/UserModule/Control/ExternalAuthList/ExternalAuthListControlFactoryInterface.php new file mode 100644 index 00000000..03a3f6c8 --- /dev/null +++ b/src/Web/AdminModule/UserModule/Control/ExternalAuthList/ExternalAuthListControlFactoryInterface.php @@ -0,0 +1,10 @@ + */ + public array $externalAuths; +} diff --git a/src/Web/AdminModule/UserModule/Control/ExternalAuthList/templates/externalAuthListControl.latte b/src/Web/AdminModule/UserModule/Control/ExternalAuthList/templates/externalAuthListControl.latte new file mode 100644 index 00000000..99fc59f4 --- /dev/null +++ b/src/Web/AdminModule/UserModule/Control/ExternalAuthList/templates/externalAuthListControl.latte @@ -0,0 +1,26 @@ +{templateType App\Web\AdminModule\UserModule\Control\ExternalAuthList\ExternalAuthListTemplate} + +
+
+
+ + + + + + + + + + + + + + + + + +
{_auth_type}{_resource_owner_id}
{$externalAuth->providerCode}{$externalAuth->resourceOwnerId}
{_no_rows}
+
+
+
diff --git a/src/Web/AdminModule/UserModule/Presenter/EditUserPresenter.php b/src/Web/AdminModule/UserModule/Presenter/EditUserPresenter.php index 66635a81..5e454539 100644 --- a/src/Web/AdminModule/UserModule/Presenter/EditUserPresenter.php +++ b/src/Web/AdminModule/UserModule/Presenter/EditUserPresenter.php @@ -7,6 +7,8 @@ use App\Application\Acl\UserResource; use App\ReadModel\User\UserView; use App\Web\AdminModule\Presenter\AdminPresenter; +use App\Web\AdminModule\UserModule\Control\ExternalAuthList\ExternalAuthListControl; +use App\Web\AdminModule\UserModule\Control\ExternalAuthList\ExternalAuthListControlFactoryInterface; use App\Web\AdminModule\UserModule\Control\NotificationPreferences\Event\NotificationPreferencesProcessingFailedEvent; use App\Web\AdminModule\UserModule\Control\NotificationPreferences\Event\NotificationPreferencesUpdatedEvent; use App\Web\AdminModule\UserModule\Control\NotificationPreferences\NotificationPreferencesControl; @@ -31,6 +33,7 @@ final class EditUserPresenter extends AdminPresenter public function __construct( private readonly UserFormControlFactoryInterface $userFormControlFactory, private readonly NotificationPreferencesControlFactoryInterface $notificationPreferencesControlFactory, + private readonly ExternalAuthListControlFactoryInterface $externalAuthListControlFactory, private readonly QueryBusInterface $queryBus, ) { parent::__construct(); @@ -91,4 +94,11 @@ protected function createComponentNotificationPreferences(): NotificationPrefere return $control; } + + protected function createComponentExternalAuthList(): ExternalAuthListControl + { + return $this->externalAuthListControlFactory->create( + userId: $this->userView->id->toString(), + ); + } } diff --git a/src/Web/AdminModule/UserModule/Presenter/templates/EditUser.default.latte b/src/Web/AdminModule/UserModule/Presenter/templates/EditUser.default.latte index 4bbe03c1..e5662109 100644 --- a/src/Web/AdminModule/UserModule/Presenter/templates/EditUser.default.latte +++ b/src/Web/AdminModule/UserModule/Presenter/templates/EditUser.default.latte @@ -15,10 +15,18 @@ {control userForm} -
+

{_notification_preferences}

{control notificationPreferences}
+ +
+
+

{_external_auth_list}

+
+ + {control externalAuthList} +
diff --git a/translations/App_Web_AdminModule_UserModule_Control_ExternalAuthList_ExternalAuthListControl.cs.neon b/translations/App_Web_AdminModule_UserModule_Control_ExternalAuthList_ExternalAuthListControl.cs.neon new file mode 100644 index 00000000..d1822815 --- /dev/null +++ b/translations/App_Web_AdminModule_UserModule_Control_ExternalAuthList_ExternalAuthListControl.cs.neon @@ -0,0 +1,3 @@ +auth_type: Typ autentizace +resource_owner_id: ID uživatele +no_rows: Uživatel nepoužívá žádnou externí autentizaci. diff --git a/translations/App_Web_AdminModule_UserModule_Control_ExternalAuthList_ExternalAuthListControl.en.neon b/translations/App_Web_AdminModule_UserModule_Control_ExternalAuthList_ExternalAuthListControl.en.neon new file mode 100644 index 00000000..8e44ab44 --- /dev/null +++ b/translations/App_Web_AdminModule_UserModule_Control_ExternalAuthList_ExternalAuthListControl.en.neon @@ -0,0 +1,3 @@ +auth_type: Authentication type +resource_owner_id: User ID +no_rows: The user does not use any external authentication. diff --git a/translations/App_Web_AdminModule_UserModule_Presenter_EditUserPresenter.cs.neon b/translations/App_Web_AdminModule_UserModule_Presenter_EditUserPresenter.cs.neon index b25fceed..900e665d 100644 --- a/translations/App_Web_AdminModule_UserModule_Presenter_EditUserPresenter.cs.neon +++ b/translations/App_Web_AdminModule_UserModule_Presenter_EditUserPresenter.cs.neon @@ -1,6 +1,7 @@ page_title: Upravit uživatele heading_basic: Základní informace notification_preferences: Nastavení notifikací +external_auth_list: Externí autentizace back_to_list: Zpět na výpis uživatelů message: diff --git a/translations/App_Web_AdminModule_UserModule_Presenter_EditUserPresenter.en.neon b/translations/App_Web_AdminModule_UserModule_Presenter_EditUserPresenter.en.neon index c23efcc8..51833579 100644 --- a/translations/App_Web_AdminModule_UserModule_Presenter_EditUserPresenter.en.neon +++ b/translations/App_Web_AdminModule_UserModule_Presenter_EditUserPresenter.en.neon @@ -1,6 +1,7 @@ page_title: Edit user heading_basic: Basic information notification_preferences: Notification settings +external_auth_list: External authentication back_to_list: Back to the user list message: