Skip to content

Commit c54e514

Browse files
committed
Merge #17 Fix backchannel logout for Telekom and keep backward compatibility V31
2 parents ae7ac01 + d1cfd56 commit c54e514

1 file changed

Lines changed: 56 additions & 15 deletions

File tree

lib/Controller/LoginController.php

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

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

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

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

183-
$this->session->set(self::PROVIDERID, $providerId);
197+
// $this->session->set(self::PROVIDERID, $providerId);
184198
$this->session->close();
185199

186200
// get attribute mapping settings
@@ -517,14 +531,19 @@ public function code(string $state = '', string $code = '', string $scope = '',
517531
$this->userSession->createRememberMeToken($user);
518532
}
519533

534+
// remove code login session values
535+
$this->session->remove(self::STATE);
536+
$this->session->remove(self::NONCE);
537+
520538
// Set last password confirm to the future as we don't have passwords to confirm against with SSO
521539
$this->session->set('last-password-confirm', strtotime('+4 year', time()));
522540

523541
// for backchannel logout
524542
try {
525543
$authToken = $this->authTokenProvider->getToken($this->session->getId());
526544
$this->sessionMapper->createSession(
527-
$idTokenPayload->sid ?? 'fallback-sid',
545+
//$idTokenPayload->sid ?? 'fallback-sid',
546+
$idTokenPayload->{'urn:telekom.com:session_token'} ?? 'fallback-sid',
528547
$idTokenPayload->sub ?? 'fallback-sub',
529548
$idTokenPayload->iss ?? 'fallback-iss',
530549
$authToken->getId(),
@@ -599,7 +618,9 @@ public function singleLogoutService() {
599618
}
600619

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

604625
$this->userSession->logout();
605626

@@ -687,7 +708,9 @@ public function backChannelLogout(string $providerIdentifier, string $logout_tok
687708
}
688709

689710
$sub = $logoutTokenPayload->sub;
690-
if ($oidcSession->getSub() !== $sub) {
711+
// if ($oidcSession->getSub() !== $sub) {
712+
// handle sub only if it is available; session is enough to identify a logout
713+
if (isset($logoutTokenPayload->sub) && ($oidcSession->getSub() !== $sub)) {
691714
return $this->getBackchannelLogoutErrorResponse(
692715
'invalid SUB',
693716
'The sub does not match the one from the login ID token',
@@ -712,17 +735,19 @@ public function backChannelLogout(string $providerIdentifier, string $logout_tok
712735
$userId = $authToken->getUID();
713736
$this->authTokenProvider->invalidateTokenById($userId, $authToken->getId());
714737
} catch (InvalidTokenException $e) {
715-
return $this->getBackchannelLogoutErrorResponse(
716-
'nc session not found',
717-
'The authentication session was not found in Nextcloud',
718-
['nc_auth_session_not_found' => $authTokenId]
719-
);
738+
// it is not a problem if the auth token is already deleted, so no error
739+
// return $this->getBackchannelLogoutErrorResponse(
740+
// 'nc session not found',
741+
// 'The authentication session was not found in Nextcloud',
742+
// ['nc_auth_session_not_found' => $authTokenId]
743+
// );
720744
}
721745

722746
// cleanup
723747
$this->sessionMapper->delete($oidcSession);
724748

725-
return new JSONResponse([], Http::STATUS_OK);
749+
// return new JSONResponse([], Http::STATUS_OK);
750+
return new JSONResponse();
726751
}
727752

728753
/**
@@ -756,4 +781,20 @@ private function toCodeChallenge(string $data): string {
756781
$s = str_replace('/', '_', $s); // 63rd char of encoding
757782
return $s;
758783
}
784+
785+
/**
786+
* Backward compatible function for MagentaCLOUD to smoothly transition to new config
787+
*
788+
* @PublicPage
789+
* @NoCSRFRequired
790+
* @BruteForceProtection(action=userOidcBackchannelLogout)
791+
*
792+
* @param string $logout_token
793+
* @return JSONResponse
794+
* @throws Exception
795+
* @throws \JsonException
796+
*/
797+
public function telekomBackChannelLogout(string $logout_token = '') {
798+
return $this->backChannelLogout('Telekom', $logout_token);
799+
}
759800
}

0 commit comments

Comments
 (0)