Extension:PermissionACL
From MediaWiki.org
For further details, see Security issues with authorization extensions
|
PermissionACL Release status: beta |
|||
|---|---|---|---|
| Implementation | User rights | ||
| Description | implements per-{namespace, page, category, user, group} access permissions | ||
| Author(s) | Jan Vavříček (VavricekTalk) | ||
| License | GPL | ||
| Download | Code | ||
|
|||
|
|||
Contents |
[edit] What can this extension do?
The PermissionACL extension implements a way to restrict access to specific {namespaces, pages, categories} based on user group or user name. This provides a more fine grained security model than the one provided by the default $wgGroupPermissions.
PermissionACL extension configuration is based on ACL (Access Control List) - list of rules which are processing from first to last. First applicable rule is used! On the end of list is implicit rule DENY TO ALL!
[edit] Usage
If $wgPermissionACL is set, then ACL model is used - if not, extension do nothing.
Rules are array elements and their order in array is used by ACL mechanism.
Syntax of rules (every rule has 4 parts):
- which page : select of pages (namespaces, categories)
- which user : select of users (groups)
- which action : select of actions ( userCan actions - read, edit, create, move)
- operation : permit or deny access
First, second and third rule part can be:
- one value
- array of values
- ALL (represented by asterisk)
[edit] Example 1
Story about:
- namespaces: Private, Ccna, Ccnp, Ns, Fwl
- user groups: private, ccna, ccnp, ns, fwl;
- group ccna has RW access only to namespace Ccna, group fwl to Fwl, ...
- group private has RW access to every namespace
- unlogged users can only read NS_MAIN namespace
- administrator (user wikisysop, vav166) can do everything
require_once('$IP/extensions/PermissionACL/PermissionACL.php'); $wgExtraNamespaces = array( 100 => "Private", 101 => "Private_Talk", 102 => "Ccna", 103 => "Ccna_Talk", 104 => "Ccnp", 105 => "Ccnp_Talk", 106 => "Ns", 107 => "Ns_Talk", 108 => "Fwl", 109 => "Fwl_Talk" ); $wgGroupPermissions['ccna']['read'] = true; $wgGroupPermissions['ccnp']['read'] = true; $wgGroupPermissions['ns']['read'] = true; $wgGroupPermissions['fwl']['read'] = true; $wgGroupPermissions['private']['read'] = true; //whitelist is used, but same thing can be done by ACL: /* $wgPermissionACL[] = array('group' => '*', 'page' => array('Special:UserLogin', 'Special:UserLogout', 'Special:Resetpass', 'Special:Confirmemail'), 'action' => 'read', 'operation' => 'permit'); */ $wgWhitelistRead = array('Special:Userlogin', 'Special:Userlogout', 'Special:Resetpass', 'Special:Confirmemail'); //Superuser is only simplification - same result will have ACL: /* $wgPermissionACL[] = array('user' => array('wikisysop', 'vav166'), 'page' => '*' 'action' => '*', 'operation' => 'permit'); */ $wgPermissionACL_Superuser = array('wikisysop', 'vav166'); $wgPermissionACL[] = array('group' => '*', 'namespace' => NS_MAIN, 'action' => 'read', 'operation' => 'permit'); $wgPermissionACL[] = array('group' => 'user', 'namespace' => array(NS_MAIN, NS_SPECIAL, NS_USER, NS_CATEGORY), 'action' => 'read', 'operation' => 'permit'); $wgPermissionACL[] = array('group' => 'private', 'namespace' => array(100, 101, 102, 103, 104, 105, 106, 107, 108, 109), 'action' => '*', 'operation' => 'permit'); $wgPermissionACL[] = array('group' => 'ccna', 'namespace' => array(102, 103), 'action' => '*', 'operation' => 'permit'); $wgPermissionACL[] = array('group' => 'ccnp', 'namespace' => array(104, 105), 'action' => '*', 'operation' => 'permit'); $wgPermissionACL[] = array('group' => 'ns', 'namespace' => array(106, 107), 'action' => '*', 'operation' => 'permit'); $wgPermissionACL[] = array('group' => 'fwl', 'namespace' => array(108, 109), 'action' => '*', 'operation' => 'permit');
[edit] Download instructions
Please cut and paste the code found below and place it in $IP/extensions/PermissionACL/PermissionACL.php.
Note: $IP stands for the root directory of your MediaWiki installation, the same directory that holds LocalSettings.php.
[edit] Installation
To install this extension, add the following to LocalSettings.php:
require_once("$IP/extensions/PermissionACL/PermissionACL.php"); #add configuration parameters here #setup user rights here
[edit] Code
<?php if( !defined( 'MEDIAWIKI' ) ) { echo("This file is an extension to the MediaWiki software and cannot be used standalone.\n"); die(1); } $wgExtensionCredits['other'][] = array( 'name' => 'PermissionACL', 'author' => 'Jan Vavříček', 'url' => 'http://mediawiki.org/wiki/Extension:PermissionACL', 'description' => 'permissions access control list', ); $wgHooks['userCan'][] = 'PermissionACL_userCan'; function PermissionACL_userCan($title, $user, $action, &$result) { global $wgPermissionACL, $wgPermissionACL_Superuser, $wgWhitelistRead; $result = NULL; if(!isset($wgPermissionACL)) return TRUE; //if not set - grant access if($title->isCssJsSubpage()) return TRUE; if($action == 'read' && is_array($wgWhitelistRead)) { //don't continue if - read action on whitelisted pages if(in_array($title->getPrefixedText(), @$wgWhitelistRead)) { $result = TRUE; return TRUE; }//if-in_array }//if-whitelist if(isset($wgPermissionACL_Superuser)) { //Superuser can do everything - no need to read ACLs if(is_array($wgPermissionACL_Superuser)) { if(in_array(strtolower($user->getName()), ArrayToLower($wgPermissionACL_Superuser))) return TRUE; }//if-superusers array else if(strtolower($user->getName()) == strtolower($wgPermissionACL_Superuser)) return TRUE; }//if-superuser foreach($wgPermissionACL as $rule) { //process ACLs if(!PermissionACL_isRuleValid($rule)) continue; //syntax checking if(PermissionACL_isRuleApplicable($rule, $title, $user, $action)) { if(PermissionACL_Permit($rule)) { $result = TRUE; return TRUE; } else { $result = FALSE; return FALSE; } }//if-applicable }//foreach //implicit end rule - DENY ALL $result = FALSE; return FALSE; }//PermissionACL_userCan function PermissionACL_isRuleValid($rule) { /* rule parts: 'group' || 'user' 'namespace' || 'page' || 'category' 'action' = (read, edit, create, move, *) 'operation' = (permit, deny) */ $tmp_actions = array('read', 'edit', 'create', 'move', '*'); $tmp_operations = array('permit', 'deny'); if( ( isset($rule['group']) && !isset($rule['user'])) || (!isset($rule['group']) && isset($rule['user'])) ) { if( ( isset($rule['namespace']) && !isset($rule['page']) && !isset($rule['category'])) || (!isset($rule['namespace']) && isset($rule['page']) && !isset($rule['category'])) || (!isset($rule['namespace']) && !isset($rule['page']) && isset($rule['category'])) ) { if( isset($rule['action']) && ((is_string($rule['action']) && in_array($rule['action'], $tmp_actions)) || is_array($rule['action']) )) { if( isset($rule['operation']) && in_array($rule['operation'], $tmp_operations)) { return TRUE; }//if-operation test }//if-action test }//if-namespace, page, category test }//if-user, group test return FALSE; }//function PermissionACL_isRuleValid function PermissionACL_isRuleApplicable($rule, $title, $user, $action) { //group|user rule if(isset($rule['group'])) { //group rule if(is_array($rule['group'])) $tmp = ArrayToLower($rule['group']); else $tmp = strtolower($rule['group']); $groups = ArrayToLower($user->getEffectiveGroups()); if(!( (is_string($tmp) && in_array($tmp, $groups)) || (is_array($tmp) && count(array_intersect($tmp, $groups))>0) )) return FALSE; } else { // user rule if(is_array($rule['user'])) $tmp = ArrayToLower($rule['user']); else $tmp = strtolower($rule['user']); $tmp2 = strtolower($user->getName()); if(!( (is_string($tmp) && $tmp=='*') || (is_string($tmp) && $tmp==$tmp2) || (is_array($tmp) && in_array($tmp2, $tmp)) )) return FALSE; } //namespace|page|category rule if(isset($rule['namespace'])) { //namespace rule $tmp = $rule['namespace']; $tmp2 = $title->getNamespace(); if(!( (is_int($tmp) && $tmp==$tmp2) || (is_string($tmp) && $tmp=='*') || (is_array($tmp) && in_array($tmp2, $tmp)) )) return FALSE; } else if(isset($rule['page'])){ //page rule $tmp = $rule['page']; $tmp2 = $title->getPrefixedText(); if(!( (is_string($tmp) && $tmp==$tmp2) || (is_string($tmp) && $tmp=='*') || (is_array($tmp) && in_array($tmp2, $tmp)) )) return FALSE; } else { //category rule $tmp = $rule['category']; $tmp2 = $title->getParentCategories(); $categs = array(); if(is_array($tmp2)) { global $wgContLang; $tmp_pos = strrpos($wgContLang->getNSText(NS_CATEGORY), ':'); foreach($tmp2 as $cat => $page) { if($tmp_pos === FALSE) { $categs[] = substr($cat, strpos($cat, ':')+1); } else { $tmp_categ = substr($cat, $tmp_pos+1); $categs[] = substr($tmp_categ, strpos($tmp_categ, ':')+1); } } } if(!( (is_string($tmp) && is_array($tmp2) && in_array($tmp, $categs)) || (is_string($tmp) && $tmp=='*') || (is_array($tmp) && is_array($tmp2) && count(array_intersect($tmp, $categs))>0) )) return FALSE; } //action rule if(is_array($rule['action'])) $tmp = ArrayToLower($rule['action']); else $tmp = strtolower($rule['action']); if(!( ($tmp == $action) || (is_string($tmp) && $tmp=='*') || (is_array($tmp) && in_array($action, $tmp)) )) return FALSE; return TRUE; }//function PermissionACL_isRuleApplicable function PermissionACL_Permit($rule) { if($rule['operation'] == 'permit') return TRUE; return FALSE; }//function PermissionACL_Permit function ArrayToLower($ar) { $tmp = array(); foreach($ar as $index => $value) $tmp[$index] = strtolower($value); return $tmp; }//function ArrayToLower ?>

