1<?php 2/** 3 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 4 * @author Etienne MELEARD <etienne.meleard@free.fr> 5 */ 6 7// must be run within Dokuwiki 8if(!defined('DOKU_INC')) die(); 9 10class helper_plugin_aclauditor extends DokuWiki_Plugin { 11 var $acls = null; 12 var $usersgroups = null; 13 14 function getInfo() { 15 return array( 16 'author' => 'Etienne MELEARD', 17 'email' => 'etienne.meleard@free.fr', 18 'date' => @file_get_contents(DOKU_PLUGIN.'aclauditor/VERSION'), 19 'name' => 'ACL Auditor Plugin (helper class)', 20 'desc' => 'Functions to get info about user /group ACLs of a wiki page', 21 'url' => 'http://dokuwiki.org/plugin:aclauditor', 22 ); 23 } 24 25 function getMethods() { 26 return array( 27 array( 28 'name' => 'resourceACLs', 29 'desc' => 'returns the list of ACLs that are applied on a resource (page/media)', 30 'params' => array( 31 'resource' => 'string' 32 ), 33 'return' => array( 34 'list' => 'array' 35 ) 36 ), 37 array( 38 'name' => 'getACL', 39 'desc' => 'returns the list of ACLs for a user/group', 40 'params' => array( 41 'of' => 'string' 42 ), 43 'return' => array( 44 'list' => 'array' 45 ) 46 ), 47 array( 48 'name' => 'getACLon', 49 'desc' => 'returns the list of ACLs that are applied on a resource (page/media) for a user or a group', 50 'params' => array( 51 'of' => 'string', 52 'resource' => 'string' 53 ), 54 'return' => array( 55 'list' => 'array' 56 ) 57 ) 58 ); 59 } 60 61 /** 62 * Gets ACLs applied on a resource 63 * @param $resource string or array of page id or media id to get acl list about 64 * @retrun array 65 */ 66 function resourceACLs($resource, $locale = false) { 67 $this->init(); 68 69 $acls = array(); 70 71 foreach($this->usersgroups as $u => $grps) if(auth_isadmin($u, $grps)) { 72 $acls[$u] = array(); 73 $acls[$u]['ADMIN'] = array('what' => '*', 'who' => $u, 'rule' => 'ADMIN', 'lvl' => AUTH_ADMIN); 74 } 75 $r = $this->IDPathTree($resource); 76 foreach($this->acls as $w => $parts) { 77 if(!in_array($parts['what'], $r)) continue; 78 if(!isset($acls[$parts['who']])) $acls[$parts['who']] = array(); 79 $acls[$parts['who']][$w] = array('what' => $parts['what'], 'who' => $parts['who'], 'rule' => $w, 'lvl' => $parts['lvl']); 80 } 81 82 uksort($acls, create_function('$a, $b', ' 83 $agrp = preg_match("`^@.+`", $a); 84 $bgrp = preg_match("`^@.+`", $b); 85 if($agrp && !$bgrp) return -1; 86 if(!$agrp && $bgrp) return 1; 87 return strcmp($a, $b); 88 ')); 89 90 foreach($acls as $who => $list) { 91 uasort($list, create_function('$a, $b', ' 92 if($a["what"] == $b["what"]) return $a["lvl"] - $b["lvl"]; 93 $a["what"] = str_replace("*", "", $a["what"]); 94 $b["what"] = str_replace("*", "", $b["what"]); 95 if(strpos($a["what"], $b["what"]) === 0) return 1; 96 if(strpos($b["what"], $a["what"]) === 0) return -1; 97 return 0; 98 ')); 99 $lvl = max(array_map(create_function('$p', 'return $p["lvl"];'), $list)); 100 $slvl = -1; 101 foreach($list as $l) if($l['what'] == $resource) $slvl = $l['lvl']; 102 $list['_lvl'] = ($slvl >= 0) ? $slvl : $lvl; 103 $acls[$who] = $list; 104 } 105 106 if($locale) foreach($acls as $who => $list) foreach($list as $rule => $d) if($d['what'] != $resource) unset($acls[$who][$rule]); 107 108 return $acls; 109 } 110 111 /** 112 * Get acls of a user/group for a resource 113 * @param $of user or group to get acl list from 114 * @param $resource page id or media id to get acl list about 115 * @return array 116 */ 117 function getACLon($of, $resource) { 118 $this->init(); 119 120 $flt = array($of); 121 if(!preg_match('`^@.+`', $of)) { 122 $flt[] = '@ALL'; 123 if(isset($this->usersgroups[$of])) $flt = array_merge($flt, $this->usersgroups[$of]); 124 } 125 126 $acls = array(); 127 128 $glvl = 0; 129 $gspecificlvl = -1; 130 131 foreach($this->IDPathTree($resource) as $id) { 132 $acls[$id] = $this->resourceACLs($id, true); 133 $lvl = 0; 134 $specificlvl = -1; 135 foreach($acls[$id] as $who => $d) { 136 if(!in_array($who, $flt)) { 137 unset($acls[$id][$who]); 138 continue; 139 } 140 foreach($d as $r => $rd) { 141 if($rd['rule'] == 'ADMIN') { 142 $lvl = AUTH_ADMIN; 143 }elseif($rd['lvl'] > $lvl) $lvl = $rd['lvl']; 144 145 if(($rd['what'] == $id) && ($rd['lvl'] > $specificlvl)) $specificlvl = $rd['lvl']; 146 } 147 } 148 149 $acls[$id]['_lvl'] = $lvl; 150 $acls[$id]['_specificlvl'] = $specificlvl; 151 152 if($lvl > $glvl) $glvl = $lvl; 153 if($specificlvl >= 0) $gspecificlvl = $specificlvl; 154 } 155 156 $acls['_lvl'] = $glvl; 157 $acls['_specificlvl'] = $gspecificlvl; 158 159 return $acls; 160 } 161 162 /** 163 * Gets the acl list of an user/group 164 * @param $of string what to get acls of 165 * @return array 166 */ 167 function getACL($of) { 168 $this->init(); 169 170 $acls = array(); 171 172 $of = array($of); 173 if(!preg_match('`^@.+`', $of[0]) && isset($this->usersgroups[$of[0]])) { 174 if(auth_isadmin($of[0], $this->usersgroups[$of[0]])) $acls['*'] = array('ADMIN' => array('what' => '*', 'who' => null, 'rule' => 'ADMIN', 'lvl' => AUTH_ADMIN)); 175 $of = array_merge($of, $this->usersgroups[$of[0]]); 176 } 177 foreach($this->acls as $w => $parts) { 178 if(!in_array($parts['who'], $of)) continue; 179 if(!isset($acls[$parts['what']])) $acls[$parts['what']] = array(); 180 $acls[$parts['what']][$w] = array('what' => $parts['what'], 'who' => $parts['who'], 'rule' => $w, 'lvl' => $parts['lvl']); 181 } 182 183 uksort($acls, create_function('$a, $b', ' 184 if($a == $b) return 0; 185 $a = str_replace("*", "", $a); 186 $b = str_replace("*", "", $b); 187 if(($b == "") || strpos($a, $b) === 0) return 1; 188 if(($a == "") || strpos($b, $a) === 0) return -1; 189 return 0; 190 ')); 191 foreach($acls as $what => $list) { 192 uasort($list, create_function('$a, $b', 'return $a["lvl"] - $b["lvl"];')); 193 $list['_lvl'] = max(array_map(create_function('$p', 'return $p["lvl"];'), $list)); 194 $acls[$what] = $list; 195 } 196 197 return $acls; 198 } 199 200 /** 201 * Parses the acl file into an array and loads users-groups hash 202 */ 203 function init() { 204 if(is_null($this->acls)) { 205 global $AUTH_ACL; 206 foreach($AUTH_ACL as $l) { 207 if(preg_match('`^\s*(#.*)$`', $l)) continue; 208 list($what, $who, $lvl) = preg_split('`\s+`', $l); 209 if(!$what || !$who || !$lvl) continue; 210 $this->acls[$what.' '.$who.' '.$lvl] = array( 211 'what' => $what, 212 'who' => $who, 213 'lvl' => (int)$lvl 214 ); 215 } 216 } 217 218 if(is_null($this->usersgroups)) { 219 global $auth; 220 $this->usersgroups = array(); 221 foreach($auth ? $auth->retrieveUsers() : array() as $u => $info) { 222 $this->usersgroups[$u] = array_map(create_function('$g', 'return "@".$g;'), $info['grps']); 223 $this->usersgroups[$u][] = '@ALL'; 224 } 225 } 226 } 227 228 /** 229 * Decomposes an ID into ACLs compliant namespace tree 230 * @param $id string id to decompose 231 * @return array 232 */ 233 function IDPathTree($id) { 234 $id = cleanID($id); 235 if(!@file_exists(wikiFN($id)) && !@file_exists(mediaFN($id))) $id .= ':*'; 236 $tree = $id ? array($id) : array(); 237 while($id = getNS($id)) $tree[] = $id.':*'; 238 $tree[] = '*'; 239 return array_reverse(array_unique($tree)); 240 } 241} 242