ACLtags as $aclKey => $aclItem) { // check if acl item already exists if there's acl content for it if (!array_key_exists($aclKey, $pageMap) && (isset($aclItem["match"]) || isset($aclItem["pattern"]))) { $pageMap[$aclKey] = array(); } if (isset($aclItem["match"])) { foreach ($aclItem['match'] as $matchexpr) { $pageMap[$aclKey][] = trim($matchexpr); } } } return $pageMap; } /** * merge legacy acl's from json file into $this->ACLtags */ private function mergeLegacyACL() { // load legacy acl from json file $this->ACLtags = array_merge_recursive( $this->ACLtags, json_decode(file_get_contents(__DIR__."/ACL_Legacy_Page_Map.json"), true) ); } /** * merge pluggable ACL xml's into $this->ACLtags * @throws \Exception */ private function mergePluggableACLs() { // crawl all vendors and modules and add acl definitions foreach (glob(__DIR__.'/../../*') as $vendor) { foreach (glob($vendor.'/*') as $module) { $acl_cfg_xml = $module.'/ACL/ACL.xml'; if (file_exists($acl_cfg_xml)) { // load ACL xml file and perform some basic validation $ACLxml = simplexml_load_file($acl_cfg_xml); if ($ACLxml === false) { throw new \Exception('ACL xml '.$acl_cfg_xml.' not valid') ; } if ($ACLxml->getName() != "acl") { throw new \Exception('ACL xml '.$acl_cfg_xml.' seems to be of wrong type') ; } // when acl was correctly loaded, let's parse data into private $this->ACLtags foreach ($ACLxml as $aclID => $ACLnode) { // an acl should minimal have a name, without one skip processing. if (isset($ACLnode->name)) { $aclPayload = array(); $aclPayload['name'] = (string)$ACLnode->name; if (isset($ACLnode->description)) { // rename internal tag for backward compat. $aclPayload['desc'] = (string)$ACLnode->description; } if (isset($ACLnode->patterns->pattern)) { // rename pattern to match for internal usage, old code did use match and // to avoid duplicate conversion let's do this only on input. $aclPayload['match'] = array(); foreach ($ACLnode->patterns->pattern as $pattern) { $aclPayload['match'][] = (string)$pattern; } } $this->ACLtags[$aclID] = $aclPayload; } } } } } } /** * init legacy ACL features */ private function init() { // add acl payload $this->mergeLegacyACL(); $this->mergePluggableACLs(); $pageMap = $this->loadPageMap(); // create privilege mappings $this->legacyUsers = array(); $this->legacyGroupPrivs = array(); $groupmap = array(); // gather user / group data from config.xml $config = Config::getInstance()->object() ; if ($config->system != null) { foreach ($config->system->children() as $key => $node) { if ($key == 'user') { $this->legacyUsers[$node->name->__toString()] = array() ; $this->legacyUsers[$node->name->__toString()]['uid'] = $node->uid->__toString(); $this->legacyUsers[$node->name->__toString()]['groups'] = array(); $this->legacyUsers[$node->name->__toString()]['priv'] = array(); foreach ($node->priv as $priv) { if (substr($priv, 0, 5) == 'page-') { if (array_key_exists($priv->__toString(), $pageMap)) { $this->legacyUsers[$node->name->__toString()]['priv'][] = $pageMap[$priv->__toString()]; } } } } elseif ($key == 'group') { $groupmap[$node->name->__toString()] = $node ; } } } // interpret group privilege data and update user data with group information. foreach ($groupmap as $groupkey => $groupNode) { $legacyGroupPrivs[$groupkey] = array(); foreach ($groupNode->children() as $itemKey => $node) { if ($node->getName() == "member" && $node->__toString() != "") { foreach ($this->legacyUsers as $username => $userinfo) { if ($this->legacyUsers[$username]["uid"] == $node->__toString()) { $this->legacyUsers[$username]["groups"][] = $groupkey; } } } elseif ($node->getName() == "priv" && substr($node->__toString(), 0, 5) == "page-") { if (array_key_exists($node->__toString(), $pageMap)) { $this->legacyGroupPrivs[$groupkey][] = $pageMap[$node->__toString()]; } } } } } /** * check url against regex mask * @param $url url to match * @param $urlmask regex mask * @return bool url matches mask */ private function urlMatch($url, $urlmask) { $match = str_replace(array(".", "*","?"), array("\.", ".*","\?"), $urlmask); $result = preg_match("@^/{$match}$@", "{$url}"); if ($result) { return true; } else { return false; } } /** * Construct new ACL object */ public function __construct() { $this->init(); } /** * legacy functionality to check if a page is accessible for the specified user. * @param $username user name * @param $url full url, for example /firewall_rules.php * @return bool */ public function isPageAccessible($username, $url) { if (array_key_exists($username, $this->legacyUsers)) { // search user privs foreach ($this->legacyUsers[$username]["priv"] as $privset) { foreach ($privset as $urlmask) { if ($this->urlMatch($url, $urlmask)) { return true; } } } // search group privs foreach ($this->legacyUsers[$username]["groups"] as $itemkey => $group) { if (array_key_exists($group, $this->legacyGroupPrivs)) { foreach ($this->legacyGroupPrivs[$group] as $privset) { foreach ($privset as $urlmask) { if ($this->urlMatch($url, $urlmask)) { return true; } } } } } } return false; } /** * return privilege list as array (sorted), only for backward compatibility * @return array */ public function getLegacyPrivList() { // convert json priv map to array $priv_list = array(); foreach ($this->ACLtags as $aclKey => $aclItem) { $priv_list[$aclKey] = array(); foreach ($aclItem as $propName => $propValue) { if ($propName == 'name' || $propName == 'descr') { // translate name and description tags $priv_list[$aclKey][$propName] = gettext($propValue); } else { $priv_list[$aclKey][$propName] = $propValue; } } } // sort by name ( case insensitive ) uasort($priv_list, function ($a, $b) { return strcasecmp($a["name"], $b["name"]) ; }); return $priv_list; } }