@@ -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