<?php /** * user class contains username and its roles * This class is used in the base class * * @author hahn * * Axel <axel.hahn@unibe.ch> * 2024-08-29 Axel php8 only; added variable types; use short array syntax */ class user { /** * login name of the current user * @var string */ private string $_sUsername = ''; /** * list of groups of the current user * @var array */ private array $_aUserGroups = []; /** * list of roles based on the groups * @var array */ private array $_aUserPermmissions = []; /** * list of projects the current user is involved in * @var array */ private $_aProjects = []; /** * name of the last checked role * @var string */ private $_sLastCheckedPermission = false; /** * Constructor * init user with optional given user * * @param string $sUser username to set */ public function __construct(string $sUser = '') { $this->setUser($sUser); } // ---------------------------------------------------------------------- // private functions // ---------------------------------------------------------------------- /** * Get string with detected user from current session / basic auth / cli access * * @return string */ private function _autoDetectUser(): string { $sUser = ''; if (isset($_SESSION) && isset($_SESSION["PHP_AUTH_USER"])) { $sUser = $_SESSION["PHP_AUTH_USER"]; } if (!$sUser && isset($_SERVER["PHP_AUTH_USER"])) { $sUser = $_SERVER["PHP_AUTH_USER"]; } if (php_sapi_name() == "cli") { $sUser = "cliadmin"; } return $sUser; } /** * UNUSED SO FAR * Idea: limit user access to a set of projects */ private function _getUser2Projects() { $sFile = __DIR__ . '/../../../config/inc_user2projects.php'; return file_exists($sFile) ? require $sFile : [] ; } /** * Load roles per user from config * @return array */ private function _getUser2Roles(): array { $sFile = __DIR__ . '/../../../config/inc_user2roles.php'; return file_exists($sFile) ? require $sFile : ['admin' => ['admin']] ; } /** * TODO: reimplement * get the user groups of the current user from an internal source. * The function returns a flat aray with names of the groups * @return array */ private function _getUserGroups(): array { $aGroups = []; if ($this->_sUsername) { $aGroups[] = "authenticated"; // $aGroups[]='#'.$this->_sUsername; $aUserDefinitions = $this->_getUser2Roles(); foreach (array_keys($aUserDefinitions) as $sGroup) { if (array_search($this->_sUsername, $aUserDefinitions[$sGroup]) !== false) { $aGroups[] = $sGroup; } } } $this->_aUserGroups = $aGroups; return $this->_aUserGroups; } /** * TODO: reimplement * get the user roles of the current user from an internal source. * The function returns a flat aray with names of the roles * @return array */ private function _getUserPermission(): array { $aRoles = []; $aRolesDefinitions = require(__DIR__ . '/../../../config/inc_roles.php'); // anonymous roles: $aRoles = array_merge($aRoles, $aRolesDefinitions['all']); foreach (array_keys($aRolesDefinitions) as $sGroup) { if ($this->hasGroup($sGroup)) { $aRoles = array_merge($aRoles, $aRolesDefinitions[$sGroup]); } } $this->_aUserPermmissions = array_unique($aRoles); return $this->_aUserPermmissions; } // ---------------------------------------------------------------------- // public ACTIONS // ---------------------------------------------------------------------- /** * authenticate a user with the configured methods * * @global array $aConfig global config * @global array $aParams params (i.e. GET and POST) * * @return boolean */ public function authenticate(): bool { global $aConfig, $aParams; if (!isset($aConfig['auth']) || !is_array($aConfig['auth']) || !count($aConfig['auth']) || !isset($aParams['user'])) { return false; } $sUser = $aParams['user']; $sPassword = isset($aParams['password']) ? $aParams['password'] : false; foreach (array_keys($aConfig['auth']) as $sAuthMethod) { $oUserAuth = false; switch ($sAuthMethod) { case 'ldap': require_once("userauth.ldap.class.php"); $oUserAuth = new userauthLdap($aConfig['auth']['ldap']); break; // implement other methods here // see userauth.ldap.class.php as simple example default: echo 'WARNING: authmethod ' . $sAuthMethod . ' in your config is not implemented in ' . basename(__FILE__) . ' and is useless so far.<br>'; } // if authentication fails then continue and try next method if ($oUserAuth && $oUserAuth->authenticate($sUser, $sPassword)) { // set a session - it must correspondent with _autoDetectUser() // $_SESSION["PHP_AUTH_USER"]=$sUser; $this->setUser($sUser); return true; } // if authentication fails then continue and try next method if (!$oUserAuth) { echo "DEBUG: ERROR oUserAuth waasn't initialized for [$sAuthMethod].<br>"; } } return false; } /** * logoff user * @return boolean */ public function logoff(): bool { unset($_SESSION["PHP_AUTH_USER"]); $this->setUser(); return true; } /** * set an authenticated user and get its roles * @param string $sUser optional: set a given username * @return void */ public function setUser(string $sUser = ''): void { if ($sUser) { $this->_sUsername = $sUser; $_SESSION["PHP_AUTH_USER"] = $sUser; } else { // check user from basic auth or cli $this->_sUsername = $this->_autoDetectUser(); } $this->_getUserGroups(); $this->_getUserPermission(); } /** * Get html code to display a denied message * @return string */ public function showDenied(): string { return '<div class="alert alert-danger" role="alert">' . ($this->_sUsername ? t("class-user-error-deny-no-role") . '<br>' . $this->_sUsername . ' --> (' . $this->_sLastCheckedPermission . ')<br>' : t("class-user-error-login-required") ) . '</div><br>' . '<a href="/deployment/all/login/" class="btn btn-primary">' . t('menu-login') . '</a>' ; } // ---------------------------------------------------------------------- // public GETTER // ---------------------------------------------------------------------- /** * UNUSED SO FAR * Idea: limit user access to a set of projects */ public function getUser2Projects() { return $this->_getUser2Projects(); } /** * Get a list of all roles for the current user * @return array */ public function getUser2Roles(): array { return $this->_getUser2Roles(); } /** * Get the current username * @return string */ public function getUsername(): string { return $this->_sUsername; } /** * Get a flat array with roles of the current user * @return array */ public function getUserGroups(): array { return $this->_aUserGroups; } /** * Get a flat array with roles of the current user * @return array */ public function getUserPermission(): array { return $this->_aUserPermmissions; } /** * check if the current user has a given role name * @param string $sGroupname name of the role to check * @return bool */ public function hasGroup($sGroupname) { return !!(array_search($sGroupname, $this->_aUserGroups) !== false); } /** * check if the current user has a given role name * @param string $sPermission name of the role to check * @return boolean */ public function hasPermission($sPermission): bool { $this->_sLastCheckedPermission = $sPermission; $bReturn = !!(array_search($sPermission, $this->_aUserPermmissions) !== false); // $this->log(__FUNCTION__ . "($sRolename) -> " . $bReturn ? 'true' : 'false'); return $bReturn; } }