]> 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 fc0c0029856e69091d252ea77f3c6343b80bcea8..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;
     }
 
     /**