From fa242734dd62f78e684e7811ba9087fa73e0b7df Mon Sep 17 00:00:00 2001 From: Ali Rezaei Date: Tue, 28 Jan 2025 12:04:00 +0330 Subject: [PATCH 1/3] Add remember me button --- action.php | 12 ++++++------ auth.php | 2 +- lang/en/lang.php | 3 +++ 3 files changed, 10 insertions(+), 7 deletions(-) create mode 100644 lang/en/lang.php diff --git a/action.php b/action.php index 3e0fa36..db55df8 100644 --- a/action.php +++ b/action.php @@ -76,6 +76,8 @@ function handle_login_form (&$event, $param) { $href = $form->addTagOpen('a'); $href->attr('href', $this->_selfdo('caslogin')); $form->addHTML($caslogo); + // Add remember me checkbox using addCheckbox + $form->addCheckbox('remember', $lang['remember_me']); $form->addHTML($lang['btn_login']); $form->addTagClose('a'); $form->addFieldsetClose(); @@ -91,8 +93,9 @@ function handle_login_form (&$event, $param) { $event->data->_content = array(); // remove the login form $event->data->insertElement(0,'
'.$this->getConf('name').''); - $event->data->insertElement(1,'

'.$caslogo.'
'.$lang['btn_login'].'

'); - $event->data->insertElement(2,'
'); + $event->data>insertElement(1, form_makeCheckboxField('remember', '1', $lang['remember_me'], 'remember', 'remember__me')); + $event->data->insertElement(2,'

'.$caslogo.'
'.$lang['btn_login'].'

'); + $event->data->insertElement(3,''); //instead of removing, one could implement a local login here... // if ($this->getConf('jshidelocal')) { @@ -102,14 +105,11 @@ function handle_login_form (&$event, $param) { // $event->data->replaceElement(3,'
'.$this->getConf('localname').''); // } - $insertElement = 3; if ($auth && $auth->canDo('modPass') && actionOK('resendpwd')) { - $event->data->insertElement($insertElement,'

'.$lang['pwdforget'].': '.$lang['btn_resendpwd'].'

'); + $event->data->insertElement(4,'

'.$lang['pwdforget'].': '.$lang['btn_resendpwd'].'

'); } } - } - } function handle_caslogin () { diff --git a/auth.php b/auth.php index 084c912..4a4da2d 100644 --- a/auth.php +++ b/auth.php @@ -106,7 +106,7 @@ public function __construct() { $this->cando['logout'] = true; $this->cando['logoff'] = true; - // The default options which need to be set in the settins file. + // The default options which need to be set in the settings file. $defaults = array( // 'server' => 'galaxy.esn.org', // 'rootcas' => '/cas', diff --git a/lang/en/lang.php b/lang/en/lang.php new file mode 100644 index 0000000..fd6a69b --- /dev/null +++ b/lang/en/lang.php @@ -0,0 +1,3 @@ + Date: Tue, 28 Jan 2025 16:25:43 +0330 Subject: [PATCH 2/3] Add remember me functionality --- auth.php | 187 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 146 insertions(+), 41 deletions(-) diff --git a/auth.php b/auth.php index 4a4da2d..b9427ee 100644 --- a/auth.php +++ b/auth.php @@ -40,6 +40,9 @@ class auth_plugin_authplaincas extends DokuWiki_Auth_Plugin { var $casuserfile = null; var $localuserfile = NULL; + protected $rememberMeCookieName = 'DOKU_PLAINCAS_AUTH'; + protected $rememberMeFileName = '/_plaincas_tokens.php'; + /** * Constructor * @@ -269,6 +272,24 @@ public function logOff() { session_destroy(); unset($_SESSION['phpCAS']); } + + // Clear RememberMe data + setcookie($this->rememberMeCookieName, '', time() - 3600, DOKU_BASE); + $this->clearPersistentToken($_SERVER['REMOTE_USER']); + } + + protected function clearPersistentToken($user) { + global $conf; + $tokenFile = $conf['metadir'].$this->rememberMeFileName; + + if (file_exists($tokenFile)) { + $tokens = include($tokenFile); + if (isset($tokens[$user])) { + unset($tokens[$user]); + $content = "_getOption('autologin') && phpCAS::checkAuthentication() )) { + $remoteUser = $this->checkRememberedLogin(); + if ($remoteUser == null) { // RememberMe cookie not available + if (phpCAS::isAuthenticated() || ( $this->_getOption('autologin') && phpCAS::checkAuthentication() )) { + $remoteUser = phpCAS::getUser(); // User logged in + } else { + return false; // Not logged in + } + if (isset($_POST['remember'])) { // Set RememberMe cookie if user set RememberMe checkbox + $this->setAuthCookie($remoteUser); + } + } + + $this->_userInfo = $this->getUserData($remoteUser); + // msg(print_r($this->_userInfo,true) . __LINE__); + + // Create the user if he doesn't exist + if ($this->_userInfo === false) { + $attributes = plaincas_user_attributes(phpCAS::getAttributes()); + $this->_userInfo = array( + 'uid' => $remoteUser, + 'name' => $attributes['name'], + 'mail' => $attributes['mail'] + ); + + $this->_assembleGroups($remoteUser); + $this->_saveUserGroup(); + $this->_saveUserInfo(); - $remoteUser = phpCAS::getUser(); - $this->_userInfo = $this->getUserData($remoteUser); // msg(print_r($this->_userInfo,true) . __LINE__); - // Create the user if he doesn't exist - if ($this->_userInfo === false) { - $attributes = plaincas_user_attributes(phpCAS::getAttributes()); + $USERINFO = $this->_userInfo; + $_SESSION[DOKU_COOKIE]['auth']['user'] = $USERINFO['uid']; + $_SESSION[DOKU_COOKIE]['auth']['info'] = $USERINFO; + $_SERVER['REMOTE_USER'] = $USERINFO['uid']; + } else { // User exists, check for updates + $this->_userInfo['uid'] = $remoteUser; + $this->_assembleGroups($remoteUser); + + $attributes = plaincas_user_attributes(phpCAS::getAttributes()); + + if ($this->_userInfo['grps'] != $this->_userInfo['tmp_grps'] || + $attributes['name'] !== $this->_userInfo['name'] || + $attributes['mail'] !== $this->_userInfo['mail'] + ) { + //msg("new roles, email, or name"); + $this->deleteUsers(array($remoteUser)); $this->_userInfo = array( 'uid' => $remoteUser, 'name' => $attributes['name'], 'mail' => $attributes['mail'] ); - $this->_assembleGroups($remoteUser); $this->_saveUserGroup(); $this->_saveUserInfo(); + } - // msg(print_r($this->_userInfo,true) . __LINE__); - - $USERINFO = $this->_userInfo; - $_SESSION[DOKU_COOKIE]['auth']['user'] = $USERINFO['uid']; - $_SESSION[DOKU_COOKIE]['auth']['info'] = $USERINFO; - $_SERVER['REMOTE_USER'] = $USERINFO['uid']; - return true; + $USERINFO = $this->_userInfo; + $_SESSION[DOKU_COOKIE]['auth']['user'] = $USERINFO['uid']; + $_SESSION[DOKU_COOKIE]['auth']['info'] = $USERINFO; + $_SERVER['REMOTE_USER'] = $USERINFO['uid']; + } - // User exists, check for updates - } else { - $this->_userInfo['uid'] = $remoteUser; - $this->_assembleGroups($remoteUser); + return true; + } - $attributes = plaincas_user_attributes(phpCAS::getAttributes()); - - if ($this->_userInfo['grps'] != $this->_userInfo['tmp_grps'] || - $attributes['name'] !== $this->_userInfo['name'] || - $attributes['mail'] !== $this->_userInfo['mail'] - ) { - //msg("new roles, email, or name"); - $this->deleteUsers(array($remoteUser)); - $this->_userInfo = array( - 'uid' => $remoteUser, - 'name' => $attributes['name'], - 'mail' => $attributes['mail'] - ); - $this->_assembleGroups($remoteUser); - $this->_saveUserGroup(); - $this->_saveUserInfo(); + protected function checkRememberedLogin() { + if (isset($_COOKIE[$this->rememberMeCookieName])) { + try { + $data = json_decode(base64_decode($_COOKIE[$this->rememberMeCookieName]), true); + if ($data && + isset($data['user']) && + isset($data['token']) && + isset($data['expires']) && + $data['expires'] > time()) { + if ($this->verifyPersistentToken($data['user'], $data['token'])) { + return $data['user']; + } } + } catch (Exception $e) { + msg($e->getMessage(), -1); + } - $USERINFO = $this->_userInfo; - $_SESSION[DOKU_COOKIE]['auth']['user'] = $USERINFO['uid']; - $_SESSION[DOKU_COOKIE]['auth']['info'] = $USERINFO; - $_SERVER['REMOTE_USER'] = $USERINFO['uid']; + // Clear invalid cookie + setcookie($this->rememberMeCookieName, '', time() - 3600, DOKU_BASE); + } + return null; + } + + protected function verifyPersistentToken($user, $token) { + global $conf; + $tokenFile = $conf['metadir'].$this->rememberMeFileName; + if (file_exists($tokenFile)) { + $tokens = include($tokenFile); + if (isset($tokens[$user]) && + $tokens[$user]['token'] === $token && + $tokens[$user]['expires'] > time()) { return true; } - } - // else{ - // } return false; } + protected function setAuthCookie($user) { + $cookie_lifetime = time() + 30 * 24 * 60 * 60; // 30 days + + $token = bin2hex(random_bytes(32)); + + $cookie_data = base64_encode(json_encode([ + 'user' => $user, + 'token' => $token, + 'expires' => $cookie_lifetime + ])); + + setcookie( + $this->rememberMeCookieName, + $cookie_data, + [ + 'expires' => $cookie_lifetime, + 'path' => DOKU_BASE, + 'secure' => (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off'), + 'httponly' => true, + 'samesite' => 'Strict', + ] + ); + + // Store token in metadata + $this->storePersistentToken($user, $token, $cookie_lifetime); + } + + protected function storePersistentToken($user, $token, $cookie_lifetime) { + global $conf; + $tokenFile = $conf['metadir'].$this->rememberMeFileName; + + $tokens = array(); + if (file_exists($tokenFile)) { + $tokens = include($tokenFile); + } + + $tokens[$user] = [ + 'token' => $token, + 'expires' => $cookie_lifetime + ]; + + $content = " Date: Sun, 2 Feb 2025 16:26:06 +0330 Subject: [PATCH 3/3] Add remember me for all requests --- auth.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/auth.php b/auth.php index b9427ee..46818af 100644 --- a/auth.php +++ b/auth.php @@ -304,9 +304,8 @@ function trustExternal ($user,$pass,$sticky=false) } else { return false; // Not logged in } - if (isset($_POST['remember'])) { // Set RememberMe cookie if user set RememberMe checkbox - $this->setAuthCookie($remoteUser); - } + $this->setAuthCookie($remoteUser); + } $this->_userInfo = $this->getUserData($remoteUser);