Extension:SimpleSecurity

The general problem with implementing a proper security solution in MediaWiki (giving rise to the scary looking warning box shown above) is that although most of the actions one can perform on articles can be restricted easily, the ability to read content cannot be easily restricted on a per-title basis. The reason reading is difficult to restrict is because it's an operation which is not just performed via one action, but rather that many different actions, special-pages and extensions access article content and display it in diverse ways. To make matters worse, many of these diverse means of article access are done by querying the database directly rather than going via the Article class.

See the technical details section below for more details on this problem and the solution that SimpleSecurity version 4 uses to overcome it. The solution may be considered rather extreme by some developers, but we've found no other way around it yet. The solution is disabled by default (see configuration settings below), it is still functional without it but there are then simple means available to view restricted content such as exporting it or transcluding it in another page.

If you're using an older version of MediaWiki you may need to use an older version of this extension, but please note that versions prior to 4 are unstable, unreliable and are not used in the same way as version 4 and above. The last 3.x version is available [ here]

Installation
Create a SimpleSecurity folder in your extensions directory. Download the latest snapshot and extract it to your extensions directory. Then include it in your LocalSettings.php file as in the following example.

Usage
Installation of the extension The new version is designed to be in line with MediaWiki's own development plans for security. It seems that they won't have a solution to the read problem for some time, but the current method of article protection already allows for restricting edit, create and move actions by group, and allows for the possibility of other actions to be handled, so the approach that Simple Security 4 has taken is to add a new restriction to the existing protection page called read which you can see in the images below which show the protection page with and without Simple Security installed.

The image on the right shows the additional read restriction has become available. Also the tick-box which is used to allow adjustment of the restrictions individually is changed to be more general so it will be appropriate for any number of additional restrictions.

Extended Group Permissions
Note: this function is not complete yet.

SimpleSecurity extends the functionality of the standard $wgGroupPermissions global array so that instead of applying unconditionally to all articles, permissions rules can apply selectively to categories, namespaces or titles conforming to a pattern defined by a regular expression.

Security-based conditions
SimpleSecurity adds two parser-functions for rendering content conditionally based on security permissions or group membership. Here's a couple of examples,

This example renders a link to a todo list if the user has permission to edit the main page, otherwise a link to the news is rendered instead.

Here's the same example again, but this time the conditions is whether or not the user belongs to the sysop group. A comma separated list of groups can be used for the group parameter in which case the condition will evaluate to true if the current user belongs to any of the groups in the list.


 * Notes
 * The last parameter is optional and defaults to an empty string if not supplied
 * Extension:TreeAndMenu can be used with these options since it doesn't render nodes with no content

Unreadable links
If the $wgSecurityAllowUnreadableLinks global is set to false (default), then links to local articles which the current user does not have permission to read are rendered as plain text rather than a hyperlink. The image above shows a small fragment of a recent changes list. Notice that the Sandbox article title and its diff and hist show up grey and are not links, their style can be set in CSS by addressing the unreadable class attribute.

Global security settings
Here are the global variables which affect the operation of the extension. These should be set in your LocalSettings file after the include of the SimpleSecurity.php script.

Technical details
For a more in depth explanation, see the development notes at OrganicDesign:Extension talk:SimpleSecurity.php.

To allow restrictions on the reading of article content requires a hook at a very low-level in the programming which is common to all the kinds of operations involved in the retrieving of article content. The MediaWiki code is written to support a number of different database server's each with their own implementation of the SQL language, and it has also been designed to allow a wiki's database to be served from many servers concurrently. To achieve this, a Database class has been created to abstract the database access functions from the SQL langauge specifics. All database interaction is handled via the methods of the Database class, and specifically, the only way that any legitimate MediaWiki code would obtain any article content is through the fetchRow and fetchObject methods.

So to really solve the per-title read-restriction issue, some of the methods of the Database class would need to be intercepted. There are no official hooks in the methods we need to intercept, so Simple Security version 4 uses a methodology to manipulate the methods at runtime. Some people (probably including most of the core MediaWiki developers) would horrified by this approach and may even consider it to be bordering on voodoo. In fact, we ourselves at Organic Design call the technique voodoo (voodoo's a bit of an exageration really, but it gives us an excuse to put this cool voodoo template on things!), but we have a number of clients running mediawiki on their intranets who have been in dire need of a reasonable means of restricting their content on a per-title basis, but are also dead-set on sticking with MediaWiki. Unfortunately this is the only solution we've been able to come up with for them, but testing so far is showing positive results and should be no problem for all but the very high traffic sites.

The function which implements the voodoo is wfAddDatabaseHooks, it first creates a new Database class which is based on the one currently in use but has "2" appended to its name and has its query and fetchObject methods overridden. Unfortunately this is not the end of the story, because every time a new database connection is requested, it will of course return an instance of the normal class such as DatabaseMysql instead of DatabaseMysql2. So the class responsible for returning database connection objects must also be replaced which is the LoadBalancer class. Luckily the LoadBalancer is a singleton which means we can sneakily switch it for an exact replica except that it's of class LoadBalancer2 which has its reallyOpenConnection method replaced with one that instantiates and returns an instances of the new database class.

All text content is held in the old_text field of the text table, so the row-reading needs to be intercepted. But the SELECT queries also have to be adjusted to ensure that the old_id field is available along with old_text otherwise it cannot be established whether or not the text is allowed to be viewed (since the id is needed to relate the text fragment with a current article title). The query method of the database class has been overridden to patch the SQL, and fetchObject has been overridden to replace the content of the requested old_text field if it should not be accessible.