Skip to content

Commit f1b7775

Browse files
committed
delete flow session values when the code endpoint fails or succeeds
Signed-off-by: Julien Veyssier <julien-nc@posteo.net>
1 parent 8a3cb0e commit f1b7775

1 file changed

Lines changed: 29 additions & 0 deletions

File tree

lib/Controller/LoginController.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ public function code(string $state = '', string $code = '', string $scope = '',
382382
$sessionTimestamp = $this->session->get(self::TIMESTAMP . $sessionKeySuffix);
383383
if ($currentTimestamp - $sessionTimestamp > self::LOGIN_FLOW_TIMEOUT) {
384384
// the state, nonce etc... were stored too long ago, the login flow has expired
385+
$this->cleanupSessionState($sessionKeySuffix);
385386
$message = $this->l10n->t('The received state has expired.');
386387
return $this->build403TemplateResponse($message, Http::STATUS_FORBIDDEN, [], false);
387388
}
@@ -393,6 +394,7 @@ public function code(string $state = '', string $code = '', string $scope = '',
393394
'state_exists_in_session' => $this->session->exists(self::STATE . $sessionKeySuffix),
394395
]);
395396

397+
$this->cleanupSessionState($sessionKeySuffix);
396398
$message = $this->l10n->t('The received state does not match the expected value.');
397399
if ($this->isDebugModeEnabled()) {
398400
$responseData = [
@@ -414,6 +416,7 @@ public function code(string $state = '', string $code = '', string $scope = '',
414416
$providerClientSecret = $this->crypto->decrypt($provider->getClientSecret());
415417
} catch (\Exception $e) {
416418
$this->logger->error('Failed to decrypt the client secret', ['exception' => $e]);
419+
$this->cleanupSessionState($sessionKeySuffix);
417420
$message = $this->l10n->t('Failed to decrypt the OIDC provider client secret');
418421
return $this->buildErrorTemplateResponse($message, Http::STATUS_BAD_REQUEST, [], false);
419422
}
@@ -486,10 +489,12 @@ public function code(string $state = '', string $code = '', string $scope = '',
486489
$this->logger->debug('Failed to contact the OIDC provider token endpoint', ['exception' => $e]);
487490
$message = $this->l10n->t('Failed to contact the OIDC provider token endpoint');
488491
}
492+
$this->cleanupSessionState($sessionKeySuffix);
489493
return $this->build403TemplateResponse($message, Http::STATUS_FORBIDDEN, [], false);
490494
} catch (\Exception $e) {
491495
$this->logger->debug('Failed to contact the OIDC provider token endpoint', ['exception' => $e]);
492496
$message = $this->l10n->t('Failed to contact the OIDC provider token endpoint');
497+
$this->cleanupSessionState($sessionKeySuffix);
493498
return $this->build403TemplateResponse($message, Http::STATUS_FORBIDDEN, [], false);
494499
}
495500

@@ -501,12 +506,14 @@ public function code(string $state = '', string $code = '', string $scope = '',
501506
'body' => $body,
502507
]);
503508
$message = $this->l10n->t('Failed to contact the OIDC provider token endpoint');
509+
$this->cleanupSessionState($sessionKeySuffix);
504510
return $this->build403TemplateResponse($message, Http::STATUS_FORBIDDEN, [], false);
505511
}
506512

507513
if (!isset($data['id_token'])) {
508514
$this->logger->error('Missing id_token in IdP token response', ['keys' => array_keys($data)]);
509515
$message = $this->l10n->t('Failed to contact the OIDC provider token endpoint');
516+
$this->cleanupSessionState($sessionKeySuffix);
510517
return $this->build403TemplateResponse($message, Http::STATUS_FORBIDDEN, [], false);
511518
}
512519

@@ -544,13 +551,15 @@ public function code(string $state = '', string $code = '', string $scope = '',
544551

545552
if (!isset($idTokenPayload->exp) || $idTokenPayload->exp < $this->timeFactory->getTime()) {
546553
$this->logger->debug('Token expired');
554+
$this->cleanupSessionState($sessionKeySuffix);
547555
$message = $this->l10n->t('The received token is expired.');
548556
return $this->build403TemplateResponse($message, Http::STATUS_FORBIDDEN, ['reason' => 'token expired']);
549557
}
550558

551559
// Verify issuer
552560
if (!isset($idTokenPayload->iss) || $idTokenPayload->iss !== $discovery['issuer']) {
553561
$this->logger->debug('This token is issued by the wrong issuer');
562+
$this->cleanupSessionState($sessionKeySuffix);
554563
$message = $this->l10n->t('The issuer does not match the one from the discovery endpoint');
555564
return $this->build403TemplateResponse($message, Http::STATUS_FORBIDDEN, ['invalid_issuer' => $idTokenPayload->iss]);
556565
}
@@ -566,6 +575,7 @@ public function code(string $state = '', string $code = '', string $scope = '',
566575
|| (is_array($tokenAudience) && !in_array($providerClientId, $tokenAudience, true))
567576
) {
568577
$this->logger->debug('This token is not for us');
578+
$this->cleanupSessionState($sessionKeySuffix);
569579
$message = $this->l10n->t('The audience does not match ours');
570580
return $this->build403TemplateResponse($message, Http::STATUS_FORBIDDEN, ['invalid_audience' => $idTokenPayload->aud]);
571581
}
@@ -578,13 +588,15 @@ public function code(string $state = '', string $code = '', string $scope = '',
578588
// If the azp claim is present, it should be the client ID
579589
if (isset($idTokenPayload->azp) && $idTokenPayload->azp !== $provider->getClientId()) {
580590
$this->logger->debug('This token is not for us, authorized party (azp) is different than the client ID');
591+
$this->cleanupSessionState($sessionKeySuffix);
581592
$message = $this->l10n->t('The authorized party does not match ours');
582593
return $this->build403TemplateResponse($message, Http::STATUS_FORBIDDEN, ['invalid_azp' => $idTokenPayload->azp]);
583594
}
584595
}
585596

586597
if (isset($idTokenPayload->nonce) && $idTokenPayload->nonce !== $this->session->get(self::NONCE . $sessionKeySuffix)) {
587598
$this->logger->debug('Nonce does not match');
599+
$this->cleanupSessionState($sessionKeySuffix);
588600
$message = $this->l10n->t('The nonce does not match');
589601
return $this->build403TemplateResponse($message, Http::STATUS_FORBIDDEN, ['reason' => 'invalid nonce']);
590602
}
@@ -594,6 +606,7 @@ public function code(string $state = '', string $code = '', string $scope = '',
594606
$userId = $this->provisioningService->getClaimValue($idTokenPayload, $uidAttribute, $providerId);
595607

596608
if ($userId === null) {
609+
$this->cleanupSessionState($sessionKeySuffix);
597610
$message = $this->l10n->t('Failed to provision the user');
598611
return $this->build403TemplateResponse($message, Http::STATUS_BAD_REQUEST, ['reason' => 'failed to provision user']);
599612
}
@@ -605,6 +618,7 @@ public function code(string $state = '', string $code = '', string $scope = '',
605618

606619
if ($syncGroups === null || count($syncGroups) === 0) {
607620
$this->logger->debug('Prevented user from login as user is not part of a whitelisted group');
621+
$this->cleanupSessionState($sessionKeySuffix);
608622
$message = $this->l10n->t('You do not have permission to log in to this instance. If you think this is an error, please contact an administrator.');
609623
return $this->build403TemplateResponse($message, Http::STATUS_FORBIDDEN, ['reason' => 'user not in any whitelisted group']);
610624
}
@@ -630,6 +644,7 @@ public function code(string $state = '', string $code = '', string $scope = '',
630644
if (!$softAutoProvisionAllowed && $existingUser !== null && $existingUser->getBackendClassName() !== Application::APP_ID) {
631645
// if soft auto-provisioning is disabled,
632646
// we refuse login for a user that already exists in another backend
647+
$this->cleanupSessionState($sessionKeySuffix);
633648
$message = $this->l10n->t('User conflict');
634649
return $this->build403TemplateResponse($message, Http::STATUS_BAD_REQUEST, ['reason' => 'non-soft auto provision, user conflict'], false);
635650
}
@@ -647,6 +662,7 @@ public function code(string $state = '', string $code = '', string $scope = '',
647662
}
648663

649664
if ($user === null) {
665+
$this->cleanupSessionState($sessionKeySuffix);
650666
$message = $this->l10n->t('Failed to provision the user');
651667
return $this->build403TemplateResponse($message, Http::STATUS_BAD_REQUEST, ['reason' => 'failed to provision user']);
652668
}
@@ -719,6 +735,7 @@ public function code(string $state = '', string $code = '', string $scope = '',
719735
$this->logger->debug('Redirecting user');
720736

721737
$redirectUrl = $this->session->get(self::REDIRECT_AFTER_LOGIN . $sessionKeySuffix);
738+
$this->cleanupSessionState($sessionKeySuffix);
722739
if ($redirectUrl) {
723740
return $this->getRedirectResponse($redirectUrl);
724741
}
@@ -998,4 +1015,16 @@ private function toCodeChallenge(string $data): string {
9981015
$s = str_replace('/', '_', $s); // 63rd char of encoding
9991016
return $s;
10001017
}
1018+
1019+
/**
1020+
* Clean up session values for a given state suffix
1021+
*/
1022+
private function cleanupSessionState(string $sessionKeySuffix): void {
1023+
$this->session->remove(self::STATE . $sessionKeySuffix);
1024+
$this->session->remove(self::NONCE . $sessionKeySuffix);
1025+
$this->session->remove(self::LOGIN_PROVIDERID . $sessionKeySuffix);
1026+
$this->session->remove(self::REDIRECT_AFTER_LOGIN . $sessionKeySuffix);
1027+
$this->session->remove(self::CODE_VERIFIER . $sessionKeySuffix);
1028+
$this->session->remove(self::TIMESTAMP . $sessionKeySuffix);
1029+
}
10011030
}

0 commit comments

Comments
 (0)