Skip to content

Commit 6233888

Browse files
committed
Merge #17 Fix backchannel logout for Telekom and keep backward compatibility V31
2 parents 68a90bb + 90207a1 commit 6233888

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
@@ -621,6 +635,22 @@ public function code(string $state = '', string $code = '', string $scope = '',
621635
$this->eventDispatcher->dispatchTyped(new UserLoggedInEvent($user, $user->getUID(), null, false));
622636
}
623637

638+
// remove code login session values
639+
$this->session->remove(self::STATE);
640+
$this->session->remove(self::NONCE);
641+
642+
// $tokenExchangeEnabled = (isset($oidcSystemConfig['token_exchange']) && $oidcSystemConfig['token_exchange'] === true);
643+
// if ($tokenExchangeEnabled) {
644+
// store all token information for potential token exchange requests
645+
// $tokenData = array_merge(
646+
// $data,
647+
// ['provider_id' => $providerId],
648+
// );
649+
// $this->tokenService->storeToken($tokenData);
650+
// }
651+
652+
// $this->config->setUserValue($user->getUID(), Application::APP_ID, 'had_token_once', '1');
653+
/*
624654
$storeLoginTokenEnabled = $this->appConfig->getValueString(Application::APP_ID, 'store_login_token', '0') === '1';
625655
if ($storeLoginTokenEnabled) {
626656
// store all token information for potential token exchange requests
@@ -631,6 +661,7 @@ public function code(string $state = '', string $code = '', string $scope = '',
631661
$this->tokenService->storeToken($tokenData);
632662
}
633663
$this->config->setUserValue($user->getUID(), Application::APP_ID, 'had_token_once', '1');
664+
*/
634665

635666
// Set last password confirm to the future as we don't have passwords to confirm against with SSO
636667
$this->session->set('last-password-confirm', strtotime('+4 year', time()));
@@ -639,7 +670,7 @@ public function code(string $state = '', string $code = '', string $scope = '',
639670
try {
640671
$authToken = $this->authTokenProvider->getToken($this->session->getId());
641672
$this->sessionMapper->createOrUpdateSession(
642-
$idTokenPayload->sid ?? 'fallback-sid',
673+
$idTokenPayload->{'urn:telekom.com:session_token'} ?? 'fallback-sid',
643674
$idTokenPayload->sub ?? 'fallback-sub',
644675
$idTokenPayload->iss ?? 'fallback-iss',
645676
$authToken->getId(),
@@ -743,7 +774,9 @@ public function singleLogoutService() {
743774
}
744775

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

748781
$this->userSession->logout();
749782

@@ -812,7 +845,28 @@ public function backChannelLogout(string $providerIdentifier, string $logout_tok
812845
);
813846
}
814847

815-
if (!isset($logoutTokenPayload->iss)) {
848+
// get the auth token ID associated with the logout token's sid attr
849+
$sid = $logoutTokenPayload->sid;
850+
try {
851+
$oidcSession = $this->sessionMapper->findSessionBySid($sid);
852+
} catch (DoesNotExistException $e) {
853+
return $this->getBackchannelLogoutErrorResponse(
854+
'invalid SID',
855+
'The sid of the logout token was not found',
856+
['session_sid_not_found' => $sid]
857+
);
858+
} catch (MultipleObjectsReturnedException $e) {
859+
return $this->getBackchannelLogoutErrorResponse(
860+
'invalid SID',
861+
'The sid of the logout token was found multiple times',
862+
['multiple_logout_tokens_found' => $sid]
863+
);
864+
}
865+
866+
$sub = $logoutTokenPayload->sub;
867+
// if ($oidcSession->getSub() !== $sub) {
868+
// handle sub only if it is available; session is enough to identify a logout
869+
if (isset($logoutTokenPayload->sub) && ($oidcSession->getSub() !== $sub)) {
816870
return $this->getBackchannelLogoutErrorResponse(
817871
'invalid iss',
818872
'The logout token should contain an iss attribute',
@@ -894,7 +948,24 @@ public function backChannelLogout(string $providerIdentifier, string $logout_tok
894948
$this->sessionMapper->delete($oidcSession);
895949
}
896950

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

900971
/**

0 commit comments

Comments
 (0)