Extension:AutomaticREMOTE USER

From MediaWiki.org

Jump to: navigation, search

         

Manual on MediaWiki Extensions
List of MediaWiki Extensions
Crystal Clear action run.png
Automatic REMOTE_USER Authentication

Release status: beta

Implementation  User identity
Description Automatically logs users using the REMOTE_USER environment variable
Author(s)  Rusty Burchfield, User:Otheus Shelling, James Kinsman
Last Version  1.1
MediaWiki  1.9
License GPLv2
Download see below

check usage (experimental)

Automatic REMOTE_USER Authentication extension automatically logs users using the REMOTE_USER environment variable.

There are several sites using this extension, including at least one using 1.13 and LDAP authentication, but proceed at your own risk!

Save the file as /extensions/Auth_remoteuser.php


Then place the following two lines in your LocalSettings.php file:

require_once('extensions/Auth_remoteuser.php');
$wgAuth = new Auth_remoteuser();

Note: Using this extension sets $wgMinimalPasswordLength to zero

[edit] Code

<?php
// vim:sw=2:softtabstop=2:textwidth=80
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program.  If not, see <http://www.gnu.org/licenses/>.
//
// Copyright 2006 Otheus Shelling
// Copyright 2007 Rusty Burchfield
// Copyright 2009 James Kinsman
//
// In 2009, the copyright holders determined that the original publishing of this code
// under GPLv3 was legally and logistically in error, and re-licensed it under GPLv2.
//
// See http://www.mediawiki.org/wiki/Extension:AutomaticREMOTE_USER
//
// Adapted by Rusty to be compatible with version 1.9 of MediaWiki
// Optional settings from Emmanuel Dreyfus
// Adapted by VibroAxe (James Kinsman) to be compatible with version 1.16 of MediaWiki
// Adapted by VibroAxe (James Kinsman) to allow domain substitution for Integrated Windows Authentication
//
// Add these lines to your LocalSettings.php
//
// /* Optional settings */
// $wgAuthRemoteuserAuthz = true; /* Your own authorization test */
// $wgAuthRemoteuserName = $_SERVER["AUTHENTICATE_CN"]; /* User's name */
// $wgAuthRemoteuserMail = $_SERVER["AUTHENTICATE_MAIL"]; /* User's Mail */
// $wgAuthRemoteuserNotify = false; /* Do not send mail notifications */
// $wgAuthRemoteuserDomain = "NETBIOSDOMAIN" /*Remove NETBIOSDOMAIN\ from the beginning of a IWA username
// /* This is required for Auth_remoteuser operation
// 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.
 
//Extension credits that show up on Special:Version
$wgExtensionCredits['other'][] = array(
        'name' => 'AutomaticREMOTE USER',
        'version' => '1.1',
        'author' => array('Otheus Shelling', 'Rusty Burchfield', 'James Kinsman'),
        'url' => 'http://www.mediawiki.org/wiki/Extension:AutomaticREMOTE_USER',
        'description' => 'Automatically logs users using the REMOTE_USER environment variable.',
);
 
// Don't let anonymous people do things...
$wgGroupPermissions['*']['createaccount']   = false;
$wgGroupPermissions['*']['read']            = false;
$wgGroupPermissions['*']['edit']            = false;
//We must allow zero length passwords
$wgMinimalPasswordLength = 0;
 
// 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;
  global $wgAuthRemoteuserDomain;
 
  // 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();
  }
 
  //Process the username if required
  if (!isset($_SERVER['REMOTE_USER'])) 
  {
	return;
  }
 
  if (isset($wgAuthRemoteuserDomain) && strlen($wgAuthRemoteuserDomain))
  {
	$username = str_replace("$wgAuthRemoteuserDomain\\","",$_SERVER['REMOTE_USER']);
  } else {
	$username = $_SERVER['REMOTE_USER' ];
  }
  // Submit a fake login form to authenticate the 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) {
	switch ($result) {
			case LoginForm :: NO_NAME :
				$errormessage = 'NoName';
				break;
			case LoginForm :: ILLEGAL :
				$errormessage = 'Illegal';
				break;
			case LoginForm :: WRONG_PLUGIN_PASS :
				$errormessage = 'WrongPluginPass';
				break;
			case LoginForm :: NOT_EXISTS :
				$errormessage = 'NotExists';
				break;
			case LoginForm :: WRONG_PASS :
				$errormessage = 'WrongPass';
				break;
			case LoginForm :: EMPTY_PASS :
				$errormessage = 'EmptyPass';
				break;
			default:
				$errormessage = 'Unknown';
				break;
		}
		error_log('Unexpected REMOTE_USER authentication failure. Login Error was:'.$errormessage);
    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
   */
  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
   */
  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;
    global $wgAuthRemoteuserAuthz;
	global $wgAuthRemoteuserDomain;
 
    if (isset($wgAuthRemoteuserAuthz) && $wgAuthRemoteuserAuthz != true)
       return false;
 
	if (isset($_SERVER['REMOTE_USER']) == false)
	{
		$_SERVER['REMOTE_USER'] = "";
	}
	if (!isset($_SERVER['REMOTE_USER']))
	{
		return false;
	}
	if (isset($wgAuthRemoteuserDomain) && strlen($wgAuthRemoteuserDomain)>0) {
		$usertest = str_replace("$wgAuthRemoteuserDomain\\","",$_SERVER['REMOTE_USER']);
	} else {
		$usertest = $_SERVER['REMOTE_USER'];
	}
 
    return (strtolower($username) == strtolower($usertest));
  }
 
  /**
   * 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;
    global $wgAuthRemoteuserName;
    global $wgAuthRemoteuserMail;
    global $wgAuthRemoteuserNotify;
 
    $username = $_SERVER['REMOTE_USER'];
 
    if (isset($wgAuthRemoteuserName))
      $user->setRealName($wgAuthRemoteuserName);
    else
      $user->setRealName('');
 
    if (isset($wgAuthRemoteuserMail))
      $user->setEmail($wgAuthRemoteuserMail);
    else
      $user->setEmail($username . "@example.com");
 
    $user->mEmailAuthenticated = wfTimestampNow();
    $user->setToken();
 
    //turn on e-mail notifications
    if (isset($wgAuthRemoteuserNotify) && $wgAuthRemoteuserNotify) {
        $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;
  }
}
?>

[edit] MediaWiki 1.9.4

To get this extension to work with MediaWiki 1.9.4, I made a couple of horrid hacks because of this error:

Internal error

<password-change-forbidden>

Backtrace:

#0 /var/www/default/mediawiki-1.9.4/includes/User.php(1332): User::setPassword()
#1 /var/www/default/mediawiki-1.9.4/includes/SpecialUserlogin.php(311): User->setPassword('')
#2 /var/www/default/mediawiki-1.9.4/includes/SpecialUserlogin.php(352): LoginForm->initUser(Object(User))
#3 /var/www/default/mediawiki-1.9.4/extensions/Auth_remoteuser.php(77): LoginForm->authenticateUserData()
#4 /var/www/default/mediawiki-1.9.4/includes/Setup.php(219): Auth_remote_user_hook()
#5 /var/www/default/mediawiki-1.9.4/includes/Setup.php(219): call_user_func('Auth_remote_use...')
#6 /var/www/default/mediawiki-1.9.4/includes/WebStart.php(90): require_once('/var/www/defaul...')
#7 /var/www/default/mediawiki-1.9.4/index.php(4): require_once('/var/www/defaul...')
#8 {main}

The horrid hacks:

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;
  }
?>