2 rcs_id('$Id: PagePerm.php,v 1.2 2004-02-08 13:17:48 rurban Exp $');
4 Copyright 2004 $ThePhpWikiProgrammingTeam
6 This file is part of PhpWiki.
8 PhpWiki is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 PhpWiki is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with PhpWiki; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 Permissions per page and action based on current user,
25 ownership and group membership implemented with ACL's (Access Control Lists),
26 opposed to the simplier unix like ugo:rwx system.
27 The previous system was only based on action and current user. (lib/main.php)
29 Permissions maybe inherited its parent pages, and ultimativly the
30 optional master page (".")
31 For Authentification see WikiUserNew.php, WikiGroup.php and main.php
32 Page Permssions are in PhpWiki since v1.3.9 and enabled since v1.4.0
34 This file might replace the following functions from main.php:
35 Request::_notAuthorized($require_level)
36 display the denied message and optionally a login form
37 to gain higher privileges
38 Request::getActionDescription($action)
39 helper to localize the _notAuthorized message per action,
41 Request::getDisallowedActionDescription($action)
42 helper to localize the _notAuthorized message per action,
44 Request::requiredAuthority($action)
45 returns the needed user level
46 has a hook for plugins on POST
47 Request::requiredAuthorityForAction($action)
48 just returns the level per action, will be replaced with the
51 The defined main.php actions map to simplier access types here:
54 create => edit or create
58 list in PageList => list
61 /* Symbolic special ACL groups. Untranslated to be stored in page metadata*/
62 define('ACL_EVERY', '_EVERY');
63 define('ACL_ANONYMOUS', '_ANONYMOUS');
64 define('ACL_BOGOUSERS', '_BOGOUSERS');
65 define('ACL_SIGNED', '_SIGNED');
66 define('ACL_AUTHENTICATED','_AUTHENTICATED');
67 define('ACL_ADMIN', '_ADMIN');
68 define('ACL_OWNER', '_OWNER');
69 define('ACL_CREATOR', '_CREATOR');
71 // Walk down the inheritance tree. Collect all permissions until
72 // the minimum required level is gained, which is not
73 // overruled by more specific forbid rules.
74 // Todo: cache result per access and page in session
75 function requiredAuthorityForPage ($action) {
77 // translate action to access
85 $access = 'view'; break;
88 $access = 'dump'; break;
90 $access = 'edit'; break;
92 $page = $this->getPage();
93 $current = $page->getCurrentRevision();
94 if ($current->hasDefaultContents())
106 $access = 'change'; break;
108 if (isWikiWord($action))
114 return _requiredAuthorityForPagename($access,$request->getArg('pagename'));
117 function _requiredAuthorityForPagename ($access,$pagename) {
119 $page = $request->getPage($pagename);
121 $perm = new PagePermission(); // check against default permissions
122 return ($perm->isAuthorized($access,$request->_user) === true);
124 $perm = getPagePermissions($page);
125 $authorized = $perm->isAuthorized($access,$request->_user);
126 if ($authorized != -1)
127 return $authorized ? $request->_user->_level : WIKIAUTH_FORBIDDEN;
129 return _requiredAuthorityForPagename($access,getParentPage($pagename));
134 * @param string $pagename page from which the parent page is searched.
135 * @return string parent pagename or the (possibly pseudo) dot-pagename.
137 function getParentPage($pagename) {
139 if (ifSubPage($pagename)) {
140 return subPageSlice($pagename,0);
146 // read the ACL from the page
147 function getPagePermissions ($page) {
148 $hash = $page->get('perm');
149 if ($hash) // hash => object
150 return new PagePermission(unserialize($hash));
152 return new PagePermission();
155 // store the ACL in the page
156 function setPagePermissions ($page,$perm) {
160 // provide ui helpers to view and change page permissions
161 function displayPagePermissions () {
166 * The ACL object per page. It is stored in a page, but can also
167 * be merged with ACL's from other pages or taken from the master (pseudo) dot-file.
169 * A hash of "access" => "requires" pairs.
170 * "access" is a shortcut for common actions, which map to main.php actions
171 * "requires" required username or groupname or any special group => true or false
173 * Define any special rules here, like don't list dot-pages.
175 class PagePermission {
178 function PagePermission($hash = array()) {
179 if (is_array($hash) and !empty($hash)) {
180 $accessTypes = $this->accessTypes();
181 foreach ($hash as $access => $requires) {
182 if (in_array($access,$accessTypes))
183 $this->perm->{$access} = $requires;
185 trigger_error(sprintf(_("Unsupported ACL access type %s ignored."),$access),
189 // set default permissions, the so called dot-file acl's
190 $this->perm = $this->defaultPerms();
196 * The workhorse to check the user against the current ACL pairs.
197 * Must translate the various special groups to the actual users settings
198 * (userid, group membership).
200 function isAuthorized($access,$user) {
201 if (!empty($this->perm{$access})) {
202 foreach ($this->perm{$access} as $group => $bool) {
203 if ($this->isMember($user,$group))
207 return -1; // undecided
211 * Translate the various special groups to the actual users settings
212 * (userid, group membership).
214 function isMember($group) {
216 if ($group === ACL_EVERY) return true;
217 $member = &WikiGroup::getGroup($request);
218 $user = & $request->_user;
219 if ($group === ACL_ADMIN) // WIKI_ADMIN or member of _("Administrators")
220 return $user->isAdmin() or
221 $member->isMember(GROUP_ADMIN);
222 if ($group === ACL_ANONYMOUS)
223 return ! $user->isSigned();
224 if ($group === ACL_BOGOUSERS)
225 if (ENABLE_USER_NEW) return isa($user,'_BogoUser');
226 else return isWikiWord($user->UserName());
227 if ($group === ACL_SIGNED)
228 return $user->isSigned();
229 if ($group === ACL_AUTHENTICATED)
230 return $user->isAuthenticated();
231 if ($group === ACL_OWNER) {
232 $page = $request->getPage();
233 return $page->get('author') === $user->UserName();
235 if ($group === ACL_CREATOR) {
236 $page = $request->getPage();
237 $rev = $page->getRevision(1);
238 return $rev->get('author') === $user->UserName();
240 /* or named groups or usernames */
241 return $user->UserName() === $group or
242 $member->isMember($group);
246 * returns hash of default permissions.
247 * check if the page '.' exists and returns this instead.
249 function defaultPerms() {
250 //Todo: check for the existance of '.' and take this instead.
251 //Todo: honor more index.php auth settings here
252 $perm = array('view' => array(ACL_EVERY => true),
253 'edit' => array(ACL_EVERY => true),
254 'create' => array(ACL_EVERY => true),
255 'list' => array(ACL_EVERY => true),
256 'remove' => array(ACL_ADMIN => true,
258 'change' => array(ACL_ADMIN => true,
260 if (defined('ZIPDUMP_AUTH') && ZIPDUMP_AUTH)
261 $perm['dump'] = array(ACL_ADMIN => true,
264 $perm['dump'] = array(ACL_EVERY => true);
265 if (defined('REQUIRE_SIGNIN_BEFORE_EDIT') && REQUIRE_SIGNIN_BEFORE_EDIT)
266 $perm['edit'] = array(ACL_SIGNIN => true);
267 if (defined('ALLOW_ANON_USER') && ! ALLOW_ANON_USER) {
268 if (defined('ALLOW_BOGO_USER') && ALLOW_BOGO_USER) {
269 $perm['view'] = array(ACL_BOGOUSER => true);
270 $perm['edit'] = array(ACL_BOGOUSER => true);
271 } elseif (defined('ALLOW_USER_PASSWORDS') && ALLOW_USER_PASSWORDS) {
272 $perm['view'] = array(ACL_AUTHENTICATED => true);
273 $perm['edit'] = array(ACL_AUTHENTICATED => true);
275 $perm['view'] = array(ACL_SIGNIN => true);
276 $perm['edit'] = array(ACL_SIGNIN => true);
282 * returns list of all supported access types.
284 function accessTypes() {
285 return array_keys($this->defaultPerms());
289 * special permissions for dot-files, beginning with '.'
290 * maybe also for '_' files?
292 function dotPerms() {
293 $def = array(ACL_ADMIN => true,
296 foreach ($this->accessTypes as $access) {
297 $perm[$access] = $def;
303 * dead code. not needed inside the object. see getPagePermissions($page)
305 function retrieve($page) {
306 $hash = $page->get('perm');
307 if ($hash) // hash => object
308 return new PagePermission(unserialize($hash));
310 return new PagePermission();
313 function store($page) {
315 return $page->set('perm',serialize(obj2hash($this->perm)));
319 // $Log: not supported by cvs2svn $
320 // Revision 1.1 2004/02/08 12:29:30 rurban
321 // initial version, not yet hooked into lib/main.php
329 // c-hanging-comment-ender-p: nil
330 // indent-tabs-mode: nil