From 98e521eeaee9655d714ab7fb1c7f805404384a65 Mon Sep 17 00:00:00 2001
From: Jan-Hendrik Willms <tleilax+studip@gmail.com>
Date: Mon, 2 Sep 2024 12:46:06 +0000
Subject: [PATCH] provide generic logout for sso auth plugins, fixes #3624

Closes #3624

Merge request studip/studip!3345
---
 config/config_defaults.inc.php              | 22 ++++++++++++---------
 lib/classes/auth_plugins/StudipAuthCAS.php  |  2 +-
 lib/classes/auth_plugins/StudipAuthOIDC.php |  6 +++++-
 lib/classes/auth_plugins/StudipAuthSSO.php  | 11 +++++++++--
 lib/classes/auth_plugins/StudipAuthShib.php |  9 +++++++++
 public/logout.php                           | 17 ++++++++--------
 6 files changed, 45 insertions(+), 22 deletions(-)

diff --git a/config/config_defaults.inc.php b/config/config_defaults.inc.php
index ce484922be6..e4aed075eb6 100644
--- a/config/config_defaults.inc.php
+++ b/config/config_defaults.inc.php
@@ -368,15 +368,19 @@ $STUDIP_AUTH_CONFIG_LTI = [
     ]
 ];
 
-$STUDIP_AUTH_CONFIG_SHIB = array("session_initiator" => "https://sp.studip.de/Shibboleth.sso/WAYF/DEMO",
-                                        "validate_url" => "https://sp.studip.de/auth/studip-sp.php",
-                                        "local_domain" => "studip.de",
-                                        "user_data_mapping" =>
-                                                array(  "auth_user_md5.username" => array("callback" => "dummy", "map_args" => ""),
-                                                        "auth_user_md5.password" => array("callback" => "dummy", "map_args" => ""),
-                                                        "auth_user_md5.Vorname" => array("callback" => "getUserData", "map_args" => "givenname"),
-                                                        "auth_user_md5.Nachname" => array("callback" => "getUserData", "map_args" => "surname"),
-                                                        "auth_user_md5.Email" => array("callback" => "getUserData", "map_args" => "email")));
+$STUDIP_AUTH_CONFIG_SHIB = [
+    'session_initiator' => 'https://sp.studip.de/Shibboleth.sso/WAYF/DEMO',
+    'validate_url'      => 'https://sp.studip.de/auth/studip-sp.php',
+    'logout_url'        => 'https://sp.studip.de/Shibboleth.sso/Logout',
+    'local_domain'      => 'studip.de',
+    'user_data_mapping' => [
+        'auth_user_md5.username' => ['callback' => 'dummy', 'map_args' => ''],
+        'auth_user_md5.password' => ['callback' => 'dummy', 'map_args' => ''],
+        'auth_user_md5.Vorname'  => ['callback' => 'getUserData', 'map_args' => 'givenname'],
+        'auth_user_md5.Nachname' => ['callback' => 'getUserData', 'map_args' => 'surname'],
+        'auth_user_md5.Email'    => ['callback' => 'getUserData', 'map_args' => 'email']
+    ],
+];
 
 $STUDIP_AUTH_CONFIG_IP = array('allowed_users' =>
     array ('root' => array('127.0.0.1', '::1')));
diff --git a/lib/classes/auth_plugins/StudipAuthCAS.php b/lib/classes/auth_plugins/StudipAuthCAS.php
index 29deb75bfc7..129cbd5aa81 100644
--- a/lib/classes/auth_plugins/StudipAuthCAS.php
+++ b/lib/classes/auth_plugins/StudipAuthCAS.php
@@ -80,7 +80,7 @@ class StudipAuthCAS extends StudipAuthSSO
         return $this->userdata->getUserData($key, phpCAS::getUser());
     }
 
-    function logout()
+    public function logout(): void
     {
         // do a global cas logout
         phpCAS::client(CAS_VERSION_2_0, $this->host, $this->port, $this->uri, false);
diff --git a/lib/classes/auth_plugins/StudipAuthOIDC.php b/lib/classes/auth_plugins/StudipAuthOIDC.php
index b26c17b0f94..1c77cb4791f 100644
--- a/lib/classes/auth_plugins/StudipAuthOIDC.php
+++ b/lib/classes/auth_plugins/StudipAuthOIDC.php
@@ -68,7 +68,6 @@ class StudipAuthOIDC extends StudipAuthSSO
      */
     public function verifyUsername($username)
     {
-
         $this->oidc->authenticate();
         $this->userdata = (array)$this->oidc->requestUserInfo();
         if (isset($this->userdata['sub'])) {
@@ -109,4 +108,9 @@ class StudipAuthOIDC extends StudipAuthSSO
     {
         return $this->userdata[$key];
     }
+
+    public function logout(): void
+    {
+        $this->oidc->signOut($this->oidc->getIdToken(), null);
+    }
 }
diff --git a/lib/classes/auth_plugins/StudipAuthSSO.php b/lib/classes/auth_plugins/StudipAuthSSO.php
index dd6af11387b..2cb0e146ae9 100644
--- a/lib/classes/auth_plugins/StudipAuthSSO.php
+++ b/lib/classes/auth_plugins/StudipAuthSSO.php
@@ -36,7 +36,7 @@ abstract class StudipAuthSSO extends StudipAuthAbstract
      * Check whether this user can be authenticated. The default
      * implementation just checks whether $username is not empty.
      */
-    function isAuthenticated ($username, $password)
+    public function isAuthenticated ($username, $password)
     {
         return !empty($username);
     }
@@ -44,8 +44,15 @@ abstract class StudipAuthSSO extends StudipAuthAbstract
     /**
      * SSO auth plugins cannot determine if a username is used.
      */
-    function isUsedUsername ($username)
+    public function isUsedUsername ($username)
     {
         return false;
     }
+
+    /**
+     * Use this to log out the user
+     */
+    public function logout(): void
+    {
+    }
 }
diff --git a/lib/classes/auth_plugins/StudipAuthShib.php b/lib/classes/auth_plugins/StudipAuthShib.php
index 135b3f6f878..5548e92c14d 100644
--- a/lib/classes/auth_plugins/StudipAuthShib.php
+++ b/lib/classes/auth_plugins/StudipAuthShib.php
@@ -18,6 +18,7 @@ class StudipAuthShib extends StudipAuthSSO
     public $local_domain;
     public $session_initiator;
     public $validate_url;
+    public ?string $logout_url = null;
     public $userdata;
     public $username_attribute = 'username';
 
@@ -136,4 +137,12 @@ class StudipAuthShib extends StudipAuthSSO
 
         return $data[0];
     }
+
+    public function logout(): void
+    {
+        if (!empty($this->logout_url)) {
+            header('Location: ' . URLHelper::getURL($this->logout_url, ['return' => Request::url()]));
+            exit();
+        }
+    }
 }
diff --git a/public/logout.php b/public/logout.php
index 2f8fcd8c58e..c2722a24fcf 100644
--- a/public/logout.php
+++ b/public/logout.php
@@ -42,12 +42,10 @@ if ($auth->auth['uid'] !== 'nobody') {
     $_language = $_SESSION['_language'];
     $contrast = UserConfig::get($GLOBALS['user']->id)->USER_HIGH_CONTRAST;
 
-    // TODO this needs to be generalized or removed
-    //erweiterung cas
-    if ($auth->auth['auth_plugin'] === 'cas') {
-        $casauth = StudipAuthAbstract::GetInstance('cas');
-        $docaslogout = true;
-    }
+    // Get auth plugin of user before logging out since the $auth object will
+    // be modified by the logout
+    $auth_plugin = StudipAuthAbstract::getInstance($auth->auth['auth_plugin']);
+
     //Logout aus dem Sessionmanagement
     $auth->logout();
     $sess->delete();
@@ -58,10 +56,11 @@ if ($auth->auth['uid'] !== 'nobody') {
     $timeout=(time()-(15 * 60));
     $user->set_last_action($timeout);
 
-    //der logout() Aufruf fuer CAS (dadurch wird das Cookie (Ticket) im Browser zerstoert)
-    if (!empty($docaslogout)) {
-        $casauth->logout();
+    // Perform logout from auth plugin (if possible)
+    if ($auth_plugin instanceof StudipAuthSSO) {
+        $auth_plugin->logout();
     }
+
     $sess->start();
     $_SESSION['_language'] = $_language;
     if ($contrast) {
-- 
GitLab