From 40ea391bc4a73b714814e6289b2bdb0877a79266 Mon Sep 17 00:00:00 2001 From: waldhacker1 Date: Fri, 23 Jun 2023 16:41:02 +0200 Subject: [PATCH] [WIP][TASK] TYPO3 v12 compatibility --- .../BackendAuthenticationService.php | 93 ++++++++++++++++++- .../Backend/AbstractBackendController.php | 3 +- .../Backend/ManageProvidersController.php | 35 ++----- .../Backend/Registration/VerifyController.php | 6 +- ...BeUserProviderConfigurationRestriction.php | 2 +- ...FeUserProviderConfigurationRestriction.php | 2 +- .../Listener/GenerateRequestTokenListener.php | 85 +++++++++++++++++ Classes/Repository/BackendUserRepository.php | 12 +-- Classes/Repository/FrontendUserRepository.php | 30 +++--- Classes/Session/SessionManager.php | 24 ++--- ...ConfigsTableUpdateWizard20220122130120.php | 6 +- Configuration/Backend/Routes.php | 9 ++ Configuration/Icons.php | 12 +++ Configuration/Services.yaml | 5 + .../Templates/Backend/ManageProviders.html | 59 ++++++------ .../Backend/ManageProvidersController.php | 33 ++----- .../oauth2_client_test/ext_localconf.php | 2 +- ext_localconf.php | 11 +-- 18 files changed, 293 insertions(+), 136 deletions(-) create mode 100644 Classes/Events/Listener/GenerateRequestTokenListener.php create mode 100644 Configuration/Icons.php diff --git a/Classes/Authentication/BackendAuthenticationService.php b/Classes/Authentication/BackendAuthenticationService.php index 1262f38..b1c2e53 100644 --- a/Classes/Authentication/BackendAuthenticationService.php +++ b/Classes/Authentication/BackendAuthenticationService.php @@ -23,9 +23,9 @@ use Psr\Http\Message\ResponseFactoryInterface; use Psr\Http\Message\ServerRequestInterface; use TYPO3\CMS\Backend\Routing\UriBuilder; +use TYPO3\CMS\Core\Authentication\AbstractAuthenticationService; use TYPO3\CMS\Core\Http\ImmediateResponseException; use TYPO3\CMS\Core\Http\ServerRequestFactory; -use TYPO3\CMS\Core\Service\AbstractService; use TYPO3\CMS\Core\Utility\GeneralUtility; use Waldhacker\Oauth2Client\Backend\LoginProvider\Oauth2LoginProvider; use Waldhacker\Oauth2Client\Events\BackendUserLookupEvent; @@ -35,7 +35,7 @@ use Waldhacker\Oauth2Client\Service\Oauth2Service; use Waldhacker\Oauth2Client\Session\SessionManager; -class BackendAuthenticationService extends AbstractService +class BackendAuthenticationService { private array $loginData = []; private Oauth2ProviderManager $oauth2ProviderManager; @@ -47,6 +47,12 @@ class BackendAuthenticationService extends AbstractService private ?ResourceOwnerInterface $remoteUser = null; private string $action = ''; + /** + * @var array service description array + */ + public array $info = []; + + public function __construct( Oauth2ProviderManager $oauth2ProviderManager, Oauth2Service $oauth2Service, @@ -199,12 +205,15 @@ private function verify(string $providerId, string $code, string $state, ServerR private function buildCallbackUri(string $providerId): string { + $now = (string)time(); return (string)$this->uriBuilder->buildUriFromRoute('login', [ 'loginProvider' => Oauth2LoginProvider::PROVIDER_ID, 'oauth2-provider' => $providerId, // TYPO3\CMS\Core\Authentication\BackendUserAuthentication->formfield_status 'login_status' => 'login', - 'commandLI' => 'attempt' + 'commandLI' => 'attempt', + 'time' => $now, + 'hmac' => GeneralUtility::hmac($now, BackendAuthenticationService::class), ], UriBuilder::ABSOLUTE_URL); } @@ -216,4 +225,82 @@ private function getRequest(): ServerRequestInterface } return $request; } + + /** + * Initialization of the service. + * This is a stub as needed by GeneralUtility::makeInstanceService() + * + * @internal this is part of the Service API which should be avoided to be used and only used within TYPO3 internally + */ + public function init(): bool + { + return true; + } + + /** + * Resets the service. + * This is a stub as needed by GeneralUtility::makeInstanceService() + * + * @internal this is part of the Service API which should be avoided to be used and only used within TYPO3 internally + */ + public function reset() + { + // nothing to do + } + + /** + * Returns the service key of the service + * + * @return string Service key + * @internal this is part of the Service API which should be avoided to be used and only used within TYPO3 internally + */ + public function getServiceKey() + { + return $this->info['serviceKey']; + } + + /** + * Returns the title of the service + * + * @return string Service title + * @internal this is part of the Service API which should be avoided to be used and only used within TYPO3 internally + */ + public function getServiceTitle() + { + return $this->info['title']; + } + + /** + * Returns service configuration values from the $TYPO3_CONF_VARS['SVCONF'] array + * + * @param string $optionName Name of the config option + * @param mixed $defaultValue Default configuration if no special config is available + * @param bool $includeDefaultConfig If set the 'default' config will be returned if no special config for this service is available (default: TRUE) + * @return mixed Configuration value for the service + * @internal this is part of the Service API which should be avoided to be used and only used within TYPO3 internally + */ + public function getServiceOption($optionName, $defaultValue = '', $includeDefaultConfig = true) + { + $config = null; + $serviceType = $this->info['serviceType'] ?? ''; + $serviceKey = $this->info['serviceKey'] ?? ''; + $svOptions = $GLOBALS['TYPO3_CONF_VARS']['SVCONF'][$serviceType] ?? []; + if (isset($svOptions[$serviceKey][$optionName])) { + $config = $svOptions[$serviceKey][$optionName]; + } elseif ($includeDefaultConfig && isset($svOptions['default'][$optionName])) { + $config = $svOptions['default'][$optionName]; + } + if (!isset($config)) { + $config = $defaultValue; + } + return $config; + } + + /** + * @internal this is part of the Service API which should be avoided to be used and only used within TYPO3 internally + */ + public function getLastErrorArray(): array + { + return []; + } } diff --git a/Classes/Controller/Backend/AbstractBackendController.php b/Classes/Controller/Backend/AbstractBackendController.php index bb36dce..ac3b848 100644 --- a/Classes/Controller/Backend/AbstractBackendController.php +++ b/Classes/Controller/Backend/AbstractBackendController.php @@ -21,11 +21,12 @@ use TYPO3\CMS\Core\Localization\LanguageService; use TYPO3\CMS\Core\Messaging\FlashMessage; use TYPO3\CMS\Core\Messaging\FlashMessageService; +use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity; use TYPO3\CMS\Core\Utility\GeneralUtility; class AbstractBackendController { - protected function addFlashMessage(string $message, string $title = '', int $severity = FlashMessage::INFO): void + protected function addFlashMessage(string $message, string $title = '', ContextualFeedbackSeverity $severity = ContextualFeedbackSeverity::INFO): void { GeneralUtility::makeInstance(FlashMessageService::class)->getMessageQueueByIdentifier()->enqueue( GeneralUtility::makeInstance(FlashMessage::class, $message, $title, $severity, true) diff --git a/Classes/Controller/Backend/ManageProvidersController.php b/Classes/Controller/Backend/ManageProvidersController.php index 5432333..14d8e8e 100644 --- a/Classes/Controller/Backend/ManageProvidersController.php +++ b/Classes/Controller/Backend/ManageProvidersController.php @@ -24,6 +24,7 @@ use TYPO3\CMS\Backend\Routing\UriBuilder; use TYPO3\CMS\Backend\Template\Components\ButtonBar; use TYPO3\CMS\Backend\Template\ModuleTemplate; +use TYPO3\CMS\Backend\Template\ModuleTemplateFactory; use TYPO3\CMS\Core\Imaging\Icon; use TYPO3\CMS\Core\Imaging\IconFactory; use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; @@ -37,7 +38,7 @@ class ManageProvidersController extends AbstractBackendController { private Oauth2ProviderManager $oauth2ProviderManager; private BackendUserRepository $backendUserRepository; - private ModuleTemplate $moduleTemplate; + private ModuleTemplateFactory $moduleTemplateFactory; private UriBuilder $uriBuilder; private ResponseFactoryInterface $responseFactory; private IconFactory $iconFactory; @@ -45,14 +46,14 @@ class ManageProvidersController extends AbstractBackendController public function __construct( Oauth2ProviderManager $oauth2ProviderManager, BackendUserRepository $backendUserRepository, - ModuleTemplate $moduleTemplate, + ModuleTemplateFactory $moduleTemplate, UriBuilder $uriBuilder, ResponseFactoryInterface $responseFactory, IconFactory $iconFactory ) { $this->oauth2ProviderManager = $oauth2ProviderManager; $this->backendUserRepository = $backendUserRepository; - $this->moduleTemplate = $moduleTemplate; + $this->moduleTemplateFactory = $moduleTemplate; $this->uriBuilder = $uriBuilder; $this->responseFactory = $responseFactory; $this->iconFactory = $iconFactory; @@ -60,23 +61,18 @@ public function __construct( public function __invoke(ServerRequestInterface $request): ResponseInterface { - $this->addButtons($request); - - $view = $this->initializeView('ManageProviders'); - $view->assignMultiple([ + $moduleTemplate = $this->moduleTemplateFactory->create($request); + $this->addButtons($request, $moduleTemplate); + $moduleTemplate->assignMultiple([ 'providers' => $this->oauth2ProviderManager->getConfiguredBackendProviders(), 'activeProviders' => $this->backendUserRepository->getActiveProviders() ]); - $this->moduleTemplate->setContent($view->render()); - $this->moduleTemplate->getPageRenderer()->addJsFile('EXT:oauth2_client/Resources/Public/JavaScript/register.js'); - $response = $this->responseFactory->createResponse()->withHeader('Content-Type', 'text/html; charset=utf-8'); - $response->getBody()->write($this->moduleTemplate->renderContent()); - return $response; + return $moduleTemplate->renderResponse('Backend/ManageProviders'); } - private function addButtons(ServerRequestInterface $request): void + private function addButtons(ServerRequestInterface $request, ModuleTemplate $moduleTemplate): void { - $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar(); + $buttonBar = $moduleTemplate->getDocHeaderComponent()->getButtonBar(); if (($returnUrl = $this->getReturnUrl($request)) !== '') { $button = $buttonBar @@ -96,17 +92,6 @@ private function addButtons(ServerRequestInterface $request): void $buttonBar->addButton($reloadButton, ButtonBar::BUTTON_POSITION_RIGHT); } - private function initializeView(string $templateName): ViewInterface - { - /** @var StandaloneView $view */ - $view = GeneralUtility::makeInstance(StandaloneView::class); - $view->setTemplateRootPaths(['EXT:oauth2_client/Resources/Private/Templates/Backend']); - $view->setPartialRootPaths(['EXT:backend/Resources/Private/Partials']); - $view->setLayoutRootPaths(['EXT:backend/Resources/Private/Layouts']); - $view->setTemplate($templateName); - return $view; - } - private function getReturnUrl(ServerRequestInterface $request): string { $queryParams = $request->getQueryParams(); diff --git a/Classes/Controller/Backend/Registration/VerifyController.php b/Classes/Controller/Backend/Registration/VerifyController.php index 4a7ed47..3befc83 100644 --- a/Classes/Controller/Backend/Registration/VerifyController.php +++ b/Classes/Controller/Backend/Registration/VerifyController.php @@ -24,7 +24,7 @@ use Psr\Http\Message\ServerRequestInterface; use TYPO3\CMS\Backend\Routing\UriBuilder; use TYPO3\CMS\Core\Context\Context; -use TYPO3\CMS\Core\Messaging\FlashMessage; +use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity; use Waldhacker\Oauth2Client\Controller\Backend\AbstractBackendController; use Waldhacker\Oauth2Client\Repository\BackendUserRepository; use Waldhacker\Oauth2Client\Service\Oauth2ProviderManager; @@ -120,7 +120,7 @@ public function __invoke(ServerRequestInterface $request): ResponseInterface $this->addFlashMessage( $this->getLanguageService()->sL('LLL:EXT:oauth2_client/Resources/Private/Language/locallang_be.xlf:flash.providerConfigurationAdded.description'), $this->getLanguageService()->sL('LLL:EXT:oauth2_client/Resources/Private/Language/locallang_be.xlf:flash.providerConfigurationAdded.title'), - FlashMessage::OK + ContextualFeedbackSeverity::OK ); $response = $this->responseFactory @@ -136,7 +136,7 @@ private function redirectWithWarning(ServerRequestInterface $request): ResponseI $this->addFlashMessage( $this->getLanguageService()->sL('LLL:EXT:oauth2_client/Resources/Private/Language/locallang_be.xlf:flash.providerConfigurationFailed.description'), $this->getLanguageService()->sL('LLL:EXT:oauth2_client/Resources/Private/Language/locallang_be.xlf:flash.providerConfigurationFailed.title'), - FlashMessage::WARNING + ContextualFeedbackSeverity::WARNING ); $response = $this->responseFactory diff --git a/Classes/Database/Query/Restriction/Oauth2BeUserProviderConfigurationRestriction.php b/Classes/Database/Query/Restriction/Oauth2BeUserProviderConfigurationRestriction.php index dd28633..7b80a65 100644 --- a/Classes/Database/Query/Restriction/Oauth2BeUserProviderConfigurationRestriction.php +++ b/Classes/Database/Query/Restriction/Oauth2BeUserProviderConfigurationRestriction.php @@ -63,7 +63,7 @@ public function buildExpression(array $queriedTables, ExpressionBuilder $express ); } - return $expressionBuilder->andX(...$constraints); + return $expressionBuilder->and(...$constraints); } public function isEnforced(): bool diff --git a/Classes/Database/Query/Restriction/Oauth2FeUserProviderConfigurationRestriction.php b/Classes/Database/Query/Restriction/Oauth2FeUserProviderConfigurationRestriction.php index 6904cf5..c7fd8b8 100644 --- a/Classes/Database/Query/Restriction/Oauth2FeUserProviderConfigurationRestriction.php +++ b/Classes/Database/Query/Restriction/Oauth2FeUserProviderConfigurationRestriction.php @@ -71,7 +71,7 @@ public function buildExpression(array $queriedTables, ExpressionBuilder $express ); } - return $expressionBuilder->andX(...$constraints); + return $expressionBuilder->and(...$constraints); } public function isEnforced(): bool diff --git a/Classes/Events/Listener/GenerateRequestTokenListener.php b/Classes/Events/Listener/GenerateRequestTokenListener.php new file mode 100644 index 0000000..05bbb1f --- /dev/null +++ b/Classes/Events/Listener/GenerateRequestTokenListener.php @@ -0,0 +1,85 @@ + get time from token from cookie + // wenn request within 5 sec => generate and set token + + // $requestToken = RequestToken::create('core/user-auth/be'); + // $event->setRequestToken($requestToken); + + /* + $request = $event->getRequest(); + + $getParameters = $request->getQueryParams(); + $postParameters = is_array($request->getParsedBody()) ? $request->getParsedBody() : []; + + $loginProvider = $getParameters['loginProvider'] ?? null; + if ($loginProvider !== Oauth2LoginProvider::PROVIDER_ID) { + return; + } + + $code = (string)($getParameters['code'] ?? ''); + $state = (string)($getParameters['state'] ?? ''); + $providerIdFromPost = (string)($postParameters['oauth2-provider'] ?? ''); + $providerIdFromGet = (string)($getParameters['oauth2-provider'] ?? ''); + + $action = !empty($providerIdFromPost) && empty($code) && empty($state) + ? 'authorize' + : (!empty($providerIdFromGet) && !empty($code) && !empty($state) ? 'verify' : 'invalid'); + + if ($action !== 'verify') { + return; + } + + $requestToken = $event->getRequestToken(); + + + + if (!($requestToken instanceof RequestToken)) { + $event->setRequestToken(null); + return; + } + + // check time of request within 5 sec + $now = $this->context->getAspect('date')->getDateTime(); + $interval = new \DateInterval(sprintf('PT%dS', 5)); + + $moreThan5Seconds = $now > $requestToken->time->add($interval); + if ($moreThan5Seconds) { + $event->setRequestToken(null); + return; + } + */ + } +} diff --git a/Classes/Repository/BackendUserRepository.php b/Classes/Repository/BackendUserRepository.php index ae7cceb..ffaa97a 100644 --- a/Classes/Repository/BackendUserRepository.php +++ b/Classes/Repository/BackendUserRepository.php @@ -57,14 +57,14 @@ public function getUserByIdentity(string $provider, string $identifier): ?array ->from(self::OAUTH2_BE_CONFIG_TABLE, 'config') ->join('config', 'be_users', 'be_users', 'config.' . $userWithEditRightsColumn . '=be_users.uid') ->where( - $qb->expr()->andX( + $qb->expr()->and( $qb->expr()->eq('identifier', $qb->createNamedParameter($identifier, \PDO::PARAM_STR)), $qb->expr()->eq('provider', $qb->createNamedParameter($provider, \PDO::PARAM_STR)), $qb->expr()->neq('identifier', $qb->createNamedParameter(DataHandlerHook::INVALID_TOKEN, \PDO::PARAM_STR)), $qb->expr()->neq('provider', $qb->createNamedParameter(DataHandlerHook::INVALID_TOKEN, \PDO::PARAM_STR)) ) ) - ->execute(); + ->executeQuery(); $result = $result->fetchAllAssociative(); @@ -122,13 +122,13 @@ public function getActiveProviders(): array ->from(self::OAUTH2_BE_CONFIG_TABLE, 'config') ->join('config', 'be_users', 'be_users', 'config.' . $userWithEditRightsColumn . '=be_users.uid') ->where( - $qb->expr()->andX( + $qb->expr()->and( $qb->expr()->eq('be_users.uid', $qb->createNamedParameter($userid, \PDO::PARAM_INT)), $qb->expr()->neq('config.identifier', $qb->createNamedParameter(DataHandlerHook::INVALID_TOKEN, \PDO::PARAM_STR)), $qb->expr()->neq('config.provider', $qb->createNamedParameter(DataHandlerHook::INVALID_TOKEN, \PDO::PARAM_STR)) ) ) - ->execute(); + ->executeQuery(); $result = $result->fetchAllAssociative(); @@ -146,7 +146,7 @@ private function getConfigurationsByIdentity(string $provider, string $identifie $result = $qb->select('*') ->from(self::OAUTH2_BE_CONFIG_TABLE) ->where( - $qb->expr()->andX( + $qb->expr()->and( $qb->expr()->eq('identifier', $qb->createNamedParameter($identifier, \PDO::PARAM_STR)), $qb->expr()->eq('provider', $qb->createNamedParameter($provider, \PDO::PARAM_STR)), $qb->expr()->neq('identifier', $qb->createNamedParameter(DataHandlerHook::INVALID_TOKEN, \PDO::PARAM_STR)), @@ -154,7 +154,7 @@ private function getConfigurationsByIdentity(string $provider, string $identifie $qb->expr()->eq($userWithEditRightsColumn, $qb->createNamedParameter($userid, \PDO::PARAM_INT)) ) ) - ->execute(); + ->executeQuery(); $result = $result->fetchAllAssociative(); diff --git a/Classes/Repository/FrontendUserRepository.php b/Classes/Repository/FrontendUserRepository.php index b6f664f..aea4b6b 100644 --- a/Classes/Repository/FrontendUserRepository.php +++ b/Classes/Repository/FrontendUserRepository.php @@ -53,7 +53,7 @@ public function getUserByIdentity(string $provider, string $identifier, int $sto ->from(self::OAUTH2_FE_CONFIG_TABLE, 'config') ->join('config', 'fe_users', 'fe_users', 'config.' . $userWithEditRightsColumn . '=fe_users.uid') ->where( - $qb->expr()->andX( + $qb->expr()->and( $qb->expr()->eq('identifier', $qb->createNamedParameter($identifier, \PDO::PARAM_STR)), $qb->expr()->eq('provider', $qb->createNamedParameter($provider, \PDO::PARAM_STR)), $qb->expr()->neq('identifier', $qb->createNamedParameter(DataHandlerHook::INVALID_TOKEN, \PDO::PARAM_STR)), @@ -61,7 +61,7 @@ public function getUserByIdentity(string $provider, string $identifier, int $sto $qb->expr()->eq('fe_users.pid', $qb->createNamedParameter($storagePid, \PDO::PARAM_INT)) ) ) - ->execute(); + ->executeQuery(); $result = $result->fetchAllAssociative(); @@ -88,12 +88,12 @@ public function persistIdentityForUser(string $provider, string $identifier): vo $qb = $this->connectionPool->getQueryBuilderForTable(self::OAUTH2_FE_CONFIG_TABLE); $qb->delete(self::OAUTH2_FE_CONFIG_TABLE) ->where( - $qb->expr()->andX( + $qb->expr()->and( $qb->expr()->eq($userWithEditRightsColumn, $qb->createNamedParameter($userid, \PDO::PARAM_INT)), $qb->expr()->in('uid', $qb->createNamedParameter($activeConfigurationUids, Connection::PARAM_INT_ARRAY)) ) ) - ->execute(); + ->executeStatement(); } $qb = $this->connectionPool->getQueryBuilderForTable(self::OAUTH2_FE_CONFIG_TABLE); @@ -105,18 +105,18 @@ public function persistIdentityForUser(string $provider, string $identifier): vo ->setValue('parentid', $userid) ->setValue('provider', $provider) ->setValue('identifier', $identifier) - ->execute(); + ->executeStatement(); $activeProviders = $this->getActiveProviders(); $qb = $this->connectionPool->getQueryBuilderForTable('fe_users'); $qb->update('fe_users') ->set('tx_oauth2_client_configs', count($activeProviders)) ->where( - $qb->expr()->andX( + $qb->expr()->and( $qb->expr()->eq('uid', $qb->createNamedParameter($userid, \PDO::PARAM_INT)) ) ) - ->execute(); + ->executeQuery(); } public function getActiveProviders(): array @@ -129,13 +129,13 @@ public function getActiveProviders(): array ->from(self::OAUTH2_FE_CONFIG_TABLE, 'config') ->join('config', 'fe_users', 'fe_users', 'config.' . $userWithEditRightsColumn . '=fe_users.uid') ->where( - $qb->expr()->andX( + $qb->expr()->and( $qb->expr()->eq('fe_users.uid', $qb->createNamedParameter($userid, \PDO::PARAM_INT)), $qb->expr()->neq('config.identifier', $qb->createNamedParameter(DataHandlerHook::INVALID_TOKEN, \PDO::PARAM_STR)), $qb->expr()->neq('config.provider', $qb->createNamedParameter(DataHandlerHook::INVALID_TOKEN, \PDO::PARAM_STR)) ) ) - ->execute(); + ->executeQuery(); $result = $result->fetchAllAssociative(); @@ -156,22 +156,22 @@ public function deactivateProviderByUid(int $providerUid): void $qb = $this->connectionPool->getQueryBuilderForTable(self::OAUTH2_FE_CONFIG_TABLE); $qb->delete(self::OAUTH2_FE_CONFIG_TABLE) ->where( - $qb->expr()->andX( + $qb->expr()->and( $qb->expr()->eq($userWithEditRightsColumn, $qb->createNamedParameter($userid, \PDO::PARAM_INT)), $qb->expr()->eq('uid', $qb->createNamedParameter($providerUid, \PDO::PARAM_INT)) ) ) - ->execute(); + ->executeStatement(); $qb = $this->connectionPool->getQueryBuilderForTable('fe_users'); $qb->update('fe_users') ->set('tx_oauth2_client_configs', count($activeProviders) - 1) ->where( - $qb->expr()->andX( + $qb->expr()->and( $qb->expr()->eq('uid', $qb->createNamedParameter($userid, \PDO::PARAM_INT)) ) ) - ->execute(); + ->executeStatement(); } private function getConfigurationsByIdentity(string $provider, string $identifier): array @@ -184,7 +184,7 @@ private function getConfigurationsByIdentity(string $provider, string $identifie $result = $qb->select('*') ->from(self::OAUTH2_FE_CONFIG_TABLE) ->where( - $qb->expr()->andX( + $qb->expr()->and( $qb->expr()->eq('identifier', $qb->createNamedParameter($identifier, \PDO::PARAM_STR)), $qb->expr()->eq('provider', $qb->createNamedParameter($provider, \PDO::PARAM_STR)), $qb->expr()->neq('identifier', $qb->createNamedParameter(DataHandlerHook::INVALID_TOKEN, \PDO::PARAM_STR)), @@ -192,7 +192,7 @@ private function getConfigurationsByIdentity(string $provider, string $identifie $qb->expr()->eq($userWithEditRightsColumn, $qb->createNamedParameter($userid, \PDO::PARAM_INT)) ) ) - ->execute(); + ->executeQuery(); $result = $result->fetchAllAssociative(); diff --git a/Classes/Session/SessionManager.php b/Classes/Session/SessionManager.php index bef3224..fe8ba77 100644 --- a/Classes/Session/SessionManager.php +++ b/Classes/Session/SessionManager.php @@ -25,6 +25,7 @@ use TYPO3\CMS\Core\Http\ApplicationType; use TYPO3\CMS\Core\Http\CookieHeaderTrait; use TYPO3\CMS\Core\Http\ServerRequestFactory; +use TYPO3\CMS\Core\Security\JwtTrait; use TYPO3\CMS\Core\Session\UserSession; use TYPO3\CMS\Core\Session\UserSessionManager; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -36,6 +37,7 @@ class SessionManager { use CookieHeaderTrait; + use JwtTrait; public const SESSION_NAME_STATE = 'oauth2-state'; public const SESSION_NAME_ORIGINAL_REQUEST = 'oauth2-original-registration-request-data'; @@ -94,20 +96,6 @@ public function appendOAuth2CookieToResponse(ResponseInterface $response, Server return $response->withAddedHeader('Set-Cookie', (string)$this->buildOAuth2Cookie($request)); } - public function appendOAuth2CookieToExtbaseResponse(ServerRequestInterface $request = null): void - { - // @see \TYPO3\CMS\Extbase\Mvc\Response::sendHeaders() - // extbase replaces all headers instead of appending them, - // which would be necessary for multi value headers like "set-cookie". - // The only way to send cookies without extbase eating them (in TYPO3 10) - // is to send them via the native php function. - if (headers_sent()) { - return; - } - - header('Set-Cookie: ' . (string)$this->buildOAuth2Cookie($request), false); - } - public function appendRemoveOAuth2CookieToResponse(ResponseInterface $response, ServerRequestInterface $request = null): ResponseInterface { $request = $this->getRequest($request); @@ -196,6 +184,14 @@ private function buildOAuth2Cookie(ServerRequestInterface $request = null): Cook $httpOnly = true; $raw = false; + $sessionId = self::encodeHashSignedJwt( + [ + 'identifier' => $sessionId, + 'time' => (new \DateTimeImmutable())->format(\DateTimeImmutable::RFC3339), + ], + self::createSigningKeyFromEncryptionKey(UserSession::class) + ); + return new Cookie( $cookieName, $sessionId, diff --git a/Classes/Updates/RenameClientConfigsTableUpdateWizard20220122130120.php b/Classes/Updates/RenameClientConfigsTableUpdateWizard20220122130120.php index 8ad3139..754272b 100644 --- a/Classes/Updates/RenameClientConfigsTableUpdateWizard20220122130120.php +++ b/Classes/Updates/RenameClientConfigsTableUpdateWizard20220122130120.php @@ -102,11 +102,11 @@ private function findAllFromLegacyTable(): \Generator ->select('uid', 'tstamp', 'crdate', 'cruser_id', 'parentid', 'provider', 'identifier') ->from(self::OAUTH2_LEGACY_CONFIG_TABLE) ->where( - $qb->expr()->andX( + $qb->expr()->and( $qb->expr()->eq('deleted', $qb->createNamedParameter(0, \PDO::PARAM_INT)) ) ) - ->execute(); + ->executeQuery(); while ($row = $result->fetchAssociative()) { if (is_array($row)) { @@ -129,6 +129,6 @@ private function tableIsEmpty(string $tableName): bool { $qb = $this->connectionPool->getQueryBuilderForTable($tableName); $qb->getRestrictions()->removeByType(Oauth2BeUserProviderConfigurationRestriction::class); - return (int)$qb->count('*')->from($tableName)->execute()->fetchOne() === 0; + return (int)$qb->count('*')->from($tableName)->executeQuery()->fetchOne() === 0; } } diff --git a/Configuration/Backend/Routes.php b/Configuration/Backend/Routes.php index 5a5c99b..14141a3 100644 --- a/Configuration/Backend/Routes.php +++ b/Configuration/Backend/Routes.php @@ -4,6 +4,15 @@ 'oauth2_registration_authorize' => [ 'path' => '/oauth2/callback/handle', 'access' => 'public', + 'redirect' => [ + 'enable' => true, + 'parameters' => [ + 'oauth2-provider' => true, + 'action' => true, + 'code' => true, + 'state' => true + ] + ], 'target' => \Waldhacker\Oauth2Client\Controller\Backend\Registration\AuthorizeController::class . '::handleRequest', ], 'oauth2_registration_verify' => [ diff --git a/Configuration/Icons.php b/Configuration/Icons.php new file mode 100644 index 0000000..c153d90 --- /dev/null +++ b/Configuration/Icons.php @@ -0,0 +1,12 @@ + [ + 'provider' => SvgIconProvider::class, + 'source' => 'EXT:oauth2_client/Resources/Public/Icons/oauth2_client_plugin_manage_providers.svg', + ], +]; diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml index cc8da23..65834a8 100644 --- a/Configuration/Services.yaml +++ b/Configuration/Services.yaml @@ -40,6 +40,11 @@ services: identifier: 'oauth2_client' event: TYPO3\CMS\FrontendLogin\Event\ModifyLoginFormViewEvent + Waldhacker\Oauth2Client\Events\Listener\GenerateRequestTokenListener: + tags: + - name: event.listener + identifier: 'oauth2_client_req_token' + Waldhacker\Oauth2Client\Service\Oauth2ProviderManager: public: true diff --git a/Resources/Private/Templates/Backend/ManageProviders.html b/Resources/Private/Templates/Backend/ManageProviders.html index a3feb3b..96980a1 100644 --- a/Resources/Private/Templates/Backend/ManageProviders.html +++ b/Resources/Private/Templates/Backend/ManageProviders.html @@ -3,34 +3,41 @@ xmlns:core="http://typo3.org/ns/TYPO3/CMS/Core/ViewHelpers" xmlns:be="http://typo3.org/ns/TYPO3/CMS/Backend/ViewHelpers" data-namespace-typo3-fluid="true"> -

- -

+ + + +

+ +

- - -
- - - -
+ + +
+ + + +
+ +
+ + + +
+
+ + + +
+
-
- - - -
- - - - - diff --git a/build/Tests/Extensions/oauth2_client_test/Classes/Controller/Backend/ManageProvidersController.php b/build/Tests/Extensions/oauth2_client_test/Classes/Controller/Backend/ManageProvidersController.php index 582b9ba..0db998b 100644 --- a/build/Tests/Extensions/oauth2_client_test/Classes/Controller/Backend/ManageProvidersController.php +++ b/build/Tests/Extensions/oauth2_client_test/Classes/Controller/Backend/ManageProvidersController.php @@ -18,44 +18,23 @@ namespace Waldhacker\Oauth2ClientTest\Controller\Backend; -use Psr\Http\Message\ResponseFactoryInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use TYPO3\CMS\Backend\Template\ModuleTemplate; -use TYPO3\CMS\Core\Utility\GeneralUtility; -use TYPO3\CMS\Extbase\Mvc\View\ViewInterface; -use TYPO3\CMS\Fluid\View\StandaloneView; +use TYPO3\CMS\Backend\Template\ModuleTemplateFactory; class ManageProvidersController { - private ModuleTemplate $moduleTemplate; - private ResponseFactoryInterface $responseFactory; + private ModuleTemplateFactory $moduleTemplateFactory; public function __construct( - ModuleTemplate $moduleTemplate, - ResponseFactoryInterface $responseFactory + ModuleTemplateFactory $moduleTemplateFactory ) { - $this->moduleTemplate = $moduleTemplate; - $this->responseFactory = $responseFactory; + $this->moduleTemplateFactory = $moduleTemplateFactory; } public function __invoke(ServerRequestInterface $request): ResponseInterface { - $view = $this->initializeView('ManageProviders'); - $this->moduleTemplate->setContent($view->render()); - $response = $this->responseFactory->createResponse()->withHeader('Content-Type', 'text/html; charset=utf-8'); - $response->getBody()->write($this->moduleTemplate->renderContent()); - return $response; - } - - private function initializeView(string $templateName): ViewInterface - { - /** @var StandaloneView $view */ - $view = GeneralUtility::makeInstance(StandaloneView::class); - $view->setTemplateRootPaths(['EXT:oauth2_client_test/Resources/Private/Templates/Backend']); - $view->setPartialRootPaths(['EXT:backend/Resources/Private/Partials']); - $view->setLayoutRootPaths(['EXT:backend/Resources/Private/Layouts']); - $view->setTemplate($templateName); - return $view; + $moduleTemplate = $this->moduleTemplateFactory->create($request); + return $moduleTemplate->renderResponse('ManageProviders'); } } diff --git a/build/Tests/Extensions/oauth2_client_test/ext_localconf.php b/build/Tests/Extensions/oauth2_client_test/ext_localconf.php index 3e1b32c..e86e682 100644 --- a/build/Tests/Extensions/oauth2_client_test/ext_localconf.php +++ b/build/Tests/Extensions/oauth2_client_test/ext_localconf.php @@ -13,7 +13,7 @@ $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['backend']['loginProviders'][\Waldhacker\Oauth2ClientTest\Backend\LoginProvider\Oauth2LoginProvider::PROVIDER_ID] = [ 'provider' => \Waldhacker\Oauth2ClientTest\Backend\LoginProvider\Oauth2LoginProvider::class, 'sorting' => 26, - 'icon-class' => 'fa-key', + 'iconIdentifier' => 'actions-key', 'label' => 'LLL:EXT:oauth2_client_test/Resources/Private/Language/locallang_be.xlf:login.link', ]; diff --git a/ext_localconf.php b/ext_localconf.php index b92ab0f..eca42c4 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -44,19 +44,10 @@ [\Waldhacker\Oauth2Client\Controller\Frontend\ManageProvidersController::class => 'list,deactivate'] ); - $iconRegistry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Imaging\IconRegistry::class); - $iconRegistry->registerIcon( - 'oauth2_client_plugin_manage_providers', - \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class, - [ - 'source' => 'EXT:oauth2_client/Resources/Public/Icons/oauth2_client_plugin_manage_providers.svg' - ] - ); - $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['backend']['loginProviders'][\Waldhacker\Oauth2Client\Backend\LoginProvider\Oauth2LoginProvider::PROVIDER_ID] = [ 'provider' => \Waldhacker\Oauth2Client\Backend\LoginProvider\Oauth2LoginProvider::class, 'sorting' => 25, - 'icon-class' => 'fa-key', + 'iconIdentifier' => 'actions-key', 'label' => 'LLL:EXT:oauth2_client/Resources/Private/Language/locallang_be.xlf:login.link', ];