From 2f2b04a41710335ef8e8a06e92384bdca9a9dac0 Mon Sep 17 00:00:00 2001 From: Akhil Date: Tue, 6 Dec 2022 18:08:14 +0530 Subject: [PATCH 01/14] added logic to store tokens --- lib/AppInfo/Application.php | 10 ++++++ lib/Controller/LoginController.php | 2 ++ lib/Service/LoginService.php | 21 ++++++++--- lib/Service/TokenService.php | 57 ++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 lib/Service/TokenService.php diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index ff5116f..3cd2128 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -6,6 +6,7 @@ use OC\AppFramework\Utility\ControllerMethodReflector; use OCA\OIDCLogin\OIDCLoginOption; +use OCA\OIDCLogin\Service\TokenService; use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IBootContext; use OCP\AppFramework\Bootstrap\IBootstrap; @@ -31,6 +32,8 @@ class Application extends App implements IBootstrap protected $config; private $appName = 'oidc_login'; + private $tokenService; + public function __construct() { parent::__construct($this->appName); @@ -73,6 +76,7 @@ public function boot(IBootContext $context): void { $container = $context->getAppContainer(); $this->l = $container->query(IL10N::class); + $this->tokenService = $container->query(TokenService::class); $this->url = $container->query(IURLGenerator::class); $this->config = $container->query(IConfig::class); $request = $container->query(IRequest::class); @@ -121,6 +125,12 @@ public function boot(IBootContext $context): void }); } + if (!$this->tokenService->refreshTokens()) { + $userSession->logout(); + + return; + } + // Hide password change form if ($this->config->getSystemValue('oidc_login_hide_password_form', false)) { Util::addStyle($this->appName, 'oidc.hidepasswordform'); diff --git a/lib/Controller/LoginController.php b/lib/Controller/LoginController.php index 9714b7a..616efde 100644 --- a/lib/Controller/LoginController.php +++ b/lib/Controller/LoginController.php @@ -87,6 +87,8 @@ public function oidc() // Authenticate $oidc->authenticate(); + $this->loginService->storeTokens($oidc->getTokenResponse()); + $user = null; if ($this->config->getSystemValue('oidc_login_use_id_token', false)) { // Get user information from ID Token diff --git a/lib/Service/LoginService.php b/lib/Service/LoginService.php index fcffa0f..e299fdd 100644 --- a/lib/Service/LoginService.php +++ b/lib/Service/LoginService.php @@ -192,15 +192,28 @@ public function completeLogin($user, $userPassword, $userSession, $request) $user->updateLastLoginTimestamp(); } + public function storeTokens(object $tokenResponse) + { + $this->session->set('oidc_access_token', $tokenResponse->access_token); + $this->session->set('oidc_refresh_token', $tokenResponse->refresh_token); + + $now = time(); + $accessTokenExpiresIn = $tokenResponse->expires_in + $now; + $refreshTokenExpiresIn = $now + $tokenResponse->refresh_expires_in - 5; + + $this->session->set('oidc_access_token_expires_in', $accessTokenExpiresIn); + $this->session->set('oidc_refresh_token_expires_in', $refreshTokenExpiresIn); + } + /** * If the LDAP backend interface is enabled, make user the * user actually exists in LDAP and return the uid. * * @param null|string $ldapUid * - * @return null|string LDAP user uid or null if not found - * * @throws LoginException if LDAP backend is not enabled or user is not found + * + * @return null|string LDAP user uid or null if not found */ private function getLDAPUserUid($ldapUid) { @@ -258,9 +271,9 @@ private function getLDAPUserUid($ldapUid) * * @param string $uid * - * @return false|\OCP\IUser User object if created - * * @throws LoginException If oidc_login_disable_registration is true + * + * @return false|\OCP\IUser User object if created */ private function createUser($uid) { diff --git a/lib/Service/TokenService.php b/lib/Service/TokenService.php new file mode 100644 index 0000000..848442d --- /dev/null +++ b/lib/Service/TokenService.php @@ -0,0 +1,57 @@ +appName = $appName; + $this->session = $session; + $this->loginService = $loginService; + $this->urlGenerator = $urlGenerator; + } + + public function refreshTokens(): bool + { + $accessTokenExpiresIn = $this->session->get('oidc_access_token_expires_in'); + $now = time(); + if ($now < $accessTokenExpiresIn) { + return true; + } + + $refreshTokenExpiresIn = $this->session->get('oidc_refresh_token_expires_in'); + $refreshToken = $this->session->get('oidc_refresh_token'); + if (!$refreshToken || ($refreshTokenExpiresIn && $now > $refreshTokenExpiresIn)) { + return false; + } + + $callbackUrl = $this->urlGenerator->linkToRouteAbsolute($this->appName.'.login.oidc'); + + try { + $oidc = $this->loginService->createOIDCClient($callbackUrl); + $tokenResponse = $oidc->refreshToken($refreshToken); + } catch (Exception $e) { + return false; + } + + $this->loginService->storeTokens($tokenResponse); + + return true; + } +} From 060a8c89cea31900797e82a4e1a33bf1aece8d63 Mon Sep 17 00:00:00 2001 From: Akhil Date: Fri, 9 Dec 2022 19:07:38 +0530 Subject: [PATCH 02/14] Handle token refresh via listener --- lib/AppInfo/Application.php | 8 --- lib/Controller/LoginController.php | 11 ++- .../BeforeTemplateRenderedListener.php | 46 +++++++++++++ lib/Service/LoginService.php | 34 ---------- lib/Service/TokenService.php | 68 ++++++++++++++++--- lib/WebDAV/BasicAuthBackend.php | 9 ++- lib/WebDAV/BearerAuthBackend.php | 8 ++- 7 files changed, 129 insertions(+), 55 deletions(-) create mode 100644 lib/Listeners/BeforeTemplateRenderedListener.php diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 3cd2128..1a4de8c 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -6,7 +6,6 @@ use OC\AppFramework\Utility\ControllerMethodReflector; use OCA\OIDCLogin\OIDCLoginOption; -use OCA\OIDCLogin\Service\TokenService; use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IBootContext; use OCP\AppFramework\Bootstrap\IBootstrap; @@ -32,7 +31,6 @@ class Application extends App implements IBootstrap protected $config; private $appName = 'oidc_login'; - private $tokenService; public function __construct() { @@ -76,7 +74,6 @@ public function boot(IBootContext $context): void { $container = $context->getAppContainer(); $this->l = $container->query(IL10N::class); - $this->tokenService = $container->query(TokenService::class); $this->url = $container->query(IURLGenerator::class); $this->config = $container->query(IConfig::class); $request = $container->query(IRequest::class); @@ -125,11 +122,6 @@ public function boot(IBootContext $context): void }); } - if (!$this->tokenService->refreshTokens()) { - $userSession->logout(); - - return; - } // Hide password change form if ($this->config->getSystemValue('oidc_login_hide_password_form', false)) { diff --git a/lib/Controller/LoginController.php b/lib/Controller/LoginController.php index 616efde..65d9e62 100644 --- a/lib/Controller/LoginController.php +++ b/lib/Controller/LoginController.php @@ -3,6 +3,7 @@ namespace OCA\OIDCLogin\Controller; use OCA\OIDCLogin\Service\LoginService; +use OCA\OIDCLogin\Service\TokenService; use OCP\AppFramework\Controller; use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Utility\ITimeFactory; @@ -38,6 +39,9 @@ class LoginController extends Controller /** @var LoginService */ private $loginService; + /** @var TokenService */ + private $tokenService; + /** @var IL10N */ private $l; @@ -55,6 +59,7 @@ public function __construct( ISession $session, IL10N $l, LoginService $loginService, + TokenService $tokenService, $storagesService ) { parent::__construct($appName, $request); @@ -66,6 +71,7 @@ public function __construct( $this->session = $session; $this->l = $l; $this->loginService = $loginService; + $this->tokenService = $tokenService; $this->storagesService = $storagesService; } @@ -82,12 +88,13 @@ public function oidc() try { // Construct new client - $oidc = $this->loginService->createOIDCClient($callbackUrl); + $oidc = $this->tokenService->createOIDCClient($callbackUrl); // Authenticate $oidc->authenticate(); - $this->loginService->storeTokens($oidc->getTokenResponse()); + $tokenResponse = $oidc->getTokenResponse(); + $this->tokenService->storeTokens($tokenResponse); $user = null; if ($this->config->getSystemValue('oidc_login_use_id_token', false)) { diff --git a/lib/Listeners/BeforeTemplateRenderedListener.php b/lib/Listeners/BeforeTemplateRenderedListener.php new file mode 100644 index 0000000..810e414 --- /dev/null +++ b/lib/Listeners/BeforeTemplateRenderedListener.php @@ -0,0 +1,46 @@ +appName = $appName; + $this->userSession = $userSession; + $this->tokenService = $tokenService; + $this->session = $session; + } + + public function handle(Event $event): void + { + if (!($event instanceof BeforeTemplateRenderedEvent) || !$this->userSession->isLoggedIn() || !$this->session->exists('is_oidc')) { + return; + } + + if (!$this->tokenService->refreshTokens()) { + $this->userSession->logout(); + } + } +} diff --git a/lib/Service/LoginService.php b/lib/Service/LoginService.php index e299fdd..d6aa660 100644 --- a/lib/Service/LoginService.php +++ b/lib/Service/LoginService.php @@ -4,7 +4,6 @@ use OC\Authentication\Token\IProvider; use OC\User\LoginException; -use OCA\OIDCLogin\Provider\OpenIDConnectClient; use OCP\IAvatarManager; use OCP\IConfig; use OCP\IGroupManager; @@ -75,26 +74,6 @@ public function __construct( $this->attr = new AttributeMap($config); } - public function createOIDCClient($callbackUrl = '') - { - $oidc = new OpenIDConnectClient( - $this->session, - $this->config, - $this->appName, - ); - $oidc->setRedirectURL($callbackUrl); - - // set TLS development mode - $oidc->setVerifyHost($this->config->getSystemValue('oidc_login_tls_verify', true)); - $oidc->setVerifyPeer($this->config->getSystemValue('oidc_login_tls_verify', true)); - - // Set OpenID Connect Scope - $scope = $this->config->getSystemValue('oidc_login_scope', 'openid'); - $oidc->addScope($scope); - - return $oidc; - } - public function login($profile, $userSession, $request) { // Flatten the profile array @@ -192,19 +171,6 @@ public function completeLogin($user, $userPassword, $userSession, $request) $user->updateLastLoginTimestamp(); } - public function storeTokens(object $tokenResponse) - { - $this->session->set('oidc_access_token', $tokenResponse->access_token); - $this->session->set('oidc_refresh_token', $tokenResponse->refresh_token); - - $now = time(); - $accessTokenExpiresIn = $tokenResponse->expires_in + $now; - $refreshTokenExpiresIn = $now + $tokenResponse->refresh_expires_in - 5; - - $this->session->set('oidc_access_token_expires_in', $accessTokenExpiresIn); - $this->session->set('oidc_refresh_token_expires_in', $refreshTokenExpiresIn); - } - /** * If the LDAP backend interface is enabled, make user the * user actually exists in LDAP and return the uid. diff --git a/lib/Service/TokenService.php b/lib/Service/TokenService.php index 848442d..d1f5d03 100644 --- a/lib/Service/TokenService.php +++ b/lib/Service/TokenService.php @@ -3,55 +3,105 @@ namespace OCA\OIDCLogin\Service; use Exception; +use OCA\OIDCLogin\Provider\OpenIDConnectClient; +use OCP\IConfig; use OCP\ISession; use OCP\IURLGenerator; class TokenService { - public const USER_AGENT = 'NextcloudOIDCLogin'; + /** @var string */ + private $appName; /** @var ISession */ private $session; - private $loginService; + /** @var IConfig */ + private $config; + + /** @var IURLGenerator */ + private $urlGenerator; public function __construct( $appName, ISession $session, - LoginService $loginService, + IConfig $config, IURLGenerator $urlGenerator, ) { $this->appName = $appName; $this->session = $session; - $this->loginService = $loginService; + $this->config = $config; $this->urlGenerator = $urlGenerator; } + /** + * @param string $callbackUrl + * + * @return OpenIDConnectClient Configured instance of OpendIDConnectClient + */ + public function createOIDCClient($callbackUrl = '') + { + $oidc = new OpenIDConnectClient( + $this->session, + $this->config, + $this->appName, + ); + $oidc->setRedirectURL($callbackUrl); + + // set TLS development mode + $oidc->setVerifyHost($this->config->getSystemValue('oidc_login_tls_verify', true)); + $oidc->setVerifyPeer($this->config->getSystemValue('oidc_login_tls_verify', true)); + + // Set OpenID Connect Scope + $scope = $this->config->getSystemValue('oidc_login_scope', 'openid'); + $oidc->addScope($scope); + + return $oidc; + } + + /** + * @return bool Whether or not valid access token + */ public function refreshTokens(): bool { $accessTokenExpiresIn = $this->session->get('oidc_access_token_expires_in'); $now = time(); - if ($now < $accessTokenExpiresIn) { + // If access token hasn't expired yet + if (!empty($accessTokenExpiresIn) && $now < $accessTokenExpiresIn) { return true; } $refreshTokenExpiresIn = $this->session->get('oidc_refresh_token_expires_in'); $refreshToken = $this->session->get('oidc_refresh_token'); - if (!$refreshToken || ($refreshTokenExpiresIn && $now > $refreshTokenExpiresIn)) { + // If refresh token doesn't exist or refresh token has expired + if (!$refreshToken || (!empty($refreshTokenExpiresIn) && $now > $refreshTokenExpiresIn)) { return false; } $callbackUrl = $this->urlGenerator->linkToRouteAbsolute($this->appName.'.login.oidc'); + // Refresh the tokens, return false on failure try { - $oidc = $this->loginService->createOIDCClient($callbackUrl); + $oidc = $this->createOIDCClient($callbackUrl); $tokenResponse = $oidc->refreshToken($refreshToken); + $this->storeTokens($tokenResponse); + + return true; } catch (Exception $e) { return false; } + } - $this->loginService->storeTokens($tokenResponse); + public function storeTokens(object $tokenResponse): void + { + $this->session->set('oidc_access_token', $tokenResponse->access_token); + $this->session->set('oidc_refresh_token', $tokenResponse->refresh_token); + + $now = time(); + $accessTokenExpiresIn = $tokenResponse->expires_in + $now; + $refreshTokenExpiresIn = $now + $tokenResponse->refresh_expires_in - 5; - return true; + $this->session->set('oidc_access_token_expires_in', $accessTokenExpiresIn); + $this->session->set('oidc_refresh_token_expires_in', $refreshTokenExpiresIn); } } diff --git a/lib/WebDAV/BasicAuthBackend.php b/lib/WebDAV/BasicAuthBackend.php index 7c890e4..d02ab28 100644 --- a/lib/WebDAV/BasicAuthBackend.php +++ b/lib/WebDAV/BasicAuthBackend.php @@ -3,6 +3,7 @@ namespace OCA\OIDCLogin\WebDAV; use OCA\OIDCLogin\Service\LoginService; +use OCA\OIDCLogin\Service\TokenService; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; use OCP\IConfig; @@ -35,6 +36,10 @@ class BasicAuthBackend extends AbstractBasic implements IEventListener /** @var LoginService */ private $loginService; + /** @var TokenService */ + private $tokenService; + + /** * @param string $principalPrefix */ @@ -46,6 +51,7 @@ public function __construct( IConfig $config, LoggerInterface $logger, LoginService $loginService, + TokenService $tokenService, $principalPrefix = 'principals/users/' ) { $this->appName = $appName; @@ -55,6 +61,7 @@ public function __construct( $this->config = $config; $this->logger = $logger; $this->loginService = $loginService; + $this->tokenService = $tokenService; $this->principalPrefix = $principalPrefix; $this->context = ['app' => $appName]; @@ -123,7 +130,7 @@ private function setupUserFs($userId) */ private function login(string $username, string $password) { - $client = $this->loginService->createOIDCClient(); + $client = $this->tokenService->createOIDCClient(); if (null === $client) { throw new \Exception("Couldn't create OIDC client!"); } diff --git a/lib/WebDAV/BearerAuthBackend.php b/lib/WebDAV/BearerAuthBackend.php index 65628ff..1ea5d3b 100644 --- a/lib/WebDAV/BearerAuthBackend.php +++ b/lib/WebDAV/BearerAuthBackend.php @@ -3,6 +3,7 @@ namespace OCA\OIDCLogin\WebDAV; use OCA\OIDCLogin\Service\LoginService; +use OCA\OIDCLogin\Service\TokenService; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; use OCP\IConfig; @@ -38,6 +39,9 @@ class BearerAuthBackend extends AbstractBearer implements IEventListener /** @var LoginService */ private $loginService; + /** @var TokenService */ + private $tokenService; + /** * @param string $principalPrefix */ @@ -49,6 +53,7 @@ public function __construct( IConfig $config, LoggerInterface $logger, LoginService $loginService, + TokenService $tokenService, $principalPrefix = 'principals/users/' ) { $this->appName = $appName; @@ -58,6 +63,7 @@ public function __construct( $this->config = $config; $this->logger = $logger; $this->loginService = $loginService; + $this->tokenService = $tokenService; $this->principalPrefix = $principalPrefix; $this->context = ['app' => $appName]; @@ -119,7 +125,7 @@ private function setupUserFs($userId) */ private function login(string $bearerToken) { - $client = $this->loginService->createOIDCClient(); + $client = $this->tokenService->createOIDCClient(); if (null === $client) { throw new \Exception("Couldn't create OIDC client!"); } From 7f8b0cfce5131b4ed29b29dd01c0db583ae29353 Mon Sep 17 00:00:00 2001 From: Akhil Date: Fri, 9 Dec 2022 19:12:00 +0530 Subject: [PATCH 03/14] Register event listener --- lib/AppInfo/Application.php | 6 ++++-- lib/Listeners/BeforeTemplateRenderedListener.php | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 1a4de8c..a152241 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -5,11 +5,13 @@ namespace OCA\OIDCLogin\AppInfo; use OC\AppFramework\Utility\ControllerMethodReflector; +use OCA\OIDCLogin\Listeners\BeforeTemplateRenderedListener; use OCA\OIDCLogin\OIDCLoginOption; use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IBootContext; use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\Bootstrap\IRegistrationContext; +use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent; use OCP\AppFramework\Utility\ITimeFactory; use OCP\IConfig; use OCP\IL10N; @@ -31,7 +33,6 @@ class Application extends App implements IBootstrap protected $config; private $appName = 'oidc_login'; - public function __construct() { parent::__construct($this->appName); @@ -68,6 +69,8 @@ public function register(IRegistrationContext $context): void 'OCA\DAV\Connector\Sabre::addPlugin', '\OCA\OIDCLogin\WebDAV\BasicAuthBackend' ); + + $context->registerEventListener(BeforeTemplateRenderedEvent::class, BeforeTemplateRenderedListener::class); } public function boot(IBootContext $context): void @@ -122,7 +125,6 @@ public function boot(IBootContext $context): void }); } - // Hide password change form if ($this->config->getSystemValue('oidc_login_hide_password_form', false)) { Util::addStyle($this->appName, 'oidc.hidepasswordform'); diff --git a/lib/Listeners/BeforeTemplateRenderedListener.php b/lib/Listeners/BeforeTemplateRenderedListener.php index 810e414..00261fd 100644 --- a/lib/Listeners/BeforeTemplateRenderedListener.php +++ b/lib/Listeners/BeforeTemplateRenderedListener.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace OCA\EcloudAccounts\Listeners; +namespace OCA\OIDCLogin\Listeners; use OCA\OIDCLogin\Service\TokenService; use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent; @@ -35,6 +35,7 @@ public function __construct($appName, IUserSession $userSession, ISession $sessi public function handle(Event $event): void { + // If user not logged in or not an oidc session, nothing to do if (!($event instanceof BeforeTemplateRenderedEvent) || !$this->userSession->isLoggedIn() || !$this->session->exists('is_oidc')) { return; } From ee908c6b5da37d20efab9de9bd6802d1ce880352 Mon Sep 17 00:00:00 2001 From: Akhil Date: Fri, 9 Dec 2022 19:23:18 +0530 Subject: [PATCH 04/14] Run php-cs-fixer on lib --- lib/WebDAV/BasicAuthBackend.php | 1 - lib/WebDAV/BearerAuthBackend.php | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/WebDAV/BasicAuthBackend.php b/lib/WebDAV/BasicAuthBackend.php index d02ab28..c8ee921 100644 --- a/lib/WebDAV/BasicAuthBackend.php +++ b/lib/WebDAV/BasicAuthBackend.php @@ -39,7 +39,6 @@ class BasicAuthBackend extends AbstractBasic implements IEventListener /** @var TokenService */ private $tokenService; - /** * @param string $principalPrefix */ diff --git a/lib/WebDAV/BearerAuthBackend.php b/lib/WebDAV/BearerAuthBackend.php index 1ea5d3b..7ecb17c 100644 --- a/lib/WebDAV/BearerAuthBackend.php +++ b/lib/WebDAV/BearerAuthBackend.php @@ -40,7 +40,7 @@ class BearerAuthBackend extends AbstractBearer implements IEventListener private $loginService; /** @var TokenService */ - private $tokenService; + private $tokenService; /** * @param string $principalPrefix From 16721a75ac9cc54a3e1984ba6cbf945e4f347108 Mon Sep 17 00:00:00 2001 From: Akhil Date: Fri, 9 Dec 2022 19:33:12 +0530 Subject: [PATCH 05/14] Fix token service in listener constructor --- lib/Listeners/BeforeTemplateRenderedListener.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Listeners/BeforeTemplateRenderedListener.php b/lib/Listeners/BeforeTemplateRenderedListener.php index 00261fd..ef116bc 100644 --- a/lib/Listeners/BeforeTemplateRenderedListener.php +++ b/lib/Listeners/BeforeTemplateRenderedListener.php @@ -25,7 +25,7 @@ class BeforeTemplateRenderedListener implements IEventListener /** @var ISession */ private $session; - public function __construct($appName, IUserSession $userSession, ISession $session) + public function __construct($appName, IUserSession $userSession, TokenService $tokenService, ISession $session) { $this->appName = $appName; $this->userSession = $userSession; From 935a4f97e5c98572fd4461a8d5e48b27e8149e67 Mon Sep 17 00:00:00 2001 From: Akhil Date: Tue, 13 Dec 2022 18:36:34 +0530 Subject: [PATCH 06/14] Remove listener, use boot --- lib/AppInfo/Application.php | 14 ++++-- .../BeforeTemplateRenderedListener.php | 47 ------------------- 2 files changed, 10 insertions(+), 51 deletions(-) delete mode 100644 lib/Listeners/BeforeTemplateRenderedListener.php diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index a152241..fdf8b1d 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -5,13 +5,12 @@ namespace OCA\OIDCLogin\AppInfo; use OC\AppFramework\Utility\ControllerMethodReflector; -use OCA\OIDCLogin\Listeners\BeforeTemplateRenderedListener; use OCA\OIDCLogin\OIDCLoginOption; +use OCA\OIDCLogin\Service\TokenService; use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IBootContext; use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\Bootstrap\IRegistrationContext; -use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent; use OCP\AppFramework\Utility\ITimeFactory; use OCP\IConfig; use OCP\IL10N; @@ -31,6 +30,10 @@ class Application extends App implements IBootstrap /** @var Config */ protected $config; + + /** @var TokenService */ + private $tokenService; + private $appName = 'oidc_login'; public function __construct() @@ -69,8 +72,6 @@ public function register(IRegistrationContext $context): void 'OCA\DAV\Connector\Sabre::addPlugin', '\OCA\OIDCLogin\WebDAV\BasicAuthBackend' ); - - $context->registerEventListener(BeforeTemplateRenderedEvent::class, BeforeTemplateRenderedListener::class); } public function boot(IBootContext $context): void @@ -79,6 +80,7 @@ public function boot(IBootContext $context): void $this->l = $container->query(IL10N::class); $this->url = $container->query(IURLGenerator::class); $this->config = $container->query(IConfig::class); + $this->tokenService = $container->query(TokenService::class); $request = $container->query(IRequest::class); // Check if automatic redirection is enabled @@ -125,6 +127,10 @@ public function boot(IBootContext $context): void }); } + if (!$this->tokenService->refreshTokens()) { + $userSession->logout(); + } + // Hide password change form if ($this->config->getSystemValue('oidc_login_hide_password_form', false)) { Util::addStyle($this->appName, 'oidc.hidepasswordform'); diff --git a/lib/Listeners/BeforeTemplateRenderedListener.php b/lib/Listeners/BeforeTemplateRenderedListener.php deleted file mode 100644 index ef116bc..0000000 --- a/lib/Listeners/BeforeTemplateRenderedListener.php +++ /dev/null @@ -1,47 +0,0 @@ -appName = $appName; - $this->userSession = $userSession; - $this->tokenService = $tokenService; - $this->session = $session; - } - - public function handle(Event $event): void - { - // If user not logged in or not an oidc session, nothing to do - if (!($event instanceof BeforeTemplateRenderedEvent) || !$this->userSession->isLoggedIn() || !$this->session->exists('is_oidc')) { - return; - } - - if (!$this->tokenService->refreshTokens()) { - $this->userSession->logout(); - } - } -} From 299d3e16c5c0e500b9d953c579caeb4dd310febc Mon Sep 17 00:00:00 2001 From: Akhil Date: Tue, 13 Dec 2022 18:38:31 +0530 Subject: [PATCH 07/14] use empty() --- lib/Service/TokenService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Service/TokenService.php b/lib/Service/TokenService.php index d1f5d03..cf20bb9 100644 --- a/lib/Service/TokenService.php +++ b/lib/Service/TokenService.php @@ -74,7 +74,7 @@ public function refreshTokens(): bool $refreshTokenExpiresIn = $this->session->get('oidc_refresh_token_expires_in'); $refreshToken = $this->session->get('oidc_refresh_token'); // If refresh token doesn't exist or refresh token has expired - if (!$refreshToken || (!empty($refreshTokenExpiresIn) && $now > $refreshTokenExpiresIn)) { + if (empty($refreshToken) || (!empty($refreshTokenExpiresIn) && $now > $refreshTokenExpiresIn)) { return false; } From 48588152f543f95ed690e6a922cdf82a60a8429e Mon Sep 17 00:00:00 2001 From: Akhil Date: Fri, 6 Jan 2023 13:59:01 +0530 Subject: [PATCH 08/14] Add setting oidc_refresh_tokens_enabled --- README.md | 6 ++++++ lib/AppInfo/Application.php | 3 ++- lib/Controller/LoginController.php | 5 ++++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index db869d5..cf9c221 100644 --- a/README.md +++ b/README.md @@ -209,6 +209,12 @@ $CONFIG = array ( // - 'plain' // The default value is empty, which won't apply the PKCE flow. 'oidc_login_code_challenge_method' => '', + + // If OIDC server has refresh tokens enabled and + // you want to manage session at OIDC server by storing + // and refreshing tokens. Defaults to false. + 'oidc_refresh_tokens_enabled' => false, + ); ``` ### Usage with [Keycloak](https://www.keycloak.org/) diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index fdf8b1d..a0737c4 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -127,7 +127,8 @@ public function boot(IBootContext $context): void }); } - if (!$this->tokenService->refreshTokens()) { + $refreshTokensEnabled = $this->config->getSystemValue('oidc_refresh_tokens_enabled', false); + if ($refreshTokensEnabled && !$this->tokenService->refreshTokens()) { $userSession->logout(); } diff --git a/lib/Controller/LoginController.php b/lib/Controller/LoginController.php index 65d9e62..8459aa5 100644 --- a/lib/Controller/LoginController.php +++ b/lib/Controller/LoginController.php @@ -94,8 +94,11 @@ public function oidc() $oidc->authenticate(); $tokenResponse = $oidc->getTokenResponse(); - $this->tokenService->storeTokens($tokenResponse); + $refreshTokensEnabled = $this->config->getSystemValue('oidc_refresh_tokens_enabled', false); + if ($refreshTokensEnabled) { + $this->tokenService->storeTokens($tokenResponse); + } $user = null; if ($this->config->getSystemValue('oidc_login_use_id_token', false)) { // Get user information from ID Token From 93a2ff5613be7231d7dc153641651049c76cedcb Mon Sep 17 00:00:00 2001 From: Akhil Date: Mon, 6 Feb 2023 01:09:17 +0530 Subject: [PATCH 09/14] Fixes according to comments Signed-off-by: Akhil --- lib/AppInfo/Application.php | 6 ++++- lib/Service/TokenService.php | 43 +++++++++++++++++++++++++++++------- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index a0737c4..0cf3ec6 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -106,6 +106,7 @@ public function boot(IBootContext $context): void // Disable password confirmation for user $session->set('last-password-confirm', $container->query(ITimeFactory::class)->getTime()); + $refreshTokensEnabled = $this->config->getSystemValue('oidc_refresh_tokens_enabled', false); /* Redirect to logout URL on completing logout If do not have logout URL, go to noredir on logout */ if ($logoutUrl = $session->get('oidc_logout_url', $noRedirLoginUrl)) { @@ -121,13 +122,16 @@ public function boot(IBootContext $context): void $session->close(); header('Clear-Site-Data: "cache", "storage"'); + if ($refreshTokensEnabled) { + $logoutUrl = $this->tokenService->getLogoutUrl(); + } + header('Location: '.$logoutUrl); exit; }); } - $refreshTokensEnabled = $this->config->getSystemValue('oidc_refresh_tokens_enabled', false); if ($refreshTokensEnabled && !$this->tokenService->refreshTokens()) { $userSession->logout(); } diff --git a/lib/Service/TokenService.php b/lib/Service/TokenService.php index cf20bb9..775af3b 100644 --- a/lib/Service/TokenService.php +++ b/lib/Service/TokenService.php @@ -7,6 +7,7 @@ use OCP\IConfig; use OCP\ISession; use OCP\IURLGenerator; +use OCP\ILogger; class TokenService { @@ -22,16 +23,22 @@ class TokenService /** @var IURLGenerator */ private $urlGenerator; + /** @var ILogger */ + private ILogger $logger; + + public function __construct( $appName, ISession $session, IConfig $config, IURLGenerator $urlGenerator, + ILogger $logger ) { $this->appName = $appName; $this->session = $session; $this->config = $config; $this->urlGenerator = $urlGenerator; + $this->logger = $logger; } /** @@ -64,44 +71,64 @@ public function createOIDCClient($callbackUrl = '') */ public function refreshTokens(): bool { - $accessTokenExpiresIn = $this->session->get('oidc_access_token_expires_in'); + $accessTokenExpiresAt = $this->session->get('oidc_access_token_expires_at'); $now = time(); // If access token hasn't expired yet - if (!empty($accessTokenExpiresIn) && $now < $accessTokenExpiresIn) { + $this->logger->debug("checking if token should be refreshed", ["expires" => $accessTokenExpiresAt]); + + if (!empty($accessTokenExpiresAt) && $now < $accessTokenExpiresAt) { + $this->logger->debug("no token expiration or not yet expired"); return true; } - $refreshTokenExpiresIn = $this->session->get('oidc_refresh_token_expires_in'); $refreshToken = $this->session->get('oidc_refresh_token'); // If refresh token doesn't exist or refresh token has expired - if (empty($refreshToken) || (!empty($refreshTokenExpiresIn) && $now > $refreshTokenExpiresIn)) { + if (empty($refreshToken)) { + $this->logger->debug("refresh token not found"); return false; } $callbackUrl = $this->urlGenerator->linkToRouteAbsolute($this->appName.'.login.oidc'); // Refresh the tokens, return false on failure + $this->logger->debug("refreshing token"); try { $oidc = $this->createOIDCClient($callbackUrl); $tokenResponse = $oidc->refreshToken($refreshToken); $this->storeTokens($tokenResponse); + if ($this->session->get('oidc_logout_url')) { + $this->logger->debug("updating logout url"); + $oidc_login_logout_url = $this->config->getSystemValue('oidc_login_logout_url', false); + $logoutUrl = $oidc->getEndSessionUrl($oidc_login_logout_url); + $this->session->set('oidc_logout_url', $logoutUrl); + } + + $this->logger->debug("token refreshed"); return true; } catch (Exception $e) { + $this->logger->error("token refresh failed", ['exception' => $e]); return false; } } public function storeTokens(object $tokenResponse): void { + $oldAccessToken = $this->session->get('oidc_access_token'); + $this->logger->debug("old access token: " . $oldAccessToken); + $this->logger->debug("new access token: " . $tokenResponse->access_token); + $this->session->set('oidc_access_token', $tokenResponse->access_token); $this->session->set('oidc_refresh_token', $tokenResponse->refresh_token); $now = time(); - $accessTokenExpiresIn = $tokenResponse->expires_in + $now; - $refreshTokenExpiresIn = $now + $tokenResponse->refresh_expires_in - 5; + $accessTokenExpiresAt = $tokenResponse->expires_in + $now; + + $this->session->set('oidc_access_token_expires_at', $accessTokenExpiresIn); + } - $this->session->set('oidc_access_token_expires_in', $accessTokenExpiresIn); - $this->session->set('oidc_refresh_token_expires_in', $refreshTokenExpiresIn); + public function getLogoutUrl() { + + return $this->session->get('oidc_logout_url'); } } From 331748e28e65de31149969f9cc4cc4dcfe51678e Mon Sep 17 00:00:00 2001 From: Akhil Date: Wed, 14 Jun 2023 14:31:55 +0530 Subject: [PATCH 10/14] Run php cs fixer --- lib/Service/TokenService.php | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/lib/Service/TokenService.php b/lib/Service/TokenService.php index 775af3b..6a515a1 100644 --- a/lib/Service/TokenService.php +++ b/lib/Service/TokenService.php @@ -5,9 +5,9 @@ use Exception; use OCA\OIDCLogin\Provider\OpenIDConnectClient; use OCP\IConfig; +use OCP\ILogger; use OCP\ISession; use OCP\IURLGenerator; -use OCP\ILogger; class TokenService { @@ -23,10 +23,8 @@ class TokenService /** @var IURLGenerator */ private $urlGenerator; - /** @var ILogger */ private ILogger $logger; - public function __construct( $appName, ISession $session, @@ -74,40 +72,45 @@ public function refreshTokens(): bool $accessTokenExpiresAt = $this->session->get('oidc_access_token_expires_at'); $now = time(); // If access token hasn't expired yet - $this->logger->debug("checking if token should be refreshed", ["expires" => $accessTokenExpiresAt]); + $this->logger->debug('checking if token should be refreshed', ['expires' => $accessTokenExpiresAt]); if (!empty($accessTokenExpiresAt) && $now < $accessTokenExpiresAt) { - $this->logger->debug("no token expiration or not yet expired"); + $this->logger->debug('no token expiration or not yet expired'); + return true; } $refreshToken = $this->session->get('oidc_refresh_token'); // If refresh token doesn't exist or refresh token has expired if (empty($refreshToken)) { - $this->logger->debug("refresh token not found"); + $this->logger->debug('refresh token not found'); + return false; } $callbackUrl = $this->urlGenerator->linkToRouteAbsolute($this->appName.'.login.oidc'); // Refresh the tokens, return false on failure - $this->logger->debug("refreshing token"); + $this->logger->debug('refreshing token'); + try { $oidc = $this->createOIDCClient($callbackUrl); $tokenResponse = $oidc->refreshToken($refreshToken); $this->storeTokens($tokenResponse); if ($this->session->get('oidc_logout_url')) { - $this->logger->debug("updating logout url"); + $this->logger->debug('updating logout url'); $oidc_login_logout_url = $this->config->getSystemValue('oidc_login_logout_url', false); $logoutUrl = $oidc->getEndSessionUrl($oidc_login_logout_url); $this->session->set('oidc_logout_url', $logoutUrl); } - $this->logger->debug("token refreshed"); + $this->logger->debug('token refreshed'); + return true; } catch (Exception $e) { - $this->logger->error("token refresh failed", ['exception' => $e]); + $this->logger->error('token refresh failed', ['exception' => $e]); + return false; } } @@ -115,8 +118,8 @@ public function refreshTokens(): bool public function storeTokens(object $tokenResponse): void { $oldAccessToken = $this->session->get('oidc_access_token'); - $this->logger->debug("old access token: " . $oldAccessToken); - $this->logger->debug("new access token: " . $tokenResponse->access_token); + $this->logger->debug('old access token: '.$oldAccessToken); + $this->logger->debug('new access token: '.$tokenResponse->access_token); $this->session->set('oidc_access_token', $tokenResponse->access_token); $this->session->set('oidc_refresh_token', $tokenResponse->refresh_token); @@ -127,8 +130,8 @@ public function storeTokens(object $tokenResponse): void $this->session->set('oidc_access_token_expires_at', $accessTokenExpiresIn); } - public function getLogoutUrl() { - + public function getLogoutUrl() + { return $this->session->get('oidc_logout_url'); } } From e75cf44fe2ba75a9d8b474c72250692c05d0a969 Mon Sep 17 00:00:00 2001 From: Akhil Date: Tue, 25 Jul 2023 23:04:33 +0530 Subject: [PATCH 11/14] Check if session is active if autologin is enabled Signed-off-by: Akhil --- lib/AppInfo/Application.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 0cf3ec6..82899b7 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -133,7 +133,16 @@ public function boot(IBootContext $context): void } if ($refreshTokensEnabled && !$this->tokenService->refreshTokens()) { - $userSession->logout(); + // See if session is active if autologin is enabled; else logout + if ($useLoginRedirect) { + $loginLink = OIDCLoginOption::getLoginLink($request, $this->url); + header('Location: '.$loginLink); + + exit; + } else { + $userSession->logout(); + + } } // Hide password change form From 8140d88adb2ada1da75d7d5aae4de594c5c97113 Mon Sep 17 00:00:00 2001 From: Akhil Date: Tue, 1 Aug 2023 20:47:32 +0530 Subject: [PATCH 12/14] Disable refresh tokens only if explicitly mentioned Signed-off-by: Akhil --- README.md | 8 +++----- lib/AppInfo/Application.php | 15 +++++++-------- lib/Controller/LoginController.php | 26 +++++++++++++++++++++++++- lib/Service/TokenService.php | 2 +- 4 files changed, 36 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index cf9c221..45a7c59 100644 --- a/README.md +++ b/README.md @@ -210,11 +210,9 @@ $CONFIG = array ( // The default value is empty, which won't apply the PKCE flow. 'oidc_login_code_challenge_method' => '', - // If OIDC server has refresh tokens enabled and - // you want to manage session at OIDC server by storing - // and refreshing tokens. Defaults to false. - 'oidc_refresh_tokens_enabled' => false, - + // If you want to explicitly disable usage of access/refresh + // tokens. Defaults to false. + 'oidc_refresh_tokens_disabled' => false, ); ``` ### Usage with [Keycloak](https://www.keycloak.org/) diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 82899b7..e137b84 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -106,11 +106,11 @@ public function boot(IBootContext $context): void // Disable password confirmation for user $session->set('last-password-confirm', $container->query(ITimeFactory::class)->getTime()); - $refreshTokensEnabled = $this->config->getSystemValue('oidc_refresh_tokens_enabled', false); + $refreshTokensEnabled = $session->exists('oidc_refresh_tokens_enabled'); /* Redirect to logout URL on completing logout If do not have logout URL, go to noredir on logout */ if ($logoutUrl = $session->get('oidc_logout_url', $noRedirLoginUrl)) { - $userSession->listen('\OC\User', 'postLogout', function () use ($logoutUrl, $session) { + $userSession->listen('\OC\User', 'postLogout', function () use ($logoutUrl, $session, $refreshTokensEnabled) { // Do nothing if this is a CORS request if ($this->getContainer()->query(ControllerMethodReflector::class)->hasAnnotation('CORS')) { return; @@ -119,12 +119,13 @@ public function boot(IBootContext $context): void // Properly close the session and clear the browsers storage data before // redirecting to the logout url. $session->set('clearingExecutionContexts', '1'); - $session->close(); - header('Clear-Site-Data: "cache", "storage"'); - if ($refreshTokensEnabled) { + // Refresh tokens before logout + $this->tokenService->refreshTokens(); $logoutUrl = $this->tokenService->getLogoutUrl(); } + $session->close(); + header('Clear-Site-Data: "cache", "storage"'); header('Location: '.$logoutUrl); @@ -139,10 +140,8 @@ public function boot(IBootContext $context): void header('Location: '.$loginLink); exit; - } else { - $userSession->logout(); - } + $userSession->logout(); } // Hide password change form diff --git a/lib/Controller/LoginController.php b/lib/Controller/LoginController.php index 8459aa5..3271356 100644 --- a/lib/Controller/LoginController.php +++ b/lib/Controller/LoginController.php @@ -94,11 +94,20 @@ public function oidc() $oidc->authenticate(); $tokenResponse = $oidc->getTokenResponse(); - $refreshTokensEnabled = $this->config->getSystemValue('oidc_refresh_tokens_enabled', false); + + $refreshTokensEnabled = false; + $refreshTokensDisabledExplicitly = $this->config->getSystemValue('oidc_refresh_tokens_disabled', false); + + if (!$refreshTokensDisabledExplicitly) { + $scopes = $oidc->getScopes(); + $refreshTokensEnabled = $this->shouldEnableRefreshTokens($scopes, $tokenResponse); + } if ($refreshTokensEnabled) { + $this->session->set('oidc_refresh_tokens_enabled', 1); $this->tokenService->storeTokens($tokenResponse); } + $user = null; if ($this->config->getSystemValue('oidc_login_use_id_token', false)) { // Get user information from ID Token @@ -177,4 +186,19 @@ private function login($profile) return new RedirectResponse($this->urlGenerator->getAbsoluteURL($redir)); } + + private function shouldEnableRefreshTokens(array $scopes, object $tokenResponse): bool + { + foreach ($scopes as $scope) { + if (str_contains($scope, 'offline_access')) { + return true; + } + } + + if (isset($tokenResponse->refresh_token) && !empty($tokenResponse->refresh_token)) { + return true; + } + + return false; + } } diff --git a/lib/Service/TokenService.php b/lib/Service/TokenService.php index 6a515a1..991b122 100644 --- a/lib/Service/TokenService.php +++ b/lib/Service/TokenService.php @@ -127,7 +127,7 @@ public function storeTokens(object $tokenResponse): void $now = time(); $accessTokenExpiresAt = $tokenResponse->expires_in + $now; - $this->session->set('oidc_access_token_expires_at', $accessTokenExpiresIn); + $this->session->set('oidc_access_token_expires_at', $accessTokenExpiresAt); } public function getLogoutUrl() From 24e3a2d09c8afa2bcd19acca0f48fd0ed344db27 Mon Sep 17 00:00:00 2001 From: Akhil Date: Wed, 2 Aug 2023 01:26:18 +0530 Subject: [PATCH 13/14] Fire event on regenerating access token Signed-off-by: Akhil --- lib/Events/AccessTokenUpdatedEvent.php | 31 ++++++++++++++++++++++++++ lib/Service/TokenService.php | 11 ++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 lib/Events/AccessTokenUpdatedEvent.php diff --git a/lib/Events/AccessTokenUpdatedEvent.php b/lib/Events/AccessTokenUpdatedEvent.php new file mode 100644 index 0000000..70b9973 --- /dev/null +++ b/lib/Events/AccessTokenUpdatedEvent.php @@ -0,0 +1,31 @@ +accessToken = $accessToken; + } + + public function getAccessToken(): string + { + return $this->accessToken; + } +} diff --git a/lib/Service/TokenService.php b/lib/Service/TokenService.php index 991b122..3eada98 100644 --- a/lib/Service/TokenService.php +++ b/lib/Service/TokenService.php @@ -1,9 +1,13 @@ appName = $appName; $this->session = $session; $this->config = $config; $this->urlGenerator = $urlGenerator; $this->logger = $logger; + $this->dispatcher = $dispatcher; } /** @@ -128,6 +136,7 @@ public function storeTokens(object $tokenResponse): void $accessTokenExpiresAt = $tokenResponse->expires_in + $now; $this->session->set('oidc_access_token_expires_at', $accessTokenExpiresAt); + $this->dispatcher->dispatchTyped(new AccessTokenUpdatedEvent($tokenResponse->access_token)); } public function getLogoutUrl() From 0ea84a296ead8cdb9e83b17ee9e03c8f8efae098 Mon Sep 17 00:00:00 2001 From: Akhil Date: Thu, 3 Aug 2023 00:09:43 +0530 Subject: [PATCH 14/14] Fix logout and token refresh --- lib/AppInfo/Application.php | 15 +++++++++------ lib/Controller/LoginController.php | 18 +++--------------- lib/Service/TokenService.php | 23 +++++++++++++---------- 3 files changed, 25 insertions(+), 31 deletions(-) diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index e137b84..7f17763 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -110,7 +110,15 @@ public function boot(IBootContext $context): void /* Redirect to logout URL on completing logout If do not have logout URL, go to noredir on logout */ if ($logoutUrl = $session->get('oidc_logout_url', $noRedirLoginUrl)) { - $userSession->listen('\OC\User', 'postLogout', function () use ($logoutUrl, $session, $refreshTokensEnabled) { + $userSession->listen('\OC\User', 'logout', function () use (&$logoutUrl, $refreshTokensEnabled, $session) { + if ($refreshTokensEnabled) { + // Refresh tokens before logout + $this->tokenService->refreshTokens(); + $logoutUrl = $session->get('oidc_logout_url'); + } + }); + + $userSession->listen('\OC\User', 'postLogout', function () use ($logoutUrl, $session) { // Do nothing if this is a CORS request if ($this->getContainer()->query(ControllerMethodReflector::class)->hasAnnotation('CORS')) { return; @@ -119,11 +127,6 @@ public function boot(IBootContext $context): void // Properly close the session and clear the browsers storage data before // redirecting to the logout url. $session->set('clearingExecutionContexts', '1'); - if ($refreshTokensEnabled) { - // Refresh tokens before logout - $this->tokenService->refreshTokens(); - $logoutUrl = $this->tokenService->getLogoutUrl(); - } $session->close(); header('Clear-Site-Data: "cache", "storage"'); diff --git a/lib/Controller/LoginController.php b/lib/Controller/LoginController.php index 3271356..8f4e665 100644 --- a/lib/Controller/LoginController.php +++ b/lib/Controller/LoginController.php @@ -1,5 +1,7 @@ requestUserInfo(); } - $this->prepareLogout($oidc); + $this->tokenService->prepareLogout($oidc); // Convert to PHP array and process return $this->authSuccess(json_decode(json_encode($user), true)); @@ -144,20 +146,6 @@ private function authSuccess($profile) return $this->login($profile); } - private function prepareLogout($oidc) - { - if ($oidc_login_logout_url = $this->config->getSystemValue('oidc_login_logout_url', false)) { - if ($this->config->getSystemValue('oidc_login_end_session_redirect', false)) { - $signout_url = $oidc->getEndSessionUrl($oidc_login_logout_url); - $this->session->set('oidc_logout_url', $signout_url); - } else { - $this->session->set('oidc_logout_url', $oidc_login_logout_url); - } - } else { - $this->session->set('oidc_logout_url', false); - } - } - private function login($profile) { // Redirect if already logged in diff --git a/lib/Service/TokenService.php b/lib/Service/TokenService.php index 3eada98..830c18b 100644 --- a/lib/Service/TokenService.php +++ b/lib/Service/TokenService.php @@ -105,16 +105,10 @@ public function refreshTokens(): bool $oidc = $this->createOIDCClient($callbackUrl); $tokenResponse = $oidc->refreshToken($refreshToken); $this->storeTokens($tokenResponse); - - if ($this->session->get('oidc_logout_url')) { - $this->logger->debug('updating logout url'); - $oidc_login_logout_url = $this->config->getSystemValue('oidc_login_logout_url', false); - $logoutUrl = $oidc->getEndSessionUrl($oidc_login_logout_url); - $this->session->set('oidc_logout_url', $logoutUrl); - } - $this->logger->debug('token refreshed'); + $this->prepareLogout($oidc); + return true; } catch (Exception $e) { $this->logger->error('token refresh failed', ['exception' => $e]); @@ -139,8 +133,17 @@ public function storeTokens(object $tokenResponse): void $this->dispatcher->dispatchTyped(new AccessTokenUpdatedEvent($tokenResponse->access_token)); } - public function getLogoutUrl() + public function prepareLogout(OpenIDConnectClient $oidc) { - return $this->session->get('oidc_logout_url'); + if ($oidc_login_logout_url = $this->config->getSystemValue('oidc_login_logout_url', false)) { + if ($this->config->getSystemValue('oidc_login_end_session_redirect', false)) { + $signout_url = $oidc->getEndSessionUrl($oidc_login_logout_url); + $this->session->set('oidc_logout_url', $signout_url); + } else { + $this->session->set('oidc_logout_url', $oidc_login_logout_url); + } + } else { + $this->session->set('oidc_logout_url', false); + } } }