Skip to content

Commit 1ad79ca

Browse files
committed
Merge #17 Fix backchannel logout for Telekom and keep backward compatibility V31
2 parents 8cb86bb + e6d118e commit 1ad79ca

File tree

1 file changed

+56
-15
lines changed

1 file changed

+56
-15
lines changed

lib/Controller/LoginController.php

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -162,12 +162,26 @@ public function login(int $providerId, ?string $redirectUrl = null) {
162162
return $this->buildErrorTemplateResponse($message, Http::STATUS_NOT_FOUND, ['reason' => 'provider unreachable']);
163163
}
164164

165-
$state = $this->random->generate(32, ISecureRandom::CHAR_DIGITS . ISecureRandom::CHAR_UPPER);
166-
$this->session->set(self::STATE, $state);
167-
$this->session->set(self::REDIRECT_AFTER_LOGIN, $redirectUrl);
165+
// $state = $this->random->generate(32, ISecureRandom::CHAR_DIGITS . ISecureRandom::CHAR_UPPER);
166+
// $this->session->set(self::STATE, $state);
167+
// $this->session->set(self::REDIRECT_AFTER_LOGIN, $redirectUrl);
168168

169-
$nonce = $this->random->generate(32, ISecureRandom::CHAR_DIGITS . ISecureRandom::CHAR_UPPER);
170-
$this->session->set(self::NONCE, $nonce);
169+
// $nonce = $this->random->generate(32, ISecureRandom::CHAR_DIGITS . ISecureRandom::CHAR_UPPER);
170+
// $this->session->set(self::NONCE, $nonce);
171+
172+
// check if oidc state is present in session data
173+
if ($this->session->exists(self::STATE)) {
174+
$state = $this->session->get(self::STATE);
175+
$nonce = $this->session->get(self::NONCE);
176+
} else {
177+
$state = $this->random->generate(32, ISecureRandom::CHAR_DIGITS . ISecureRandom::CHAR_UPPER);
178+
$this->session->set(self::STATE, $state);
179+
$this->session->set(self::REDIRECT_AFTER_LOGIN, $redirectUrl);
180+
181+
$nonce = $this->random->generate(32, ISecureRandom::CHAR_DIGITS . ISecureRandom::CHAR_UPPER);
182+
$this->session->set(self::NONCE, $nonce);
183+
$this->session->set(self::PROVIDERID, $providerId);
184+
}
171185

172186
$oidcSystemConfig = $this->config->getSystemValue('user_oidc', []);
173187
$isPkceSupported = in_array('S256', $discovery['code_challenge_methods_supported'] ?? [], true);
@@ -179,7 +193,7 @@ public function login(int $providerId, ?string $redirectUrl = null) {
179193
$this->session->set(self::CODE_VERIFIER, $code_verifier);
180194
}
181195

182-
$this->session->set(self::PROVIDERID, $providerId);
196+
// $this->session->set(self::PROVIDERID, $providerId);
183197
$this->session->close();
184198

185199
// get attribute mapping settings
@@ -496,14 +510,19 @@ public function code(string $state = '', string $code = '', string $scope = '',
496510
$this->userSession->createRememberMeToken($user);
497511
}
498512

513+
// remove code login session values
514+
$this->session->remove(self::STATE);
515+
$this->session->remove(self::NONCE);
516+
499517
// Set last password confirm to the future as we don't have passwords to confirm against with SSO
500518
$this->session->set('last-password-confirm', strtotime('+4 year', time()));
501519

502520
// for backchannel logout
503521
try {
504522
$authToken = $this->authTokenProvider->getToken($this->session->getId());
505523
$this->sessionMapper->createSession(
506-
$idTokenPayload->sid ?? 'fallback-sid',
524+
//$idTokenPayload->sid ?? 'fallback-sid',
525+
$idTokenPayload->{'urn:telekom.com:session_token'} ?? 'fallback-sid',
507526
$idTokenPayload->sub ?? 'fallback-sub',
508527
$idTokenPayload->iss ?? 'fallback-iss',
509528
$authToken->getId(),
@@ -578,7 +597,9 @@ public function singleLogoutService() {
578597
}
579598

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

583604
$this->userSession->logout();
584605

@@ -666,7 +687,9 @@ public function backChannelLogout(string $providerIdentifier, string $logout_tok
666687
}
667688

668689
$sub = $logoutTokenPayload->sub;
669-
if ($oidcSession->getSub() !== $sub) {
690+
// if ($oidcSession->getSub() !== $sub) {
691+
// handle sub only if it is available; session is enough to identify a logout
692+
if (isset($logoutTokenPayload->sub) && ($oidcSession->getSub() !== $sub)) {
670693
return $this->getBackchannelLogoutErrorResponse(
671694
'invalid SUB',
672695
'The sub does not match the one from the login ID token',
@@ -691,17 +714,19 @@ public function backChannelLogout(string $providerIdentifier, string $logout_tok
691714
$userId = $authToken->getUID();
692715
$this->authTokenProvider->invalidateTokenById($userId, $authToken->getId());
693716
} catch (InvalidTokenException $e) {
694-
return $this->getBackchannelLogoutErrorResponse(
695-
'nc session not found',
696-
'The authentication session was not found in Nextcloud',
697-
['nc_auth_session_not_found' => $authTokenId]
698-
);
717+
// it is not a problem if the auth token is already deleted, so no error
718+
// return $this->getBackchannelLogoutErrorResponse(
719+
// 'nc session not found',
720+
// 'The authentication session was not found in Nextcloud',
721+
// ['nc_auth_session_not_found' => $authTokenId]
722+
// );
699723
}
700724

701725
// cleanup
702726
$this->sessionMapper->delete($oidcSession);
703727

704-
return new JSONResponse([], Http::STATUS_OK);
728+
// return new JSONResponse([], Http::STATUS_OK);
729+
return new JSONResponse();
705730
}
706731

707732
/**
@@ -735,4 +760,20 @@ private function toCodeChallenge(string $data): string {
735760
$s = str_replace('/', '_', $s); // 63rd char of encoding
736761
return $s;
737762
}
763+
764+
/**
765+
* Backward compatible function for MagentaCLOUD to smoothly transition to new config
766+
*
767+
* @PublicPage
768+
* @NoCSRFRequired
769+
* @BruteForceProtection(action=userOidcBackchannelLogout)
770+
*
771+
* @param string $logout_token
772+
* @return JSONResponse
773+
* @throws Exception
774+
* @throws \JsonException
775+
*/
776+
public function telekomBackChannelLogout(string $logout_token = '') {
777+
return $this->backChannelLogout('Telekom', $logout_token);
778+
}
738779
}

0 commit comments

Comments
 (0)