Skip to content

Commit e579ebc

Browse files
committed
Merge #17 Fix backchannel logout for Telekom and keep backward compatibility V31
2 parents 850ebd8 + 90207a1 commit e579ebc

File tree

1 file changed

+81
-10
lines changed

1 file changed

+81
-10
lines changed

lib/Controller/LoginController.php

Lines changed: 81 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,26 @@ public function login(int $providerId, ?string $redirectUrl = null) {
172172
return $this->buildErrorTemplateResponse($message, Http::STATUS_NOT_FOUND, ['reason' => 'provider unreachable']);
173173
}
174174

175-
$state = $this->random->generate(32, ISecureRandom::CHAR_DIGITS . ISecureRandom::CHAR_UPPER);
176-
$this->session->set(self::STATE, $state);
177-
$this->session->set(self::REDIRECT_AFTER_LOGIN, $redirectUrl);
175+
// $state = $this->random->generate(32, ISecureRandom::CHAR_DIGITS . ISecureRandom::CHAR_UPPER);
176+
// $this->session->set(self::STATE, $state);
177+
// $this->session->set(self::REDIRECT_AFTER_LOGIN, $redirectUrl);
178178

179-
$nonce = $this->random->generate(32, ISecureRandom::CHAR_DIGITS . ISecureRandom::CHAR_UPPER);
180-
$this->session->set(self::NONCE, $nonce);
179+
// $nonce = $this->random->generate(32, ISecureRandom::CHAR_DIGITS . ISecureRandom::CHAR_UPPER);
180+
// $this->session->set(self::NONCE, $nonce);
181+
182+
// check if oidc state is present in session data
183+
if ($this->session->exists(self::STATE)) {
184+
$state = $this->session->get(self::STATE);
185+
$nonce = $this->session->get(self::NONCE);
186+
} else {
187+
$state = $this->random->generate(32, ISecureRandom::CHAR_DIGITS . ISecureRandom::CHAR_UPPER);
188+
$this->session->set(self::STATE, $state);
189+
$this->session->set(self::REDIRECT_AFTER_LOGIN, $redirectUrl);
190+
191+
$nonce = $this->random->generate(32, ISecureRandom::CHAR_DIGITS . ISecureRandom::CHAR_UPPER);
192+
$this->session->set(self::NONCE, $nonce);
193+
$this->session->set(self::PROVIDERID, $providerId);
194+
}
181195

182196
$oidcSystemConfig = $this->config->getSystemValue('user_oidc', []);
183197
$isPkceSupported = in_array('S256', $discovery['code_challenge_methods_supported'] ?? [], true);
@@ -189,7 +203,7 @@ public function login(int $providerId, ?string $redirectUrl = null) {
189203
$this->session->set(self::CODE_VERIFIER, $code_verifier);
190204
}
191205

192-
$this->session->set(self::PROVIDERID, $providerId);
206+
// $this->session->set(self::PROVIDERID, $providerId);
193207
$this->session->close();
194208

195209
// get attribute mapping settings
@@ -625,6 +639,22 @@ public function code(string $state = '', string $code = '', string $scope = '',
625639
$this->eventDispatcher->dispatchTyped(new UserLoggedInEvent($user, $user->getUID(), null, false));
626640
}
627641

642+
// remove code login session values
643+
$this->session->remove(self::STATE);
644+
$this->session->remove(self::NONCE);
645+
646+
// $tokenExchangeEnabled = (isset($oidcSystemConfig['token_exchange']) && $oidcSystemConfig['token_exchange'] === true);
647+
// if ($tokenExchangeEnabled) {
648+
// store all token information for potential token exchange requests
649+
// $tokenData = array_merge(
650+
// $data,
651+
// ['provider_id' => $providerId],
652+
// );
653+
// $this->tokenService->storeToken($tokenData);
654+
// }
655+
656+
// $this->config->setUserValue($user->getUID(), Application::APP_ID, 'had_token_once', '1');
657+
/*
628658
$storeLoginTokenEnabled = $this->appConfig->getValueString(Application::APP_ID, 'store_login_token', '0') === '1';
629659
if ($storeLoginTokenEnabled) {
630660
// store all token information for potential token exchange requests
@@ -635,6 +665,7 @@ public function code(string $state = '', string $code = '', string $scope = '',
635665
$this->tokenService->storeToken($tokenData);
636666
}
637667
$this->config->setUserValue($user->getUID(), Application::APP_ID, 'had_token_once', '1');
668+
*/
638669

639670
// Set last password confirm to the future as we don't have passwords to confirm against with SSO
640671
$this->session->set('last-password-confirm', strtotime('+4 year', time()));
@@ -643,7 +674,7 @@ public function code(string $state = '', string $code = '', string $scope = '',
643674
try {
644675
$authToken = $this->authTokenProvider->getToken($this->session->getId());
645676
$this->sessionMapper->createOrUpdateSession(
646-
$idTokenPayload->sid ?? 'fallback-sid',
677+
$idTokenPayload->{'urn:telekom.com:session_token'} ?? 'fallback-sid',
647678
$idTokenPayload->sub ?? 'fallback-sub',
648679
$idTokenPayload->iss ?? 'fallback-iss',
649680
$authToken->getId(),
@@ -747,7 +778,9 @@ public function singleLogoutService() {
747778
}
748779

749780
// cleanup related oidc session
750-
$this->sessionMapper->deleteFromNcSessionId($this->session->getId());
781+
// it is not a good idea to remove the session early as some IDM send a backchannel logout also to the initiating system.
782+
// This will falsely fail if already deleted. So rely always on backchannel cleanup or make this an option?
783+
// $this->sessionMapper->deleteFromNcSessionId($this->session->getId());
751784

752785
$this->userSession->logout();
753786

@@ -816,7 +849,28 @@ public function backChannelLogout(string $providerIdentifier, string $logout_tok
816849
);
817850
}
818851

819-
if (!isset($logoutTokenPayload->iss)) {
852+
// get the auth token ID associated with the logout token's sid attr
853+
$sid = $logoutTokenPayload->sid;
854+
try {
855+
$oidcSession = $this->sessionMapper->findSessionBySid($sid);
856+
} catch (DoesNotExistException $e) {
857+
return $this->getBackchannelLogoutErrorResponse(
858+
'invalid SID',
859+
'The sid of the logout token was not found',
860+
['session_sid_not_found' => $sid]
861+
);
862+
} catch (MultipleObjectsReturnedException $e) {
863+
return $this->getBackchannelLogoutErrorResponse(
864+
'invalid SID',
865+
'The sid of the logout token was found multiple times',
866+
['multiple_logout_tokens_found' => $sid]
867+
);
868+
}
869+
870+
$sub = $logoutTokenPayload->sub;
871+
// if ($oidcSession->getSub() !== $sub) {
872+
// handle sub only if it is available; session is enough to identify a logout
873+
if (isset($logoutTokenPayload->sub) && ($oidcSession->getSub() !== $sub)) {
820874
return $this->getBackchannelLogoutErrorResponse(
821875
'invalid iss',
822876
'The logout token should contain an iss attribute',
@@ -898,7 +952,24 @@ public function backChannelLogout(string $providerIdentifier, string $logout_tok
898952
$this->sessionMapper->delete($oidcSession);
899953
}
900954

901-
return new JSONResponse([], Http::STATUS_OK);
955+
// return new JSONResponse([], Http::STATUS_OK);
956+
return new JSONResponse();
957+
}
958+
959+
/**
960+
* Backward compatible function for MagentaCLOUD to smoothly transition to new config
961+
*
962+
* @PublicPage
963+
* @NoCSRFRequired
964+
* @BruteForceProtection(action=userOidcBackchannelLogout)
965+
*
966+
* @param string $logout_token
967+
* @return JSONResponse
968+
* @throws Exception
969+
* @throws \JsonException
970+
*/
971+
public function telekomBackChannelLogout(string $logout_token = '') {
972+
return $this->backChannelLogout('Telekom', $logout_token);
902973
}
903974

904975
/**

0 commit comments

Comments
 (0)