diff options
Diffstat (limited to 'modules-available/permissionmanager')
6 files changed, 86 insertions, 72 deletions
diff --git a/modules-available/permissionmanager/hooks/translation-global.inc.php b/modules-available/permissionmanager/hooks/translation-global.inc.php index 4810a719..cf2166bc 100644 --- a/modules-available/permissionmanager/hooks/translation-global.inc.php +++ b/modules-available/permissionmanager/hooks/translation-global.inc.php @@ -18,11 +18,8 @@ if (file_exists('modules/' . $moduleName . '/permissions/permissions.json')) { /** * Configuration categories. - * - * @param \Module $module - * @return array */ - $HANDLER['grep_permissions'] = function ($module) { + $HANDLER['grep_permissions'] = function (Module $module): array { $file = 'modules/' . $module->getIdentifier() . '/permissions/permissions.json'; if (!file_exists($file)) return []; diff --git a/modules-available/permissionmanager/inc/getpermissiondata.inc.php b/modules-available/permissionmanager/inc/getpermissiondata.inc.php index 4dfb09ec..a51619e0 100644 --- a/modules-available/permissionmanager/inc/getpermissiondata.inc.php +++ b/modules-available/permissionmanager/inc/getpermissiondata.inc.php @@ -11,7 +11,7 @@ class GetPermissionData * * @return array array of users (each with userid, username and roles (each with roleid and rolename)) */ - public static function getUserData() + public static function getUserData(): array { $res = Database::simpleQuery("SELECT user.userid AS userid, user.login AS login, role.rolename AS rolename, role.roleid AS roleid FROM user @@ -19,7 +19,7 @@ class GetPermissionData LEFT JOIN role ON role_x_user.roleid = role.roleid "); $userdata = array(); - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + foreach ($res as $row) { $userdata[$row['userid'] . ' ' . $row['login']][] = array( 'roleid' => $row['roleid'], 'rolename' => $row['rolename'] @@ -42,12 +42,12 @@ class GetPermissionData * * @return array array of locations (each including the roles that have permissions for them) */ - public static function getLocationData() + public static function getLocationData(): array { $res = Database::simpleQuery("SELECT role.roleid AS roleid, rolename, GROUP_CONCAT(COALESCE(locationid, 0)) AS locationids FROM role INNER JOIN role_x_location ON role.roleid = role_x_location.roleid GROUP BY roleid ORDER BY rolename ASC"); $locations = Location::getLocations(0, 0, false, true); - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + foreach ($res as $row) { $locationids = explode(",", $row['locationids']); if (in_array("0", $locationids)) { $locationids = array_map("intval", Location::extractIds(Location::getTree())); @@ -70,7 +70,7 @@ class GetPermissionData * @param int $flags Bitmask specifying additional data to fetch (WITH_* constants of this class) * @return array array roles (each with roleid and rolename) */ - public static function getRoles($flags = 0) + public static function getRoles(int $flags = 0): array { $cols = $joins = ''; if ($flags & self::WITH_USER_COUNT) { @@ -93,23 +93,23 @@ class GetPermissionData * Get permissions and locations for a given role. * * @param string $roleid id of the role - * @return array|false array containing an array of permissions and an array of locations, false if not found + * @return ?array array containing an array of permissions and an array of locations, null if not found */ - public static function getRoleData($roleid) + public static function getRoleData(string $roleid): ?array { $data = self::getRole($roleid); $res = Database::simpleQuery("SELECT roleid, locationid FROM role_x_location WHERE roleid = :roleid", array("roleid" => $roleid)); if ($res === false) - return false; + return null; $data["locations"] = array(); - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + foreach ($res as $row) { $data["locations"][] = $row['locationid']; } $res = Database::simpleQuery("SELECT roleid, permissionid FROM role_x_permission WHERE roleid = :roleid", array("roleid" => $roleid)); $data["permissions"] = array(); - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + foreach ($res as $row) { $data["permissions"][] = $row['permissionid']; } return $data; diff --git a/modules-available/permissionmanager/inc/permissiondbupdate.inc.php b/modules-available/permissionmanager/inc/permissiondbupdate.inc.php index 0cd89b3a..49988420 100644 --- a/modules-available/permissionmanager/inc/permissiondbupdate.inc.php +++ b/modules-available/permissionmanager/inc/permissiondbupdate.inc.php @@ -9,14 +9,14 @@ class PermissionDbUpdate * @param int[] $users userids * @param int[] $roles roleids */ - public static function addRoleToUser($users, $roles) + public static function addRoleToUser(array $users, array $roles): int { if (empty($users) || empty($roles)) return 0; - $arg = array(); + $arg = []; foreach ($users AS $userid) { foreach ($roles AS $roleid) { - $arg[] = compact('userid', 'roleid'); + $arg[] = ['userid' => $userid, 'roleid' => $roleid]; } } return Database::exec("INSERT IGNORE INTO role_x_user (userid, roleid) VALUES :arg", @@ -29,12 +29,12 @@ class PermissionDbUpdate * @param int[] $users userids * @param int[] $roles roleids */ - public static function removeRoleFromUser($users, $roles) + public static function removeRoleFromUser(array $users, array $roles): int { if (empty($users) || empty($roles)) return 0; $query = "DELETE FROM role_x_user WHERE userid IN (:users) AND roleid IN (:roles)"; - return Database::exec($query, array("users" => $users, "roles" => $roles)); + return Database::exec($query, ["users" => $users, "roles" => $roles]); } /** @@ -44,7 +44,7 @@ class PermissionDbUpdate * @param int[] $users list of user ids * @param int[] $roles list of role ids */ - public static function setRolesForUser($users, $roles) + public static function setRolesForUser(array $users, array $roles): int { $count = Database::exec("DELETE FROM role_x_user WHERE userid in (:users) AND roleid NOT IN (:roles)", compact('users', 'roles')); @@ -56,7 +56,7 @@ class PermissionDbUpdate * * @param int $roleid roleid */ - public static function deleteRole($roleid) + public static function deleteRole(int $roleid): int { return Database::exec("DELETE FROM role WHERE roleid = :roleid", array("roleid" => $roleid)); } @@ -69,7 +69,8 @@ class PermissionDbUpdate * @param string[] $permissions array of permissions * @param int|null $roleId roleid or null if the role does not exist yet */ - public static function saveRole($roleName, $roleDescription, $locations, $permissions, $roleId = null) + public static function saveRole(string $roleName, string $roleDescription, array $locations, array $permissions, + ?int $roleId = null): void { foreach ($permissions as &$permission) { $permission = strtolower($permission); @@ -92,14 +93,14 @@ class PermissionDbUpdate if (!empty($locations)) { $arg = array_map(function ($loc) use ($roleId) { - return compact('roleId', 'loc'); + return ['roleId' => $roleId, 'loc' => $loc]; }, $locations); Database::exec("INSERT IGNORE INTO role_x_location (roleid, locationid) VALUES :arg", ['arg' => $arg]); } if (!empty($permissions)) { $arg = array_map(function ($perm) use ($roleId) { - return compact('roleId', 'perm'); + return ['roleId' => $roleId, 'perm' => $perm]; }, $permissions); Database::exec("INSERT IGNORE INTO role_x_permission (roleid, permissionid) VALUES :arg", ['arg' => $arg]); } diff --git a/modules-available/permissionmanager/inc/permissionutil.inc.php b/modules-available/permissionmanager/inc/permissionutil.inc.php index 6aa97600..170fd699 100644 --- a/modules-available/permissionmanager/inc/permissionutil.inc.php +++ b/modules-available/permissionmanager/inc/permissionutil.inc.php @@ -14,7 +14,7 @@ class PermissionUtil * @param string|false $wildcard if $permission is a wildcard string this returns the matching variant * @param int|false $wclen if $permission is a wildcard string, this is the length of the matching variant */ - private static function makeComparisonVariants($permission, &$compare, &$wildcard, &$wclen) + private static function makeComparisonVariants($permission, ?array &$compare, &$wildcard, &$wclen): void { if (!is_array($permission)) { $permission = explode('.', $permission); @@ -46,12 +46,12 @@ class PermissionUtil /** * Check if the user has the given permission (for the given location). * - * @param string $userid userid to check + * @param int $userid userid to check * @param string $permissionid permissionid to check * @param int|null $locationid locationid to check or null if the location should be disregarded * @return bool true if user has permission, false if not */ - public static function userHasPermission($userid, $permissionid, $locationid) + public static function userHasPermission(int $userid, string $permissionid, ?int $locationid): bool { $permissionid = strtolower($permissionid); self::validatePermission($permissionid); @@ -121,10 +121,12 @@ class PermissionUtil // Compare to database result if ($cacheAll) { $allLocs = Location::getLocationsAssoc(); + } else { + $allLocs = []; } self::makeComparisonVariants($parts, $compare, $wildcard, $wclen); $retval = false; - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + foreach ($res as $row) { if (in_array($row['permissionid'], $compare, true) || ($wildcard !== false && strncmp($row['permissionid'], $wildcard, $wclen) === 0)) { if (!$cacheAll || ($row['locationid'] == $locationid) || $row['locationid'] === null) { @@ -132,15 +134,13 @@ class PermissionUtil if (!$cacheAll) break; } - if ($cacheAll) { - $cache[$key][(int)$row['locationid']] = true; - $list = ($row['locationid'] === null) ? array_keys($allLocs) : $allLocs[(int)$row['locationid']]['children']; - foreach ($list as $lid) { - $cache[$key][$lid] = true; - } - if ($row['locationid'] === null) - break; + $cache[$key][(int)$row['locationid']] = true; + $list = ($row['locationid'] === null) ? array_keys($allLocs) : $allLocs[(int)$row['locationid']]['children']; + foreach ($list as $lid) { + $cache[$key][$lid] = true; } + if ($row['locationid'] === null) + break; } } if ($locationid === null) { @@ -154,11 +154,11 @@ class PermissionUtil /** * Get all locations where the user has the given permission. * - * @param string $userid userid to check + * @param int $userid userid to check * @param string $permissionid permissionid to check * @return array array of locationids where the user has the given permission */ - public static function getAllowedLocations($userid, $permissionid) + public static function getAllowedLocations(int $userid, string $permissionid): array { $permissionid = strtolower($permissionid); self::validatePermission($permissionid); @@ -178,7 +178,7 @@ class PermissionUtil // Gather locationid from relevant rows self::makeComparisonVariants($parts, $compare, $wildcard, $wclen); $allowedLocations = array(); - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + foreach ($res as $row) { if (in_array($row['permissionid'], $compare, true) || ($wildcard !== false && strncmp($row['permissionid'], $wildcard, $wclen) === 0)) { $allowedLocations[(int)$row['locationid']] = true; @@ -201,10 +201,10 @@ class PermissionUtil * Extend an array of locations by adding all sublocations. * * @param array $tree tree of all locations (structured like Location::getTree()) - * @param array $allowedLocations the array of locationids to extend + * @param int[] $allowedLocations the array of locationids to extend * @return array extended array of locationids */ - public static function getSublocations($tree, $allowedLocations) + public static function getSublocations(array $tree, array $allowedLocations): array { $result = $allowedLocations; foreach ($tree as $location) { @@ -226,7 +226,7 @@ class PermissionUtil * * @param string $permissionId permission to check */ - private static function validatePermission($permissionId) + private static function validatePermission(string $permissionId): void { if (!CONFIG_DEBUG || $permissionId === '*') return; @@ -255,7 +255,7 @@ class PermissionUtil * * @return array permission tree as a multidimensional array */ - public static function getPermissions() + public static function getPermissions(): array { $permissions = array(); foreach (glob("modules/*/permissions/permissions.json", GLOB_NOSORT) as $file) { @@ -268,7 +268,8 @@ class PermissionUtil continue; foreach ($data as $perm => $permissionFlags) { $description = Dictionary::translateFileModule($moduleId, "permissions", $perm); - self::putInPermissionTree($moduleId . "." . $perm, $permissionFlags['location-aware'], $description, $permissions); + self::putInPermissionTree($moduleId . "." . $perm, $permissionFlags['location-aware'] ?? false, + $description, $permissions); } } ksort($permissions); @@ -277,6 +278,7 @@ class PermissionUtil foreach ($permissions as $module => $v) { $sortingOrder[Module::get($module)->getCategory()][] = $module; } + $sortingOrder = array_values($sortingOrder); $permissions = array_replace(array_flip(call_user_func_array('array_merge', $sortingOrder)), $permissions); foreach ($permissions as $module => $v) { if (is_int($v)) { @@ -291,18 +293,17 @@ class PermissionUtil /** * Get all existing roles. * - * @param int|false $userid Which user to consider, false = none - * @param bool $onlyMatching true = filter roles the user doesn't have + * @param ?int $userid Which user to consider, false = none (list all) * @return array list of roles */ - public static function getRoles($userid = false, $onlyMatching = true) + public static function getRoles(?int $userid = null): array { if ($userid === false) { return Database::queryAll('SELECT roleid, rolename FROM role ORDER BY rolename ASC'); } $ret = Database::queryAll('SELECT r.roleid, r.rolename, u.userid AS hasRole FROM role r LEFT JOIN role_x_user u ON (r.roleid = u.roleid AND u.userid = :userid) - GROUP BY r.roleid + GROUP BY r.roleid, r.rolename ORDER BY rolename ASC', ['userid' => $userid]); foreach ($ret as &$role) { settype($role['hasRole'], 'bool'); @@ -318,7 +319,7 @@ class PermissionUtil * @param string $description the description of the permission * @param array $tree the permission tree to modify */ - private static function putInPermissionTree($permission, $locationAware, $description, &$tree) + private static function putInPermissionTree(string $permission, bool $locationAware, string $description, array &$tree): void { $subPermissions = explode('.', $permission); foreach ($subPermissions as $subPermission) { diff --git a/modules-available/permissionmanager/install.inc.php b/modules-available/permissionmanager/install.inc.php index 292a5f52..ae6c9b03 100644 --- a/modules-available/permissionmanager/install.inc.php +++ b/modules-available/permissionmanager/install.inc.php @@ -31,7 +31,7 @@ $res[] = tableCreate('role_x_location', " $res[] = tableCreate('role_x_permission', " roleid int(10) unsigned NOT NULL, - permissionid varchar(200) NOT NULL, + permissionid varchar(100) NOT NULL, PRIMARY KEY (roleid, permissionid) "); @@ -109,14 +109,20 @@ if (!tableHasColumn('role', 'builtin')) { $res[] = UPDATE_DONE; } +// 2022-07-06 permissionid too long for older mariadb versions +if (stripos(tableColumnType('role_x_permission', 'permissionid'), 'varchar(200)') !== false) { + $alter = Database::exec("ALTER TABLE role_x_permission MODIFY permissionid varchar(100) NOT NULL"); + if ($alter === false) + finalResponse(UPDATE_FAILED, 'Cannot shorten permissionid to 100: ' . Database::lastError()); + $res[] = UPDATE_DONE; +} + if (Database::exec("INSERT INTO `role` (roleid, rolename, builtin, roledescription) VALUES (1,'Super-Admin', 1, 'Hat keinerlei Zugriffsbeschränkungen'), (2,'Admin', 1, 'Alles bis auf Rechte-/Nutzerverwaltung'), (3,'Prüfungsadmin', 1, 'Kann E-Prüfungen verwalten, Prüfungsmodus einschalten, etc.'), (4,'Lesezugriff', 1, 'Kann auf die meisten Seiten zugreifen, jedoch keine Änderungen vornehmen') ON DUPLICATE KEY UPDATE rolename = VALUES(rolename), builtin = 1, roledescription = VALUES(roledescription)") !== false) { - // Old ruleset accidentally gave write permissions to the read-only role - Database::exec("DELETE FROM role_x_permission WHERE roleid = 4 AND permissionid = 'news.*'"); // Assign roles to location (all) Database::exec("DELETE FROM role_x_location WHERE roleid IN (1,2,3,4)"); Database::exec("INSERT INTO `role_x_location` VALUES (1,NULL),(2,NULL),(3,NULL),(4,NULL)"); @@ -124,24 +130,26 @@ if (Database::exec("INSERT INTO `role` (roleid, rolename, builtin, roledescripti Database::exec("DELETE FROM role_x_permission WHERE roleid IN (1,2,3,4)"); // Assign permissions to roles Database::exec("INSERT IGNORE INTO `role_x_permission` VALUES + -- Exams Admin (3,'exams.exams.*'), + (3,'locations.location.view'), (3,'rebootcontrol.action.*'), (3,'statistics.hardware.projectors.view'), + (3,'statistics.hints'), (3,'statistics.machine.note.*'), (3,'statistics.machine.view-details'), (3,'statistics.view.*'), (3,'syslog.view'), - + -- Super Admin (1,'*'), - + -- Read only (4,'adduser.user.view-list'), - (4,'backup.create'), (4,'baseconfig.view'), (4,'dnbd3.access-page'), - (4,'dnbd3.refresh'), (4,'dnbd3.view.details'), (4,'dozmod.actionlog.view'), (4,'dozmod.users.view'), + (4,'eventlog.filter.rules.view'), (4,'eventlog.view'), (4,'exams.exams.view'), (4,'locationinfo.backend.check'), @@ -149,13 +157,16 @@ if (Database::exec("INSERT INTO `role` (roleid, rolename, builtin, roledescripti (4,'locations.location.view'), (4,'minilinux.view'), (4,'news.access-page'), + (4,'passthrough.view'), (4,'permissionmanager.locations.view'), (4,'permissionmanager.roles.view'), (4,'permissionmanager.users.view'), + (4,'remoteaccess.view'), (4,'runmode.list-all'), (4,'serversetup.access-page'), (4,'serversetup.download'), (4,'statistics.hardware.projectors.view'), + (4,'statistics.hints'), (4,'statistics.machine.note.view'), (4,'statistics.machine.view-details'), (4,'statistics.view.*'), @@ -171,22 +182,24 @@ if (Database::exec("INSERT INTO `role` (roleid, rolename, builtin, roledescripti (4,'webinterface.access-page'), (4,'rebootcontrol.subnet.view'), (4,'rebootcontrol.jumphost.view'), - + -- Admin (2,'adduser.user.view-list'), (2,'backup.*'), (2,'baseconfig.*'), (2,'dnbd3.*'), (2,'dozmod.*'), - (2,'eventlog.view'), + (2,'eventlog.*'), (2,'exams.exams.*'), (2,'locationinfo.*'), (2,'locations.*'), (2,'minilinux.*'), (2,'news.*'), + (4,'passthrough.*'), (2,'permissionmanager.locations.view'), (2,'permissionmanager.roles.view'), (2,'permissionmanager.users.view'), (2,'rebootcontrol.*'), + (2,'remoteaccess.*'), (2,'roomplanner.edit'), (2,'runmode.list-all'), (2,'serversetup.*'), @@ -195,7 +208,7 @@ if (Database::exec("INSERT INTO `role` (roleid, rolename, builtin, roledescripti (2,'sysconfig.*'), (2,'syslog.*'), (2,'systemstatus.*'), - (2,'vmstore.edit'), + (2,'vmstore.*'), (2,'webinterface.*')"); Database::exec("OPTIMIZE TABLE role_x_permission"); // Assign the first user to the superadmin role (if one exists) diff --git a/modules-available/permissionmanager/page.inc.php b/modules-available/permissionmanager/page.inc.php index b431d9c9..7e9f17e4 100644 --- a/modules-available/permissionmanager/page.inc.php +++ b/modules-available/permissionmanager/page.inc.php @@ -18,13 +18,13 @@ class Page_PermissionManager extends Page $action = Request::any('action', 'show', 'string'); if ($action === 'addRoleToUser') { User::assertPermission('users.edit-roles'); - $users = Request::post('users', ''); - $roles = Request::post('roles', ''); + $users = Request::post('users', [], 'array'); + $roles = Request::post('roles', [], 'array'); PermissionDbUpdate::addRoleToUser($users, $roles); } elseif ($action === 'removeRoleFromUser') { User::assertPermission('users.edit-roles'); - $users = Request::post('users', ''); - $roles = Request::post('roles', ''); + $users = Request::post('users', [], 'array'); + $roles = Request::post('roles', [], 'array'); PermissionDbUpdate::removeRoleFromUser($users, $roles); } elseif ($action === 'deleteRole') { User::assertPermission('roles.edit'); @@ -115,7 +115,7 @@ class Page_PermissionManager extends Page $roleid = Request::get("roleid", false, 'int'); if ($roleid !== false) { $role = GetPermissionData::getRoleData($roleid); - if ($role === false) { + if ($role === null) { Message::addError('invalid-role-id', $roleid); Util::redirect('?do=permissionmanager'); } @@ -147,7 +147,8 @@ class Page_PermissionManager extends Page * @param string $permString the prefix permission string with which all permissions in the permission tree should start * @return string generated html code */ - private static function generatePermissionHTML($permissions, $selectedPermissions = array(), $selectAll = false, $permString = "", $tags = []) + private static function generatePermissionHTML(array $permissions, array $selectedPermissions = [], + bool $selectAll = false, string $permString = "", array $tags = []): string { $res = ""; $toplevel = $permString == ""; @@ -203,11 +204,12 @@ class Page_PermissionManager extends Page * * @param array $locations the location tree * @param array $selectedLocations locations that should be preselected - * @param array $selectAll true if all locations should be preselected, false if only those in $selectedLocations - * @param array $toplevel true if the location tree are the children of the root location, false if not + * @param bool $selectAll true if all locations should be preselected, false if only those in $selectedLocations + * @param bool $toplevel true if the location tree are the children of the root location, false if not * @return string generated html code */ - private static function generateLocationHTML($locations, $selectedLocations = array(), $selectAll = false, $toplevel = true, $tags = []) + private static function generateLocationHTML(array $locations, array $selectedLocations = [], + bool $selectAll = false, bool $toplevel = true, array $tags = []): string { $res = ""; if ($toplevel && in_array(0, $selectedLocations)) { @@ -242,7 +244,7 @@ class Page_PermissionManager extends Page * @param array $locations the locationid array * @return array the locationid array without redundant locationids */ - private static function processLocations($locations) + private static function processLocations(array $locations): array { if (in_array(0, $locations)) return array(null); @@ -267,7 +269,7 @@ class Page_PermissionManager extends Page * @param array $permissions the permissionid array * @return array the permissionid array without redundant permissionids */ - private static function processPermissions($permissions) + private static function processPermissions(array $permissions): array { if (in_array("*", $permissions)) return array("*"); @@ -287,7 +289,7 @@ class Page_PermissionManager extends Page * @param array $permissions multidimensional array of permissionids * @return array flat array of permissionids */ - private static function extractPermissions($permissions) + private static function extractPermissions(array $permissions): array { $result = array(); foreach ($permissions as $permission => $a) { @@ -306,7 +308,7 @@ class Page_PermissionManager extends Page return $result; } - private function denyActionIfBuiltin($roleID) + private function denyActionIfBuiltin(string $roleID): void { if ($roleID) { $existing = GetPermissionData::getRole($roleID); |