Whitelisting publicly readable title with regex
This patch make it possible to whitelist pages which anonymous users may see. It is similar to $wgWhitelistRead expect it uses regular expressions, the list of regex are to be added in the new global array $wgWhitelistReadRegexp. This would be useful in a semi-public team wiki situation where the admin would want to hide an entire namespace from everyone except those in a particular group due to sensitive team specific information. Added new unit test testUserCan in includes/TitleTest.php to test this new functionality. * adds $wgWhitelistReadRegexp to DefaultSettings.php * updates RELEASE-NOTES-1.21 new features * updates CREDITS Signed-off-by: Antoine Musso <hashar@free.fr> Change-Id: I83f6a614874c3d289ff4bd8d015f1d9c92e500b6
This commit is contained in:
parent
401aa5c63f
commit
550b878e63
5 changed files with 158 additions and 1 deletions
1
CREDITS
1
CREDITS
|
|
@ -87,6 +87,7 @@ following names for their contribution to the product.
|
|||
|
||||
== Patch Contributors ==
|
||||
* Aaron Pramana
|
||||
* Aaron Ball
|
||||
* Agbad
|
||||
* Ahmad Sherif
|
||||
* Alejandro Mery
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ production.
|
|||
a security fix (bug 42202).
|
||||
* Added the ability to limit the wall clock time used by shell processes,
|
||||
as well as the CPU time. Configurable with $wgMaxShellWallClockTime.
|
||||
* Added $wgWhitelistReadRegexp for regex whitelisting
|
||||
|
||||
=== Bug fixes in 1.21 ===
|
||||
* (bug 40353) SpecialDoubleRedirect should support interwiki redirects.
|
||||
|
|
|
|||
|
|
@ -3816,6 +3816,34 @@ $wgBlockDisablesLogin = false;
|
|||
*/
|
||||
$wgWhitelistRead = false;
|
||||
|
||||
/**
|
||||
* Pages anonymous user may see, set as an array of regular expressions.
|
||||
*
|
||||
* This function will match the regexp against the title name, which
|
||||
* is without underscore.
|
||||
*
|
||||
* @par Example:
|
||||
* To whitelist [[Main Page]]:
|
||||
* @code
|
||||
* $wgWhitelistReadRegexp = array( "/Main Page/" );
|
||||
* @endcode
|
||||
*
|
||||
* @note Unless ^ and/or $ is specified, a regular expression might match
|
||||
* pages not intended to be whitelisted. The above example will also
|
||||
* whitelist a page named 'Security Main Page'.
|
||||
*
|
||||
* @par Example:
|
||||
* To allow reading any page starting with 'User' regardless of the case:
|
||||
* @code
|
||||
* $wgWhitelistReadRegexp = array( "@^UsEr.*@i" );
|
||||
* @endcode
|
||||
* Will allow both [[User is banned]] and [[User:JohnDoe]]
|
||||
*
|
||||
* @note This will only work if $wgGroupPermissions['*']['read'] is false --
|
||||
* see below. Otherwise, ALL pages are accessible, regardless of this setting.
|
||||
*/
|
||||
$wgWhitelistReadRegexp = false;
|
||||
|
||||
/**
|
||||
* Should editors be required to have a validated e-mail
|
||||
* address before being allowed to edit?
|
||||
|
|
|
|||
|
|
@ -2087,7 +2087,7 @@ class Title {
|
|||
* @return Array list of errors
|
||||
*/
|
||||
private function checkReadPermissions( $action, $user, $errors, $doExpensiveQueries, $short ) {
|
||||
global $wgWhitelistRead, $wgRevokePermissions;
|
||||
global $wgWhitelistRead, $wgWhitelistReadRegexp, $wgRevokePermissions;
|
||||
static $useShortcut = null;
|
||||
|
||||
# Initialize the $useShortcut boolean, to determine if we can skip quite a bit of code below
|
||||
|
|
@ -2155,6 +2155,17 @@ class Title {
|
|||
}
|
||||
}
|
||||
|
||||
if( !$whitelisted && is_array( $wgWhitelistReadRegexp ) && !empty( $wgWhitelistReadRegexp ) ) {
|
||||
$name = $this->getPrefixedText();
|
||||
// Check for regex whitelisting
|
||||
foreach ( $wgWhitelistReadRegexp as $listItem ) {
|
||||
if ( preg_match( $listItem, $name ) ) {
|
||||
$whitelisted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !$whitelisted ) {
|
||||
# If the title is not whitelisted, give extensions a chance to do so...
|
||||
wfRunHooks( 'TitleReadWhitelist', array( $this, $user, &$whitelisted ) );
|
||||
|
|
|
|||
|
|
@ -79,6 +79,122 @@ class TitleTest extends MediaWikiTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides test parameter values for testIsValidMoveOperation()
|
||||
*/
|
||||
function dataTestIsValidMoveOperation() {
|
||||
return array(
|
||||
array( 'Test', 'Test', 'selfmove' ),
|
||||
array( 'File:Test.jpg', 'Page', 'imagenocrossnamespace' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Auth-less test of Title::userCan
|
||||
*
|
||||
* @param array $whitelistRegexp
|
||||
* @param string $source
|
||||
* @param string $action
|
||||
* @param array|string|true $expected Required error
|
||||
*
|
||||
* @covers Title::checkReadPermission
|
||||
* @dataProvider dataWgWhitelistReadRegexp
|
||||
*/
|
||||
function testWgWhitelistReadRegexp($whitelistRegexp, $source, $action, $expected) {
|
||||
|
||||
// $wgWhitelistReadRegexp must be an array. Since the provided test cases
|
||||
// usually have only one regex, it is more concise to write the lonely regex
|
||||
// as a string. Thus we cast to an array() to honor $wgWhitelistReadRegexp
|
||||
// type requisite.
|
||||
if( is_string( $whitelistRegexp ) ) {
|
||||
$whitelistRegexp = array( $whitelistRegexp );
|
||||
}
|
||||
|
||||
$title = Title::newFromDBkey( $source );
|
||||
|
||||
global $wgGroupPermissions;
|
||||
$oldPermissions = $wgGroupPermissions;
|
||||
// Disallow all so we can ensure our regex works
|
||||
$wgGroupPermissions = array();
|
||||
$wgGroupPermissions['*']['read'] = false;
|
||||
|
||||
global $wgWhitelistRead;
|
||||
$oldWhitelist = $wgWhitelistRead;
|
||||
// Undo any LocalSettings explicite whitelists so they won't cause a
|
||||
// failing test to succeed. Set it to some random non sense just
|
||||
// to make sure we properly test Title::checkReadPermissions()
|
||||
$wgWhitelistRead = array( 'some random non sense title' );
|
||||
|
||||
global $wgWhitelistReadRegexp;
|
||||
$oldWhitelistRegexp = $wgWhitelistReadRegexp;
|
||||
$wgWhitelistReadRegexp = $whitelistRegexp ;
|
||||
|
||||
// Just use $wgUser which in test is a user object for '127.0.0.1'
|
||||
global $wgUser;
|
||||
// Invalidate user rights cache to take in account $wgGroupPermissions
|
||||
// change above.
|
||||
$wgUser->clearInstanceCache();
|
||||
$errors = $title->userCan( $action, $wgUser );
|
||||
|
||||
// Restore globals
|
||||
$wgGroupPermissions = $oldPermissions;
|
||||
$wgWhitelistRead = $oldWhitelist;
|
||||
$wgWhitelistReadRegexp = $oldWhitelistRegexp;
|
||||
|
||||
if( is_bool( $expected ) ) {
|
||||
# Forge the assertion message depending on the assertion expectation
|
||||
$allowableness = $expected
|
||||
? " should be allowed"
|
||||
: " should NOT be allowed"
|
||||
;
|
||||
$this->assertEquals( $expected, $errors, "User action '$action' on [[$source]] $allowableness." );
|
||||
} else {
|
||||
$errors = $this->flattenErrorsArray( $errors );
|
||||
foreach ( (array)$expected as $error ) {
|
||||
$this->assertContains( $error, $errors );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides test parameter values for testWgWhitelistReadRegexp()
|
||||
*/
|
||||
function dataWgWhitelistReadRegexp() {
|
||||
$ALLOWED = true;
|
||||
$DISALLOWED = false;
|
||||
|
||||
return array(
|
||||
// Everything, if this doesn't work, we're really in trouble
|
||||
array( '/.*/', 'Main_Page', 'read', $ALLOWED ),
|
||||
array( '/.*/', 'Main_Page', 'edit', $DISALLOWED ),
|
||||
|
||||
// We validate against the title name, not the db key
|
||||
array( '/^Main_Page$/', 'Main_Page', 'read', $DISALLOWED ),
|
||||
// Main page
|
||||
array( '/^Main/', 'Main_Page', 'read', $ALLOWED ),
|
||||
array( '/^Main.*/', 'Main_Page', 'read', $ALLOWED ),
|
||||
// With spaces
|
||||
array( '/Mic\sCheck/', 'Mic Check', 'read', $ALLOWED ),
|
||||
// Unicode multibyte
|
||||
// ...without unicode modifier
|
||||
array( '/Unicode Test . Yes/', 'Unicode Test Ñ Yes', 'read', $DISALLOWED ),
|
||||
// ...with unicode modifier
|
||||
array( '/Unicode Test . Yes/u', 'Unicode Test Ñ Yes', 'read', $ALLOWED ),
|
||||
// Case insensitive
|
||||
array( '/MiC ChEcK/', 'mic check', 'read', $DISALLOWED ),
|
||||
array( '/MiC ChEcK/i', 'mic check', 'read', $ALLOWED ),
|
||||
|
||||
// From DefaultSettings.php:
|
||||
array( "@^UsEr.*@i", 'User is banned', 'read', $ALLOWED ),
|
||||
array( "@^UsEr.*@i", 'User:John Doe', 'read', $ALLOWED ),
|
||||
|
||||
// With namespaces:
|
||||
array( '/^Special:NewPages$/', 'Special:NewPages', 'read', $ALLOWED ),
|
||||
array( null, 'Special:Newpages', 'read', $DISALLOWED ),
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
function flattenErrorsArray( $errors ) {
|
||||
$result = array();
|
||||
foreach ( $errors as $error ) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue