Difference between revisions of "Extension:SimpleSecurity2.1.php"

From Organic Design wiki
m
m (sortkey)
Line 246: Line 246:
 
}
 
}
 
?></php>
 
?></php>
[[Category:Extensions]]
+
[[Category:Extensions|SimpleSecurity2.1]]

Revision as of 22:00, 18 July 2007

Legacy.svg Legacy: This article describes a concept that has been superseded in the course of ongoing development on the Organic Design wiki. Please do not develop this any further or base work on this concept, this is only useful for a historic record of work done. You may find a link to the currently used concept or function in this article, if not you can contact the author to find out what has taken the place of this legacy item.

<php><?

  1. THIS SCRIPT IS OBSOLETE!
  2. for the newer Version 3.1 (2007-03-14) see:
  3. http://www.organicdesign.co.nz/SimpleSecurity.php
  4. and also the whole help and needed reference at:
  5. http://www.mediawiki.org/wiki/Extension:Simple_Security
  6. ------------------------------------------------------------------------------------#
  7. - Version 2.1 (2007-03-09)
  8. - See http://www.organicdesign/MediaWiki_Security for installation and usage details
  9. - Licenced under LGPL (http://www.gnu.org/copyleft/lesser.html)
  10. - Needs apache's mod-rewrite for security on images, see code comments below
  11. - The following directives allows everyone view-only access to this article
  12. Template:Security:*
  13. Template:Security:view
  1. These globals can be set in LocalSettings to adjust the Simple Security attributes

if (!isset($wgSecurityName)) $wgSecurityName = "Security"; if (!isset($wgSecurityDontInheritName)) $wgSecurityDontInheritName = "*$wgSecurityName"; if (!isset($wgSecurityInheritable)) $wgSecurityInheritable = true;

  1. Handle moves (since they don't use $action)

$securityAction = $action == 'submit' ? 'edit' : strtolower($action); if ($title == 'Special:Movepage' && $action == 'submit') { $securityAction = 'move'; $securityTitle = $wgRequest->getText('wpOldTitle',$wgRequest->getVal('target')); } else $securityTitle = str_replace(' ','_',$title);

  1. If title exists, activate the security

if ($securityTitle) {

# Globals holding security info $securityDenyRevisionID = 2575; # the current-revision-id of the Template:Action not permitted $securityCache = array(); $securityItems = array();

# Handle security on files (needs apache mod-rewrite) # - mod-rewrite redirects /wiki/images/... requests to article title Download/image-path... # - Use the following rewrite condition and rule (adjust to your wiki path if necessary) # RewriteCond %{REQUEST_URI} ^/wiki/images/.+ # RewriteRule ^/wiki/images/(.+) /wiki/index.php/Download/$1 [L] if (ereg('^Download/(.+)/([^/]+)$',$securityTitle,$m)) { $path = $m[1]; $file = $image = $m[2]; if (ereg('^thumb/.+/([^/]+)$',$path,$m)) $image = $m[1]; $securityTitle = "Image:$image"; } else $file = ; if (0) { # Create a new secureLoadBalancer class by extending the existing one $LoadBalancer = get_class($wgLoadBalancer); $secureLoadBalancer = "secure$LoadBalancer"; eval('class '.$secureLoadBalancer.' extends '.$LoadBalancer.' {

# Override the getConnection method to return a secureDatabase connection function &getConnection($i, $fail = true, $groups = array()) { $db =& parent::getConnection($i,$fail,$groups);

# Create a secure subclass of the database class with extended fetchObject method $dbClass = get_class($db); $dbSecure = "secure$dbClass"; if (!class_exists($dbSecure)) { eval(\'class \'.$dbSecure.\' extends \'.$dbClass.\' { function fetchObject($res) { $row = parent::fetchObject($res); wfRunHooks("DatabaseFetchObject", array(&$this,&$row)); return $row; } }\'); }

# Replace the DatabaseXXX connection with an identical secureDatabaseXXX connection $sdb = new $dbSecure; foreach(array_keys(get_class_vars($dbClass)) as $k) $sdb->$k = $db->$k; unset($db);

return $sdb; }

}');

# Replace the global LoadBalancer object with an identical secureLoadBalancer $oldLoadBalancer = $wgLoadBalancer; $wgLoadBalancer = new $secureLoadBalancer; foreach(array_keys(get_class_vars($LoadBalancer)) as $k) $wgLoadBalancer->$k = $oldLoadBalancer->$k;

# Add our security function to the new hook # - also fills the global $securityCache cache with info to append to the rendered article #$wgHooks['DatabaseFetchObject'][] = 'securityAfterFetchObject'; function securityAfterFetchObject(&$db,&$row) { if (is_object($row) && $row->rev_text_id) { if ($row->rev_text_id == 2638) { $row->rev_text_id = $securityDenyRevisionID; msg($db->lastQuery()); } } } } # Hook2: Asseses security after raw content fetched from database and clears if not readable # - also fills the global $securityCache cache with info to append to the rendered article $wgHooks['ArticleAfterFetchContent'][] = 'securityAfterFetchContent'; $securityAfterFetchActive = true; function securityAfterFetchContent(&$article,&$text) { global $wgUser,$wgTitle,$securityItems,$securityCache,$securityAfterFetchActive, $wgSecurityName,$wgSecurityDontInheritName,$wgSecurityInheritable; if (!$securityAfterFetchActive) return true;

# Get the security info straight from cache if already exists $key = $article->mTitle->getPrefixedURL();

if (isset($securityCache[$key])) $items = $securityCache[$key]; else {

# Set up a new local parser object to process security items independently of main rendering process # - both Security and *Security items are processed and remembered $parser = new Parser; $options = ParserOptions::newFromUser($wgUser); $parser->setFunctionHook($wgSecurityName,'securityProcessItem'); $parser->setFunctionHook($wgSecurityDontInheritName,'securityProcessItem'); $securityItems = array(); $output = $parser->parse($text,$wgTitle,$options,false,false); $items = $securityItems;

# Before inheriting security from categories # - stop checking *Security because they shouldn't inherit # - disable this AfterDatabaseFetch hook while reading category contents unset($parser->mFunctionHooks[$wgSecurityDontInheritName]); $securityAfterFetchActive = false;

# Get the security items from the cats by running the parser over the content of each if ($wgSecurityInheritable) foreach ($output->getCategoryLinks() as $cat) { $ca = new Article($ct = Title::newFromText($cat = "Category:$cat")); $securityItems = array(); $parser->parse($ca->fetchContent(0,false,false),$ct,$options,false,false); foreach ($securityItems as $i) $items[] = array($i[0],$i[1],"this rule is inherited from $cat"); }

# Re-enable AfterFetch hook and cache the security info $securityAfterFetchActive = true; $securityCache[$key] = $items; }

# Don't allow any content to be returned if not viewable

if (!securityValidate($wgUser,$items,'view')) $text = "

Sorry, action not permitted!

Your user rights do not permit the view action to be performed on this article.

"; return true; }

# Hook3: Block content if action not allowed, and append any security info before parsing $wgHooks['ParserBeforeStrip'][] = 'securityBeforeParsing'; function securityBeforeParsing(&$parser,&$text,&$strip_state) { global $wgParser,$wgUser,$securityAllow,$securityCache,$securityAction,$wgSecurityName,$wgSecurityDontInheritName;

# Only process this hook if it's the main article if ($parser != $wgParser) return true; $key = $parser->mTitle->getPrefixedURL();

# Replace the content with the "Action not permitted" template if action not allowed

if (!$securityAllow) $text = "

Sorry, action not permitted!

Your user rights do not permit the $securityAction action to be performed on this article.

";

# Append the security info to the article content if (count($securityCache[$key]) && $securityAction == 'view') { $text .= "\n

Padlock.svg

There are security restrictions on this article (for information about this extension, click here)

\n"; foreach ($securityCache[$key] as $i) { $a = $i[0] == '*' ? 'Every action' : ucfirst($i[0]); $b = $i[1] == '*' ? 'anybody' : $i[1]; $c = $i[2] ? " ($i[2])" : ; $text .= "*$a requires the user to be $b$c\n"; } $text .= "\n

";

}

# Ensure the parser doesn't render the security items $parser->setFunctionHook($wgSecurityName,'securityProcessItem'); $parser->setFunctionHook($wgSecurityDontInheritName,'securityProcessItem'); return true; }

# Accumulates security information in the global $securityItems whenever a security item is parsed function securityProcessItem(&$parser,$a,$b) { global $securityItems; $securityItems[] = array($a,$b); return ; }

# Return whether or not a user is allowed to perform an action according to an array of security items function securityValidate(&$user,&$items,$action) { if (!is_array($items)) return true;

# Resolve permission for this action from the extracted security links $security = ; foreach ($items as $i) { if ($i[1] == ) $i[1] = 'sysop'; $actions = preg_split("/\\s*,\\s*/",strtolower($i[0])); if ((in_array($action,$actions)) || (in_array('*',$actions) && ($security == ))) $security = $i[1]; }

# Validate extracted security against this user/groups $groups = $user->getGroups(); foreach($groups as $k => $v) $groups[$k] = strtolower($v); $deny = false; if ($security && !in_array('sysop',$groups) && !in_array('director',$groups)) { $security = preg_split("/\\s*,\\s*/",$security); if (!in_array('*',$security)) { $groups[] = ucfirst($user->mName); if (count(array_intersect($groups,$security))==0) $deny = true; } }

return !$deny; }

# Read the article content to update security info cache $tmp = new Article(Title::newFromText($securityTitle)); $tmp->fetchContent(0,false,false); $items = $securityCache[$securityTitle];

# Validate current action and set to view if not allowed if (!$securityAllow = securityValidate($wgUser,$items,$securityAction)) $action = 'view';

# If its a file, send it back to the client and exit, or block by redirecting to the file's associated article if ($file) {

# Log the download event if any security on file if (count($items)) { $user = $wgUser->mName; $entry = $securityAllow ? "User:$user accessed \"$file\"" : "User:$user was denied access to \"$file\""; $ts = $wgLang->timeanddate(wfTimestampNow(),true); $la = new Article(Title::newFromText('Download log')); $log = "{{Log entry". "|ts=$ts". "|entry=$entry". "|ip=".$_SERVER['REMOTE_ADDR']. "|ua=".$_SERVER['HTTP_USER_AGENT']. "|cookie=".$_SERVER['HTTP_COOKIE']. "|qs=".$_SERVER['QUERY_STRING']. "}}\n"; $la->quickEdit($log.$la->fetchContent(0,false,false)); }

# Return the file to the client if security validates if ($securityAllow) { header("Content-Type: application/octet-stream"); header("Content-Disposition: attachment; filename=\"$file\""); @readfile("$wgUploadDirectory/$path/$file"); die; } else $title = $securityTitle; } } ?></php>