Mediawiki: Difference between revisions
No edit summary |
No edit summary |
||
Line 76: | Line 76: | ||
These hacks all assume that the Mediawiki application is first protected by something that sets the REMOTE_USER apache server variable, such as the [http://raven.cam.ac.uk/project/apache/ Raven Apache authentication module]. | These hacks all assume that the Mediawiki application is first protected by something that sets the REMOTE_USER apache server variable, such as the [http://raven.cam.ac.uk/project/apache/ Raven Apache authentication module]. | ||
The hacks for 1.5.2 have been really useful, but I've had a couple of problems (maybe my fault): | The hacks for 1.5.2 have been really useful, but I've had a couple of problems (maybe my fault as I notice this wiki is fine with both of these things): | ||
* upload of files | * upload of files requires creation of a "real" wiki account, which Raven users can do, but is a slight faff | ||
* changes are logged against IP rather than Raven ID | |||
This media-wiki extension solves both of these problems, for me, and is easy to implement: | |||
[http://www.mediawiki.org/wiki/Extension:AutomaticREMOTE_USER#mediawiki_1.9.4 Extension:AutomaticREMOTE USER] | |||
Documentation below in case the above disappears: | |||
After installing mediawiki put the text below into: extensions/Auth_remoteuser.php | |||
<pre> | |||
<?php | |||
// vim:sw=2:softtabstop=2:textwidth=80 | |||
// See http://meta.wikimedia.org/wiki/User:Otheus/Auto_Login_via_REMOTE_USER | |||
// Adapted by Rusty to be compatible with version 1.9 of mediawiki | |||
// | |||
// Add these two lines to the bottom of your LocalSettings.php | |||
// require_once('extensions/Auth_remoteuser.php'); | |||
// $wgAuth = new Auth_remoteuser(); | |||
// | |||
// The constructor of Auth_remoteuser registers a hook to do the automatic | |||
// login. Storing the Auth_remoteuser object in $wgAuth tells mediawiki to use | |||
// that object as the AuthPlugin. This way the login attempts by the hook will | |||
// be handled by us. | |||
// | |||
// You probably want to edit the initUser function to set the users real name | |||
// and email address properly for your configuration. | |||
// Don't let anonymous people do things... | |||
$wgGroupPermissions['*']['createaccount'] = false; | |||
$wgGroupPermissions['*']['read'] = false; | |||
$wgGroupPermissions['*']['edit'] = false; | |||
// The Auth_remoteuser class is an AuthPlugin so make sure we have this | |||
// included. | |||
require_once('AuthPlugin.php'); | |||
/** | |||
* This hook is registered by the Auth_remoteuser constructor. It will be | |||
* called on every page load. It serves the function of automatically logging | |||
* in the user. The Auth_remoteuser class is an AuthPlugin and handles the | |||
* actual authentication, user creation, etc. | |||
* | |||
* Details: | |||
* 1. Check to see if the user has a session and is not anonymous. If this is | |||
* true we can just return. | |||
* 2. If the user doesn't have a session, we create a login form with our own | |||
* fake request and ask the form to authenticate the user. If the user does | |||
* not exist authenticateUserData will attempt to create one. The login form | |||
* uses our Auth_remoteuser class as an AuthPlugin. | |||
* | |||
* Note: If cookies are disabled, an infinite loop /might/ occur? | |||
*/ | |||
function Auth_remote_user_hook() { | |||
global $wgUser; | |||
global $wgRequest; | |||
global $_REQUEST; | |||
// For a few special pages, don't do anything. | |||
$title = $wgRequest->getVal('title'); | |||
if (($title == Title::makeName(NS_SPECIAL, 'Userlogout')) || | |||
($title == Title::makeName(NS_SPECIAL, 'Userlogin'))) { | |||
return; | |||
} | |||
// Do nothing if session is valid | |||
$user = User::newFromSession(); | |||
if (!$user->isAnon()) { | |||
return; // User is already logged in and not anonymous. | |||
} | |||
// Copied from includes/SpecialUserlogin.php | |||
if(!isset($wgCommandLineMode) && !isset($_COOKIE[session_name()])) { | |||
wfSetupSession(); | |||
} | |||
// Submit a fake login form to authenticate the user. | |||
$username = $_SERVER['REMOTE_USER' ]; | |||
$params = new FauxRequest(array( | |||
'wpName' => $username, | |||
'wpPassword' => '', | |||
'wpDomain' => '', | |||
'wpRemember' => '' | |||
)); | |||
// Authenticate user data will automatically create new users. | |||
$loginForm = new LoginForm($params); | |||
$result = $loginForm->authenticateUserData(); | |||
if ($result != LoginForm::SUCCESS) { | |||
error_log('Unexpected REMOTE_USER authentication failure.'); | |||
return; | |||
} | |||
$wgUser->setCookies(); | |||
return; // User has been logged in. | |||
} | |||
class Auth_remoteuser extends AuthPlugin { | |||
function Auth_remoteuser() { | |||
// Register our hook function. This hook will be executed on every page | |||
// load. Its purpose is to automatically log the user in, if necessary. | |||
if ( strlen($_SERVER['REMOTE_USER']) ) { | |||
global $wgExtensionFunctions; | |||
if (!isset($wgExtensionFunctions)) { | |||
$wgExtensionFunctions = array(); | |||
} | |||
else if (!is_array($wgExtensionFunctions)) { | |||
$wgExtensionFunctions = array( $wgExtensionFunctions ); | |||
} | |||
array_push($wgExtensionFunctions, 'Auth_remote_user_hook'); | |||
} | |||
return; | |||
} | |||
/** | |||
* Disallow password change. | |||
* | |||
* @return bool | |||
*/ | |||
# mr349, 25/09/2007 | |||
function allowPasswordChange() { | |||
return false; | |||
} | |||
/** | |||
* This should not be called because we do not allow password change. Always | |||
* fail by returning false. | |||
* | |||
* @param $user User object. | |||
* @param $password String: password. | |||
* @return bool | |||
* @public | |||
*/ | |||
# mr349, 25/09/2007 | |||
function setPassword($user, $password) { | |||
return false; | |||
} | |||
/** | |||
* We don't support this but we have to return true for preferences to save. | |||
* | |||
* @param $user User object. | |||
* @return bool | |||
* @public | |||
*/ | |||
function updateExternalDB($user) { | |||
return true; | |||
} | |||
/** | |||
* We can't create external accounts so return false. | |||
* | |||
* @return bool | |||
* @public | |||
*/ | |||
function canCreateAccounts() { | |||
return false; | |||
} | |||
/** | |||
* We don't support adding users to whatever service provides REMOTE_USER, so | |||
* fail by always returning false. | |||
* | |||
* @param User $user | |||
* @param string $password | |||
* @return bool | |||
* @public | |||
*/ | |||
function addUser($user, $password) { | |||
return false; | |||
} | |||
/** | |||
* Pretend all users exist. This is checked by authenticateUserData to | |||
* determine if a user exists in our 'db'. By returning true we tell it that | |||
* it can create a local wiki user automatically. | |||
* | |||
* @param $username String: username. | |||
* @return bool | |||
* @public | |||
*/ | |||
function userExists($username) { | |||
return true; | |||
} | |||
/** | |||
* Check whether the given name matches REMOTE_USER. | |||
* The name will be normalized to MediaWiki's requirements, so | |||
* lower it and the REMOTE_USER before checking. | |||
* | |||
* @param $username String: username. | |||
* @param $password String: user password. | |||
* @return bool | |||
* @public | |||
*/ | |||
function authenticate($username, $password) { | |||
global $_SERVER; | |||
return isset($_SERVER['REMOTE_USER']) && | |||
(strtolower($username) == strtolower($_SERVER['REMOTE_USER'])); | |||
} | |||
/** | |||
* Check to see if the specific domain is a valid domain. | |||
* | |||
* @param $domain String: authentication domain. | |||
* @return bool | |||
* @public | |||
*/ | |||
function validDomain($domain) { | |||
return true; | |||
} | |||
/** | |||
* When a user logs in, optionally fill in preferences and such. | |||
* For instance, you might pull the email address or real name from the | |||
* external user database. | |||
* | |||
* The User object is passed by reference so it can be modified; don't | |||
* forget the & on your function declaration. | |||
* | |||
* @param User $user | |||
* @public | |||
*/ | |||
function updateUser(&$user) { | |||
// We only set this stuff when accounts are created. | |||
return true; | |||
} | |||
/** | |||
* Return true because the wiki should create a new local account | |||
* automatically when asked to login a user who doesn't exist locally but | |||
* does in the external auth database. | |||
* | |||
* @return bool | |||
* @public | |||
*/ | |||
function autoCreate() { | |||
return true; | |||
} | |||
/** | |||
* Return true to prevent logins that don't authenticate here from being | |||
* checked against the local database's password fields. | |||
* | |||
* @return bool | |||
* @public | |||
*/ | |||
function strict() { | |||
return true; | |||
} | |||
/** | |||
* When creating a user account, optionally fill in preferences and such. | |||
* For instance, you might pull the email address or real name from the | |||
* external user database. | |||
* | |||
* @param $user User object. | |||
* @public | |||
*/ | |||
function initUser(&$user) { | |||
global $_SERVER; | |||
$username = $_SERVER['REMOTE_USER']; | |||
// Using your own methods put the users real name here. | |||
$user->setRealName(''); | |||
// Using your own methods put the users email here. | |||
$user->setEmail($username . '@example.com'); | |||
$user->mEmailAuthenticated = wfTimestampNow(); | |||
$user->setToken(); | |||
//turn on e-mail notifications by default | |||
$user->setOption('enotifwatchlistpages', 1); | |||
$user->setOption('enotifusertalkpages', 1); | |||
$user->setOption('enotifminoredits', 1); | |||
$user->setOption('enotifrevealaddr', 1); | |||
$user->saveSettings(); | |||
} | |||
/** | |||
* Modify options in the login template. This shouldn't be very important | |||
* because no one should really be bothering with the login page. | |||
* | |||
* @param $template UserLoginTemplate object. | |||
* @public | |||
*/ | |||
function modifyUITemplate(&$template) { | |||
//disable the mail new password box | |||
$template->set('useemail', false); | |||
//disable 'remember me' box | |||
$template->set('remember', false); | |||
$template->set('create', false); | |||
$template->set('domain', false); | |||
$template->set('usedomain', false); | |||
} | |||
/** | |||
* Normalize user names to the mediawiki standard to prevent duplicate | |||
* accounts. | |||
* | |||
* @param $username String: username. | |||
* @return string | |||
* @public | |||
*/ | |||
function getCanonicalName($username) { | |||
// lowercase the username | |||
$username = strtolower($username); | |||
// uppercase first letter to make mediawiki happy | |||
$username[0] = strtoupper($username[0]); | |||
return $username; | |||
} | |||
} | |||
?> | |||
</pre> | |||
Yes, I have commented by code changes with my CRSID, feel free to replace the comments. | |||
The code changes: | |||
<pre> | |||
Line 111 of ./extensions/Auth_remoteuser.php change the false from: | |||
function allowPasswordChange() { | |||
return false; | |||
} | |||
to: | |||
function allowPasswordChange() { | |||
return true; | |||
} | |||
Same for line 124: | |||
function setPassword($user, $password) { | |||
return false; | |||
} | |||
to: | |||
function setPassword($user, $password) { | |||
return true; | |||
} | |||
</pre> |
Revision as of 07:36, 27 September 2007
Mediawiki is the wiki software powering wikipedia. It can fairly easily be made to work with Raven. The Computing Service has been using a Raven-enabled copy of Mediawiki internally for some time. CARET have a Raven-enabled copy of Mediawiki that is available to the university - see http://wiki.caret.cam.ac.uk/
Software hacks, 1.5.2
These hacks all assume that the Mediawiki application is first protected by something that sets the REMOTE_USER apache server variable, such as the Raven Apache authentication module.
User.php
Line 60, newFromName, replace:
$t = Title::newFromText( $name );
with:
$t = Title::newFromText( $name , NS_USER );
To explicitly specify the namespace. This will be used to check in the hack in Title.php, below.
Line 153, idFromName:
$s = $dbr->selectRow( 'user', array( 'user_id' ), array( 'user_name' => $name ), $fname );
... and in the function loadFromSession():
if ( isset( $_SERVER["REMOTE_USER"] ) ) { $sName = $_SERVER["REMOTE_USER"]; $sId = User::idFromName($sName); $user = new User(); if ( $sId == 0 ) { /* User doesn't exist here yet. */ $user->setName($sName); $user->addToDatabase(); } else { $user->mId = $sId; $user->loadFromDatabase(); } return $user; }
Title.php
Stop the first letter of userpages being capitalised, so we can stick with CRSIDs being all lowercase everywhere. To do this, in the (private) function function secureAndSplit(), replace:
if( $wgCapitalLinks && $this->mInterwiki == '' ) { $t = $wgContLang->ucfirst( $r ); } else { $t = $r; }
With:
if( $wgCapitalLinks && $this->mInterwiki == '' && NS_USER != $this->mNamespace ) { $t = $wgContLang->ucfirst( $r ); } else { $t = $r; }
SkinTemplate.php
To remove the "log out" link at the top of the page, comment out the following section like so:
# $personal_urls['logout'] = array( # 'text' => wfMsg('userlogout'), # 'href' => $this->makeSpecialUrl('Userlogout','returnto=' . $this->thisurl ) # );
Software hacks, 1.9.2
These hacks all assume that the Mediawiki application is first protected by something that sets the REMOTE_USER apache server variable, such as the Raven Apache authentication module.
The hacks for 1.5.2 have been really useful, but I've had a couple of problems (maybe my fault as I notice this wiki is fine with both of these things):
- upload of files requires creation of a "real" wiki account, which Raven users can do, but is a slight faff
- changes are logged against IP rather than Raven ID
This media-wiki extension solves both of these problems, for me, and is easy to implement: Extension:AutomaticREMOTE USER
Documentation below in case the above disappears:
After installing mediawiki put the text below into: extensions/Auth_remoteuser.php
<?php // vim:sw=2:softtabstop=2:textwidth=80 // See http://meta.wikimedia.org/wiki/User:Otheus/Auto_Login_via_REMOTE_USER // Adapted by Rusty to be compatible with version 1.9 of mediawiki // // Add these two lines to the bottom of your LocalSettings.php // require_once('extensions/Auth_remoteuser.php'); // $wgAuth = new Auth_remoteuser(); // // The constructor of Auth_remoteuser registers a hook to do the automatic // login. Storing the Auth_remoteuser object in $wgAuth tells mediawiki to use // that object as the AuthPlugin. This way the login attempts by the hook will // be handled by us. // // You probably want to edit the initUser function to set the users real name // and email address properly for your configuration. // Don't let anonymous people do things... $wgGroupPermissions['*']['createaccount'] = false; $wgGroupPermissions['*']['read'] = false; $wgGroupPermissions['*']['edit'] = false; // The Auth_remoteuser class is an AuthPlugin so make sure we have this // included. require_once('AuthPlugin.php'); /** * This hook is registered by the Auth_remoteuser constructor. It will be * called on every page load. It serves the function of automatically logging * in the user. The Auth_remoteuser class is an AuthPlugin and handles the * actual authentication, user creation, etc. * * Details: * 1. Check to see if the user has a session and is not anonymous. If this is * true we can just return. * 2. If the user doesn't have a session, we create a login form with our own * fake request and ask the form to authenticate the user. If the user does * not exist authenticateUserData will attempt to create one. The login form * uses our Auth_remoteuser class as an AuthPlugin. * * Note: If cookies are disabled, an infinite loop /might/ occur? */ function Auth_remote_user_hook() { global $wgUser; global $wgRequest; global $_REQUEST; // For a few special pages, don't do anything. $title = $wgRequest->getVal('title'); if (($title == Title::makeName(NS_SPECIAL, 'Userlogout')) || ($title == Title::makeName(NS_SPECIAL, 'Userlogin'))) { return; } // Do nothing if session is valid $user = User::newFromSession(); if (!$user->isAnon()) { return; // User is already logged in and not anonymous. } // Copied from includes/SpecialUserlogin.php if(!isset($wgCommandLineMode) && !isset($_COOKIE[session_name()])) { wfSetupSession(); } // Submit a fake login form to authenticate the user. $username = $_SERVER['REMOTE_USER' ]; $params = new FauxRequest(array( 'wpName' => $username, 'wpPassword' => '', 'wpDomain' => '', 'wpRemember' => '' )); // Authenticate user data will automatically create new users. $loginForm = new LoginForm($params); $result = $loginForm->authenticateUserData(); if ($result != LoginForm::SUCCESS) { error_log('Unexpected REMOTE_USER authentication failure.'); return; } $wgUser->setCookies(); return; // User has been logged in. } class Auth_remoteuser extends AuthPlugin { function Auth_remoteuser() { // Register our hook function. This hook will be executed on every page // load. Its purpose is to automatically log the user in, if necessary. if ( strlen($_SERVER['REMOTE_USER']) ) { global $wgExtensionFunctions; if (!isset($wgExtensionFunctions)) { $wgExtensionFunctions = array(); } else if (!is_array($wgExtensionFunctions)) { $wgExtensionFunctions = array( $wgExtensionFunctions ); } array_push($wgExtensionFunctions, 'Auth_remote_user_hook'); } return; } /** * Disallow password change. * * @return bool */ # mr349, 25/09/2007 function allowPasswordChange() { return false; } /** * This should not be called because we do not allow password change. Always * fail by returning false. * * @param $user User object. * @param $password String: password. * @return bool * @public */ # mr349, 25/09/2007 function setPassword($user, $password) { return false; } /** * We don't support this but we have to return true for preferences to save. * * @param $user User object. * @return bool * @public */ function updateExternalDB($user) { return true; } /** * We can't create external accounts so return false. * * @return bool * @public */ function canCreateAccounts() { return false; } /** * We don't support adding users to whatever service provides REMOTE_USER, so * fail by always returning false. * * @param User $user * @param string $password * @return bool * @public */ function addUser($user, $password) { return false; } /** * Pretend all users exist. This is checked by authenticateUserData to * determine if a user exists in our 'db'. By returning true we tell it that * it can create a local wiki user automatically. * * @param $username String: username. * @return bool * @public */ function userExists($username) { return true; } /** * Check whether the given name matches REMOTE_USER. * The name will be normalized to MediaWiki's requirements, so * lower it and the REMOTE_USER before checking. * * @param $username String: username. * @param $password String: user password. * @return bool * @public */ function authenticate($username, $password) { global $_SERVER; return isset($_SERVER['REMOTE_USER']) && (strtolower($username) == strtolower($_SERVER['REMOTE_USER'])); } /** * Check to see if the specific domain is a valid domain. * * @param $domain String: authentication domain. * @return bool * @public */ function validDomain($domain) { return true; } /** * When a user logs in, optionally fill in preferences and such. * For instance, you might pull the email address or real name from the * external user database. * * The User object is passed by reference so it can be modified; don't * forget the & on your function declaration. * * @param User $user * @public */ function updateUser(&$user) { // We only set this stuff when accounts are created. return true; } /** * Return true because the wiki should create a new local account * automatically when asked to login a user who doesn't exist locally but * does in the external auth database. * * @return bool * @public */ function autoCreate() { return true; } /** * Return true to prevent logins that don't authenticate here from being * checked against the local database's password fields. * * @return bool * @public */ function strict() { return true; } /** * When creating a user account, optionally fill in preferences and such. * For instance, you might pull the email address or real name from the * external user database. * * @param $user User object. * @public */ function initUser(&$user) { global $_SERVER; $username = $_SERVER['REMOTE_USER']; // Using your own methods put the users real name here. $user->setRealName(''); // Using your own methods put the users email here. $user->setEmail($username . '@example.com'); $user->mEmailAuthenticated = wfTimestampNow(); $user->setToken(); //turn on e-mail notifications by default $user->setOption('enotifwatchlistpages', 1); $user->setOption('enotifusertalkpages', 1); $user->setOption('enotifminoredits', 1); $user->setOption('enotifrevealaddr', 1); $user->saveSettings(); } /** * Modify options in the login template. This shouldn't be very important * because no one should really be bothering with the login page. * * @param $template UserLoginTemplate object. * @public */ function modifyUITemplate(&$template) { //disable the mail new password box $template->set('useemail', false); //disable 'remember me' box $template->set('remember', false); $template->set('create', false); $template->set('domain', false); $template->set('usedomain', false); } /** * Normalize user names to the mediawiki standard to prevent duplicate * accounts. * * @param $username String: username. * @return string * @public */ function getCanonicalName($username) { // lowercase the username $username = strtolower($username); // uppercase first letter to make mediawiki happy $username[0] = strtoupper($username[0]); return $username; } } ?>
Yes, I have commented by code changes with my CRSID, feel free to replace the comments.
The code changes:
Line 111 of ./extensions/Auth_remoteuser.php change the false from: function allowPasswordChange() { return false; } to: function allowPasswordChange() { return true; } Same for line 124: function setPassword($user, $password) { return false; } to: function setPassword($user, $password) { return true; }