]> BookStack Code Mirror - bookstack/commitdiff
Merge branch 'fix/oidc-logout' into development
authorDan Brown <redacted>
Wed, 6 Dec 2023 12:14:43 +0000 (12:14 +0000)
committerDan Brown <redacted>
Wed, 6 Dec 2023 12:14:43 +0000 (12:14 +0000)
.env.example.complete
app/Access/Controllers/OidcController.php
app/Access/Oidc/OidcService.php
app/Config/oidc.php
resources/views/layouts/parts/header-user-menu.blade.php
routes/web.php

index 0853bd1fecbba729352d46e46ed2c8ec9dde0d4c..0667cb75bd4ad1f85069c3caf700ece1bfd61ca1 100644 (file)
@@ -274,6 +274,10 @@ OIDC_GROUPS_CLAIM=groups
 OIDC_REMOVE_FROM_GROUPS=false
 OIDC_EXTERNAL_ID_CLAIM=sub
 
+# OIDC Logout Feature: Its value should be value of end_session_endpoint from <issuer>/.well-known/openid-configuration 
+OIDC_END_SESSION_ENDPOINT=null
+
+
 # Disable default third-party services such as Gravatar and Draw.IO
 # Service-specific options will override this option
 DISABLE_EXTERNAL_SERVICES=false
index e8c94493425f4a81d0b29dc65adc3385d47c9c46..083e83e35773131a199b0d34fb815247d10065bf 100644 (file)
@@ -63,4 +63,18 @@ class OidcController extends Controller
 
         return redirect()->intended();
     }
+
+    /**
+     * OIDC Logout Feature: Start the authorization logout flow via OIDC.
+     */
+    public function logout()
+    {
+        try {
+            return $this->oidcService->logout();
+        } catch (OidcException $exception) {
+            $this->showErrorNotification($exception->getMessage());
+            return redirect('/logout');
+        }
+    }
+
 }
index 8778cbd98c2e5dcfc17e923368eb7626e0838146..1067b0832d44086e41b58cafe25521ec939385e1 100644 (file)
@@ -217,6 +217,12 @@ class OidcService
             $settings->keys,
         );
 
+        // OIDC Logout Feature: Temporarily save token in session 
+        $access_token_for_logout = $idTokenText;
+        session()->put("oidctoken", $access_token_for_logout);
+
+
+
         $returnClaims = Theme::dispatch(ThemeEvents::OIDC_ID_TOKEN_PRE_VALIDATE, $idToken->getAllClaims(), [
             'access_token' => $accessToken->getToken(),
             'expires_in' => $accessToken->getExpires(),
@@ -284,4 +290,37 @@ class OidcService
     {
         return $this->config()['user_to_groups'] !== false;
     }
+
+
+    /**
+     * OIDC Logout Feature: Initiate a logout flow.
+     *
+     * @throws OidcException
+     *
+     * @return string
+     */
+    public function logout() {
+
+        $config = $this->config();
+        $app_url = env('APP_URL', '');
+        $end_session_endpoint = $config["end_session_endpoint"];
+
+        $oidctoken = session()->get("oidctoken");
+        session()->invalidate();
+
+        if (str_contains($app_url, 'https://')) { 
+             $protocol = 'https://';
+        } else {
+             $protocol = 'http://';
+        }
+
+
+
+        return redirect($end_session_endpoint.'?id_token_hint='.$oidctoken."&post_logout_redirect_uri=".$protocol.$_SERVER['HTTP_HOST']."/");
+
+
+    }
+
+
+
 }
index b28b8a41a826a8faf5df82767206aa0d350df752..0410588b829efa449622a0e82fb3501f74d5e5c3 100644 (file)
@@ -47,4 +47,9 @@ return [
     'groups_claim' => env('OIDC_GROUPS_CLAIM', 'groups'),
     // When syncing groups, remove any groups that no longer match. Otherwise sync only adds new groups.
     'remove_from_groups' => env('OIDC_REMOVE_FROM_GROUPS', false),
+
+    // OIDC Logout Feature: OAuth2 end_session_endpoint
+    'end_session_endpoint' => env('OIDC_END_SESSION_ENDPOINT', null),
+
 ];
+
index 0440e43d037cbf2e3f29e2140379e104dd074958..ff28f1cfb911bdd216728d08430319a26a428f23 100644 (file)
         </li>
         <li><hr></li>
         <li>
-            <form action="{{ url(config('auth.method') === 'saml2' ? '/saml2/logout' : '/logout') }}"
-                  method="post">
-                {{ csrf_field() }}
-                <button class="icon-item" data-shortcut="logout">
-                    @icon('logout')
-                    <div>{{ trans('auth.logout') }}</div>
-                </button>
-            </form>
+            <?php
+// OIDC Logout Feature: Use /oidc/logout if authentication method is oidc.
+            if (config('auth.method') === 'oidc')  {
+                ?>
+                <form action="/oidc/logout"
+                    method="get">
+                    <?php
+// OIDC Logout Feature: Use /oidc/logout if authentication method is oidc.
+                } else {
+                    ?>
+                <form action="{{ url(config('auth.method') === 'saml2' ? '/saml2/logout' : '/logout') }}"
+                      method="post">
+                        <?php
+// OIDC Logout Feature: Use /oidc/logout if authentication method is oidc.
+                    }
+                    ?>
+                    {{ csrf_field() }}
+                    <button class="icon-item" data-shortcut="logout">
+                        @icon('logout')
+                        <div>{{ trans('auth.logout') }}</div>
+                    </button>
+                </form>
         </li>
     </ul>
 </div>
\ No newline at end of file
index c86509c68bf78c559bae298652970547b75c9a77..a02b19ca331401673597476380a61177ad2484cd 100644 (file)
@@ -332,6 +332,8 @@ Route::get('/saml2/acs', [AccessControllers\Saml2Controller::class, 'processAcs'
 // OIDC routes
 Route::post('/oidc/login', [AccessControllers\OidcController::class, 'login']);
 Route::get('/oidc/callback', [AccessControllers\OidcController::class, 'callback']);
+// OIDC Logout Feature: Added to cater OIDC logout
+Route::get('/oidc/logout', [AccessControllers\OidcController::class, 'logout']);
 
 // User invitation routes
 Route::get('/register/invite/{token}', [AccessControllers\UserInviteController::class, 'showSetPassword']);