Extension:CategoryPermissions

What can this extension do?
Extends permissions checking by allowing group access to pages that have specific categories. This extension utilizes the usercan hook, however standard permissions checks are still performed. Use this extension at your own risk. Any security scheme based on userCan will not prevent page content from being displayed in search results!

Changes

 * 0.31 - Changed line 49 per anonymous note
 * 0.3 - No longer bypasses standard permissions except when denying access. Previous version was working around a problem that was outside the extension in my server configuration.

Usage
See Installation

Installation

 * Copy the code shown in the Code section below to extensions/CategoryPermissions.php
 * I will try to provide a file for download also
 * Make changes to LocalSettings.php as shown below

Changes to LocalSettings.php
require_once("$IP/extensions/CategoryPermissions.php"); $wgGroupDefaultAllow=true; //set to true to allow everyone access to pages without a category $wgCategoryExclusive=array("Category:cat_name","Category:cat2_name");//deny access to these categories for anyone not in the group $wgGroupPermissions['group_name']['Category:categoryname_read']=true; $wgGroupPermissions['group_name']['Category:categoryname_edit']=true; $wgGroupPermissions['group_name']['Category:categoryname_move']=true; $wgGroupPermissions['group_name']['Category:categoryname_create']=true; $wgGroupPermissions['group_name']['*_read']=true; //allow access to all categories

The permissions are checked as follows:
 * 1) Each category in the list is checked for permissions
 * 2) If a category is in the array $wgCategoryExcluseve and the user does not have permissions, access is immediately rejected
 * 3) If the user has permissions for any category and has not been rejected by an exclusive category, they are granted access
 * 4) If global access (*_read, etc) is set for this user, then access is granted
 * 5) If the page has no categories, $wgGroupDefaultAllow is is used to grant or deny access
 * 6) Access is denied ... but we should never get to this step

Code
<?php /* * Custom Permissions Scheme using Categories * based on Extension:NamespacePermissions by Petr Andreev * * Provides separate permissions for each action (read,edit,create,move) based * on category tags on pages. * * Author: Matthew Vernon * Additional Contributions by Carsten Zimmermann * * Licensed under GPL - use,change,enjoy * * Usage: * * require_once('extensions/CategoryPermissions.php'); * $wgCategoryExclusive=array("Category:cat_name","Category:cat2_name");//deny acces to these categories for anyone not in the group * $wgGroupAlwaysAllow=''; //set a group name to ALWAYS allow access to this group * $wgGroupDefaultAllow=true; //set to true to allow everyone access to pages without a category * * * //add groups to category permissions by: * $wgGroupPermissions['group_name']['Category:categoryname_read']=true; * $wgGroupPermissions['group_name']['Category:categoryname_edit']=true; * $wgGroupPermissions['group_name']['Category:categoryname_move']=true; * $wgGroupPermissions['group_name']['Category:categoryname_create']=true; * * //allow access to all groups like this * $wgGroupPermissions['group_name']['*_read']=true; */

//set up hook $wgExtensionFunctions[] = "wfCategoryPermissions";

function wfCategoryPermissions { global $wgHooks;

// use the userCan hook to check permissions $wgHooks[ 'userCan' ][] = 'checkCategoryPermissions'; }

//register extension $wgExtensionCredits['parserhook'][] = array( 'name'=>'CategoryPermissions', 'author'=>'Matthew Vernon', 'url'=>'http://www.mediawiki.org/wiki/Extension:CategoryPermissions');

//turn on debug messages by changing to 1 or true ... is there a better way to do this? define("__debug_permissions",0);

function checkCategoryPermissions( $title, $user, $action, $result ) { global $wgGroupDefaultAllow, $wgGroupPermissions, $wgCategoryExclusive;

$user_allowed=false;

//get categories for this page $parentCategories=$title->getParentCategories;

//scan list of categories, if any if(is_array($parentCategories)) {

foreach( $parentCategories as $category=>$dd) {     if( $user->isAllowed("{$category}_{$action}") ) {       if(__debug_permissions)wfDebug("checkCategoryPermissions:{$category}_{$action} allowed on {$title->mPrefixedText} to {$user->mName}\n"); $user_allowed=true; }     else {       if(in_array($category,$wgCategoryExclusive)) { //if category is in $wgCategoryExclusive then deny anyone who doesn't have explicit access if(__debug_permissions)wfDebug("checkCategoryPermissions:{$category}_{$action} DENIED on {$title->mPrefixedText} to {$user->mName} : Exlcusive Category\n"); $result=false; return false; }     }    }//foreach( $parentCategories as $category=>$dd) }//if($parentCategories)

//if we are here, then no exclusive categories have rejected us if($user_allowed==true) {   return null;  }

//always allow groups with *_read etc. regardless of categories if( $user->isAllowed("*_{$action}") ) {   if(__debug_permissions)wfDebug("checkCategoryPermissions:{$action} allowed on {$title->mPrefixedText} to {$user->mName} : AlwaysAllow\n"); return null; }

if(!($parentCategories)) {   //handle special case of no categories //default action is based on wgGroupDefaultAllow if($wgGroupDefaultAllow) {     if(__debug_permissions)wfDebug("checkCategoryPermissions:{$action} allowed on {$title->mPrefixedText} to {$user->mName} : No Categories\n"); return null; }   else {     if(__debug_permissions)wfDebug("checkCategoryPermissions:{$action} DENIED on {$title->mPrefixedText} to {$user->mName} : No Categories\n"); $result=false; return false; } }

//default action=deny if(__debug_permissions)wfDebug("checkCategoryPermissions:{$action} DENIED on {$title->mPrefixedText} to {$user->mName}\n"); $result=false; return false; }

?>