diff --git a/docroot/modules/custom/acquia_id/src/Controller/OAuth2Controller.php b/docroot/modules/custom/acquia_id/src/Controller/OAuth2Controller.php index a582655ac..d014bc37e 100644 --- a/docroot/modules/custom/acquia_id/src/Controller/OAuth2Controller.php +++ b/docroot/modules/custom/acquia_id/src/Controller/OAuth2Controller.php @@ -15,8 +15,6 @@ use Drupal\acquia_id\Events\OAuth2AuthorizationEvent; use Drupal\acquia_id\OAuth2\AccessTokenRepository; use Drupal\acquia_id\OAuth2\Provider\AcquiaIdProvider; -use GuzzleHttp\Exception\RequestException; -use League\OAuth2\Client\Provider\Exception\IdentityProviderException; use League\OAuth2\Client\Token\AccessToken; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; @@ -40,6 +38,7 @@ public function __construct( private readonly EventDispatcherInterface $eventDispatcher, private readonly AccessTokenRepository $accessTokenRepository, private readonly string $idpLogoutRedirectUri, + private readonly AccountInterface $currentUser, ) { } @@ -53,6 +52,7 @@ public static function create(ContainerInterface $container): self { $container->get('event_dispatcher'), $container->get('acquia_id.oauth2.access_token_repository'), $container->getParameter('acquia_id.idp_logout_redirect_uri'), + $container->get('current_user'), ); } @@ -61,7 +61,26 @@ public static function create(ContainerInterface $container): self { * * @link https://oauth.net/2/pkce/ */ - public function __invoke(Request $request): RedirectResponse { + public function __invoke(Request $request): RedirectResponse|array { + $isCallback = $request->query->has('code') || $request->query->has('state') || $request->query->has('error'); + if (!$isCallback && !$this->currentUser->isAnonymous()) { + $token = NULL; + try { + $token = $this->accessTokenRepository->get((int) $this->currentUser->id()); + } + catch (\Exception) { + } + if ($token !== NULL) { + $destination = $request->query->get('destination', ''); + if ($destination) { + return new RedirectResponse(Url::fromUserInput($destination)->toString(), Response::HTTP_SEE_OTHER); + } + return [ + '#markup' => '
' . $this->t('You are already logged in.') . '
', + ]; + } + } + // Check if this is a subrequest being made on access denied exception. // @see \Drupal\Core\EventSubscriber\HttpExceptionSubscriberBase::onException(). if ($request->attributes->has('exception')) { @@ -135,17 +154,7 @@ public function __invoke(Request $request): RedirectResponse { * Checks access for the SSO route. */ public function access(AccountInterface $account): AccessResultInterface { - $token = NULL; - try { - $token = $this->accessTokenRepository->get((int) $account->id()); - } - catch (IdentityProviderException) { - return AccessResult::allowed(); - } - catch (RequestException) { - } - - return AccessResult::allowedIf($account->isAnonymous() || $token === NULL); + return AccessResult::allowed(); } private function accessDeniedRedirect(string $logMessage = 'Access denied'): RedirectResponse { diff --git a/docroot/modules/custom/acquia_id/tests/src/Kernel/Controller/OAuth2ControllerTest.php b/docroot/modules/custom/acquia_id/tests/src/Kernel/Controller/OAuth2ControllerTest.php index 4b3c987af..3130611f7 100644 --- a/docroot/modules/custom/acquia_id/tests/src/Kernel/Controller/OAuth2ControllerTest.php +++ b/docroot/modules/custom/acquia_id/tests/src/Kernel/Controller/OAuth2ControllerTest.php @@ -192,7 +192,7 @@ public function testSsoRouteAccessAuthenticatedWithoutTokenAllowed(): void { $this->assertTrue($result); } - public function testSsoRouteAccessAuthenticatedWithTokenDenied(): void { + public function testSsoRouteAccessAuthenticatedWithToken(): void { $access_manager = $this->container->get('access_manager'); $user = $this->setUpCurrentUser(); @@ -208,7 +208,52 @@ public function testSsoRouteAccessAuthenticatedWithTokenDenied(): void { ]); $result = $access_manager->checkNamedRoute('acquia_id.sso', [], $user); - $this->assertFalse($result); + $this->assertTrue($result); + } + + public function testAuthenticatedWithTokenShowsAlreadyLoggedIn(): void { + $user = $this->setUpCurrentUser(); + + $token = new AccessToken([ + 'access_token' => 'VALID_ACCESS_TOKEN', + 'expires' => time() + 3600, + ]); + $this->container->get('user.data') + ->set('acquia_id', $user->id(), 'acquia_id_access_token', [ + 'access_token' => $token, + 'timestamp' => time(), + ]); + + $response = $this->doRequest( + Request::create(Url::fromRoute('acquia_id.sso')->toString()), + ); + + $this->assertSame(Response::HTTP_OK, $response->getStatusCode()); + $this->assertStringContainsString('You are already logged in.', $response->getContent()); + $this->assertStringContainsString('Continue', $response->getContent()); + } + + public function testAuthenticatedWithTokenAndDestinationRedirects(): void { + $user = $this->setUpCurrentUser(); + + $token = new AccessToken([ + 'access_token' => 'VALID_ACCESS_TOKEN', + 'expires' => time() + 3600, + ]); + $this->container->get('user.data') + ->set('acquia_id', $user->id(), 'acquia_id_access_token', [ + 'access_token' => $token, + 'timestamp' => time(), + ]); + + $response = $this->doRequest( + Request::create(Url::fromRoute('acquia_id.sso', [], [ + 'query' => ['destination' => '/admin'], + ])->toString()), + ); + + $this->assertSame(Response::HTTP_SEE_OTHER, $response->getStatusCode()); + $this->assertStringContainsString('/admin', $response->headers->get('Location')); } /**