]> BookStack Code Mirror - bookstack/blobdiff - app/Auth/Access/OpenIdService.php
Default OpenID display name set to standard value
[bookstack] / app / Auth / Access / OpenIdService.php
index 14b6ac9a5d4632ca321493a5d10fd68702b3ec5d..70df963f523eecbe22bf860e9c13637dce7eacd4 100644 (file)
@@ -8,7 +8,6 @@ use Exception;
 use Lcobucci\JWT\Token;
 use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
 use OpenIDConnectClient\AccessToken;
-use OpenIDConnectClient\Exception\InvalidTokenException;
 use OpenIDConnectClient\OpenIDConnectProvider;
 
 /**
@@ -63,41 +62,72 @@ class OpenIdService extends ExternalAuthService
     {
         // Retrieve access token for current session
         $json = session()->get('openid_token');
-        $accessToken = new AccessToken(json_decode($json, true));
 
-        // Check if both the access token and the ID token (if present) are unexpired
-        $idToken = $accessToken->getIdToken();
-        if (!$accessToken->hasExpired() && (!$idToken || !$idToken->isExpired())) {
+        // If no access token was found, reject the refresh
+        if (!$json) {
+            $this->actionLogout();
+            return false;
+        }
+
+        $accessToken = new AccessToken(json_decode($json, true) ?? []);
+
+        // If the token is not expired, refreshing isn't necessary
+        if ($this->isUnexpired($accessToken)) {
             return true;
         }
 
-        // If no refresh token available, logout
-        if ($accessToken->getRefreshToken() === null) {
+        // Try to obtain refreshed access token
+        try {
+            $newAccessToken = $this->refreshAccessToken($accessToken);
+        } catch (\Exception $e) {
+            // Log out if an unknown problem arises
+            $this->actionLogout();
+            throw $e;
+        }
+
+        // If a token was obtained, update the access token, otherwise log out
+        if ($newAccessToken !== null) {
+            session()->put('openid_token', json_encode($newAccessToken));
+            return true;
+        } else {
             $this->actionLogout();
             return false;
         }
+    }
+
+    /**
+     * Check whether an access token or OpenID token isn't expired.
+     */
+    protected function isUnexpired(AccessToken $accessToken): bool
+    {
+        $idToken = $accessToken->getIdToken();
+        
+        $accessTokenUnexpired = $accessToken->getExpires() && !$accessToken->hasExpired();
+        $idTokenUnexpired = !$idToken || !$idToken->isExpired(); 
+
+        return $accessTokenUnexpired && $idTokenUnexpired;
+    }
+
+    /**
+     * Generate an updated access token, through the associated refresh token.
+     * @throws Error
+     */
+    protected function refreshAccessToken(AccessToken $accessToken): ?AccessToken
+    {
+        // If no refresh token available, abort
+        if ($accessToken->getRefreshToken() === null) {
+            return null;
+        }
 
         // ID token or access token is expired, we refresh it using the refresh token
         try {
-            $provider = $this->getProvider();
-
-            $accessToken = $provider->getAccessToken('refresh_token', [
+            return $this->getProvider()->getAccessToken('refresh_token', [
                 'refresh_token' => $accessToken->getRefreshToken(),
             ]);
         } catch (IdentityProviderException $e) {
-            // Refreshing failed, logout
-            $this->actionLogout();
-            return false;
-        } catch (\Exception $e) {
-            // Unknown error, logout and throw
-            $this->actionLogout();
-            throw $e;
+            // Refreshing failed
+            return null;
         }
-
-        // A valid token was obtained, we update the access token
-        session()->put('openid_token', json_encode($accessToken));
-
-        return true;
     }
 
     /**
@@ -139,6 +169,7 @@ class OpenIdService extends ExternalAuthService
      */
     protected function getProvider(): OpenIDConnectProvider
     {
+        // Setup settings
         $settings = $this->config['openid'];
         $overrides = $this->config['openid_overrides'] ?? [];
 
@@ -149,12 +180,27 @@ class OpenIdService extends ExternalAuthService
         $openIdSettings = $this->loadOpenIdDetails();
         $settings = array_replace_recursive($settings, $openIdSettings, $overrides);
 
-        $signer = new \Lcobucci\JWT\Signer\Rsa\Sha256();
-        return new OpenIDConnectProvider($settings, ['signer' => $signer]);
+        // Setup services
+        $services = $this->loadOpenIdServices();
+        $overrides = $this->config['openid_services'] ?? [];
+
+        $services = array_replace_recursive($services, $overrides);
+
+        return new OpenIDConnectProvider($settings, $services);
+    }
+
+    /**
+     * Load services utilized by the OpenID Connect provider.
+     */
+    protected function loadOpenIdServices(): array
+    {
+        return [
+            'signer' => new \Lcobucci\JWT\Signer\Rsa\Sha256(),
+        ];
     }
 
     /**
-     * Load dynamic service provider options required by the onelogin toolkit.
+     * Load dynamic service provider options required by the OpenID Connect provider.
      */
     protected function loadOpenIdDetails(): array
     {