r83092 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r83091‎ | r83092 | r83093 >
Date:15:48, 2 March 2011
Author:reedy
Status:deferred (Comments)
Tags:
Comment:
Initial import of [[Extension:AutomaticREMOTE_USER/code]]
Modified paths:
  • /trunk/extensions/Auth_remoteuser (added) (history)
  • /trunk/extensions/Auth_remoteuser/Auth_remoteuser.php (added) (history)

Diff [purge]

Index: trunk/extensions/Auth_remoteuser/Auth_remoteuser.php
@@ -0,0 +1,458 @@
 2+<?php
 3+// vim:sw=2:softtabstop=2:textwidth=80
 4+//
 5+// This program is free software: you can redistribute it and/or modify it
 6+// under the terms of the GNU General Public License as published by the Free
 7+// Software Foundation, either version 2 of the License, or (at your option)
 8+// any later version.
 9+//
 10+// This program is distributed in the hope that it will be useful, but WITHOUT
 11+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 12+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 13+// more details.
 14+//
 15+// You should have received a copy of the GNU General Public License along with
 16+// this program. If not, see <http://www.gnu.org/licenses/>.
 17+//
 18+// Copyright 2006 Otheus Shelling
 19+// Copyright 2007 Rusty Burchfield
 20+// Copyright 2009 James Kinsman
 21+// Copyright 2010 Daniel Thomas
 22+// Copyright 2010 Ian Ward Comfort
 23+//
 24+// In 2009, the copyright holders determined that the original publishing of this code
 25+// under GPLv3 was legally and logistically in error, and re-licensed it under GPLv2.
 26+//
 27+// See http://www.mediawiki.org/wiki/Extension:AutomaticREMOTE_USER
 28+//
 29+// Adapted by Rusty to be compatible with version 1.9 of MediaWiki
 30+// Optional settings from Emmanuel Dreyfus
 31+// Adapted by VibroAxe (James Kinsman) to be compatible with version 1.16 of MediaWiki
 32+// Adapted by VibroAxe (James Kinsman) to allow domain substitution for Integrated Windows Authentication
 33+// Adapted by drt24 (Daniel Thomas) to add the optional $wgAuthRemoteuserMailDomain and remove hardcoding
 34+// of permissions for anonymous users.
 35+// Adapted by Ian Ward Comfort to detect mismatches between the session user and REMOTE_USER
 36+//
 37+// Add these lines to your LocalSettings.php
 38+//
 39+// /* Optional settings */
 40+// $wgAuthRemoteuserAuthz = true; /* Your own authorization test */
 41+// $wgAuthRemoteuserName = $_SERVER["AUTHENTICATE_CN"]; /* User's name */
 42+// $wgAuthRemoteuserMail = $_SERVER["AUTHENTICATE_MAIL"]; /* User's Mail */
 43+// $wgAuthRemoteuserNotify = false; /* Do not send mail notifications */
 44+// $wgAuthRemoteuserDomain = "NETBIOSDOMAIN"; /* Remove NETBIOSDOMAIN\ from the beginning or @NETBIOSDOMAIN at the end of a IWA username */
 45+// /* User's mail domain to append to the user name to make their email address */
 46+// $wgAuthRemoteuserMailDomain = "example.com";
 47+// // Don't let anonymous people do things...
 48+// $wgGroupPermissions['*']['createaccount'] = false;
 49+// $wgGroupPermissions['*']['read'] = false;
 50+// $wgGroupPermissions['*']['edit'] = false;
 51+//
 52+// /* This is required for Auth_remoteuser operation
 53+// require_once('extensions/Auth_remoteuser.php');
 54+// $wgAuth = new Auth_remoteuser();
 55+//
 56+// The constructor of Auth_remoteuser registers a hook to do the automatic
 57+// login. Storing the Auth_remoteuser object in $wgAuth tells mediawiki to use
 58+// that object as the AuthPlugin. This way the login attempts by the hook will
 59+// be handled by us.
 60+//
 61+// You probably want to edit the initUser function to set the users real name
 62+// and email address properly for your configuration.
 63+
 64+//Extension credits that show up on Special:Version
 65+$wgExtensionCredits['other'][] = array(
 66+ 'name' => 'AutomaticREMOTE USER',
 67+ 'version' => '1.1.3',
 68+ 'author' => array('Otheus Shelling', 'Rusty Burchfield', 'James Kinsman', 'Daniel Thomas', 'Ian Ward Comfort'),
 69+ 'url' => 'http://www.mediawiki.org/wiki/Extension:AutomaticREMOTE_USER',
 70+ 'description' => 'Automatically logs users using the REMOTE_USER environment variable.',
 71+);
 72+
 73+//We must allow zero length passwords. This extension does not work in MW 1.16 without this.
 74+$wgMinimalPasswordLength = 0;
 75+
 76+// The Auth_remoteuser class is an AuthPlugin so make sure we have this
 77+// included.
 78+require_once('AuthPlugin.php');
 79+
 80+/**
 81+ * This hook is registered by the Auth_remoteuser constructor. It will be
 82+ * called on every page load. It serves the function of automatically logging
 83+ * in the user. The Auth_remoteuser class is an AuthPlugin and handles the
 84+ * actual authentication, user creation, etc.
 85+ *
 86+ * Details:
 87+ * 1. Check to see if the user has a session and is not anonymous. If this is
 88+ * true, check whether REMOTE_USER matches the session user. If so, we can
 89+ * just return; otherwise we must logout the session user and login as the
 90+ * REMOTE_USER.
 91+ * 2. If the user doesn't have a session, we create a login form with our own
 92+ * fake request and ask the form to authenticate the user. If the user does
 93+ * not exist authenticateUserData will attempt to create one. The login form
 94+ * uses our Auth_remoteuser class as an AuthPlugin.
 95+ *
 96+ * Note: If cookies are disabled, an infinite loop /might/ occur?
 97+ */
 98+function Auth_remote_user_hook() {
 99+ global $wgUser;
 100+ global $wgRequest;
 101+ global $_REQUEST;
 102+ global $wgAuthRemoteuserDomain;
 103+
 104+ // For a few special pages, don't do anything.
 105+ $title = $wgRequest->getVal('title');
 106+ if (($title == Title::makeName(NS_SPECIAL, 'UserLogout')) ||
 107+ ($title == Title::makeName(NS_SPECIAL, 'UserLogin'))) {
 108+ return;
 109+ }
 110+
 111+ //Process the username if required
 112+ if (!isset($_SERVER['REMOTE_USER']))
 113+ {
 114+ return;
 115+ }
 116+ if (isset($wgAuthRemoteuserDomain) && strlen($wgAuthRemoteuserDomain))
 117+ {
 118+ $username = str_replace("$wgAuthRemoteuserDomain\\","",$_SERVER['REMOTE_USER']);
 119+ $username = str_replace("@$wgAuthRemoteuserDomain","",$username);
 120+ } else {
 121+ $username = $_SERVER['REMOTE_USER'];
 122+ }
 123+
 124+ // Check for valid session
 125+ $user = User::newFromSession();
 126+ if (!$user->isAnon()) {
 127+ if ($user->getName() == Auth_remoteuser::getCanonicalName($username)) {
 128+ return; // Correct user is already logged in.
 129+ } else {
 130+ $user->doLogout(); // Logout mismatched user.
 131+ }
 132+ }
 133+
 134+ // Copied from includes/SpecialUserlogin.php
 135+ if(!isset($wgCommandLineMode) && !isset($_COOKIE[session_name()])) {
 136+ wfSetupSession();
 137+ }
 138+
 139+ // If the login form returns NEED_TOKEN try once more with the right token
 140+ $tryagain=false;
 141+ $trycount=0;
 142+ $token = '';
 143+ do
 144+ {
 145+ $tryagain=false;
 146+ // Submit a fake login form to authenticate the user.
 147+ $params = new FauxRequest(array(
 148+ 'wpName' => $username,
 149+ 'wpPassword' => '',
 150+ 'wpDomain' => '',
 151+ 'wpLoginToken' => $token,
 152+ 'wpRemember' => ''
 153+ ));
 154+
 155+ // Authenticate user data will automatically create new users.
 156+ $loginForm = new LoginForm($params);
 157+ $result = $loginForm->authenticateUserData();
 158+ switch ($result) {
 159+ case LoginForm :: SUCCESS :
 160+ $wgUser->setOption('rememberpassword', 1);
 161+ $wgUser->setCookies();
 162+ break;
 163+ case LoginForm :: NEED_TOKEN:
 164+ $token = $loginForm->getLoginToken();
 165+ $tryagain=($trycount==0);
 166+ break;
 167+ case LoginForm :: WRONG_TOKEN:
 168+ $errormessage = 'WrongToken';
 169+ break;
 170+ case LoginForm :: NO_NAME :
 171+ $errormessage = 'NoName';
 172+ break;
 173+ case LoginForm :: ILLEGAL :
 174+ $errormessage = 'Illegal';
 175+ break;
 176+ case LoginForm :: WRONG_PLUGIN_PASS :
 177+ $errormessage = 'WrongPluginPass';
 178+ break;
 179+ case LoginForm :: NOT_EXISTS :
 180+ $errormessage = 'NotExists';
 181+ break;
 182+ case LoginForm :: WRONG_PASS :
 183+ $errormessage = 'WrongPass';
 184+ break;
 185+ case LoginForm :: EMPTY_PASS :
 186+ $errormessage = 'EmptyPass';
 187+ break;
 188+ default:
 189+ $errormessage = 'Unknown';
 190+ break;
 191+ }
 192+
 193+ if ($result != LoginForm::SUCCESS && $result != LoginForm::NEED_TOKEN ) {
 194+ error_log('Unexpected REMOTE_USER authentication failure. Login Error was:'.$errormessage);
 195+ }
 196+ $trycount++;
 197+ }
 198+ while ($tryagain);
 199+
 200+ return;
 201+}
 202+
 203+class Auth_remoteuser extends AuthPlugin {
 204+
 205+ function Auth_remoteuser() {
 206+ // Register our hook function. This hook will be executed on every page
 207+ // load. Its purpose is to automatically log the user in, if necessary.
 208+ if (isset($_SERVER['REMOTE_USER']) && strlen($_SERVER['REMOTE_USER'])) {
 209+ global $wgExtensionFunctions;
 210+ if (!isset($wgExtensionFunctions)) {
 211+ $wgExtensionFunctions = array();
 212+ }
 213+ else if (!is_array($wgExtensionFunctions)) {
 214+ $wgExtensionFunctions = array( $wgExtensionFunctions );
 215+ }
 216+ array_push($wgExtensionFunctions, 'Auth_remote_user_hook');
 217+ }
 218+ return;
 219+ }
 220+
 221+ /**
 222+ * Disallow password change.
 223+ *
 224+ * @return bool
 225+ */
 226+ function allowPasswordChange() {
 227+ return false;
 228+ }
 229+
 230+ /**
 231+ * This should not be called because we do not allow password change. Always
 232+ * fail by returning false.
 233+ *
 234+ * @param $user User object.
 235+ * @param $password String: password.
 236+ * @return bool
 237+ * @public
 238+ */
 239+ function setPassword($user, $password) {
 240+ return false;
 241+ }
 242+
 243+ /**
 244+ * We don't support this but we have to return true for preferences to save.
 245+ *
 246+ * @param $user User object.
 247+ * @return bool
 248+ * @public
 249+ */
 250+ function updateExternalDB($user) {
 251+ return true;
 252+ }
 253+
 254+ /**
 255+ * We can't create external accounts so return false.
 256+ *
 257+ * @return bool
 258+ * @public
 259+ */
 260+ function canCreateAccounts() {
 261+ return false;
 262+ }
 263+
 264+ /**
 265+ * We don't support adding users to whatever service provides REMOTE_USER, so
 266+ * fail by always returning false.
 267+ *
 268+ * @param User $user
 269+ * @param string $password
 270+ * @return bool
 271+ * @public
 272+ */
 273+ function addUser($user, $password) {
 274+ return false;
 275+ }
 276+
 277+ /**
 278+ * Pretend all users exist. This is checked by authenticateUserData to
 279+ * determine if a user exists in our 'db'. By returning true we tell it that
 280+ * it can create a local wiki user automatically.
 281+ *
 282+ * @param $username String: username.
 283+ * @return bool
 284+ * @public
 285+ */
 286+ function userExists($username) {
 287+ return true;
 288+ }
 289+
 290+ /**
 291+ * Check whether the given name matches REMOTE_USER.
 292+ * The name will be normalized to MediaWiki's requirements, so
 293+ * lower it and the REMOTE_USER before checking.
 294+ *
 295+ * @param $username String: username.
 296+ * @param $password String: user password.
 297+ * @return bool
 298+ * @public
 299+ */
 300+ function authenticate($username, $password) {
 301+ global $_SERVER;
 302+ global $wgAuthRemoteuserAuthz;
 303+ global $wgAuthRemoteuserDomain;
 304+
 305+ if (isset($wgAuthRemoteuserAuthz) && $wgAuthRemoteuserAuthz != true)
 306+ return false;
 307+
 308+ if (isset($_SERVER['REMOTE_USER']) == false)
 309+ {
 310+ $_SERVER['REMOTE_USER'] = "";
 311+ }
 312+ if (!isset($_SERVER['REMOTE_USER']))
 313+ {
 314+ return false;
 315+ }
 316+ if (isset($wgAuthRemoteuserDomain) && strlen($wgAuthRemoteuserDomain)>0) {
 317+ $usertest = str_replace("$wgAuthRemoteuserDomain\\","",$_SERVER['REMOTE_USER']);
 318+ $usertest = str_replace("@$wgAuthRemoteuserDomain","",$usertest);
 319+ } else {
 320+ $usertest = $_SERVER['REMOTE_USER'];
 321+ }
 322+
 323+ return (strtolower($username) == strtolower($usertest));
 324+ }
 325+
 326+ /**
 327+ * Check to see if the specific domain is a valid domain.
 328+ *
 329+ * @param $domain String: authentication domain.
 330+ * @return bool
 331+ * @public
 332+ */
 333+ function validDomain($domain) {
 334+ return true;
 335+ }
 336+
 337+ /**
 338+ * When a user logs in, optionally fill in preferences and such.
 339+ * For instance, you might pull the email address or real name from the
 340+ * external user database.
 341+ *
 342+ * The User object is passed by reference so it can be modified; don't
 343+ * forget the & on your function declaration.
 344+ *
 345+ * @param User $user
 346+ * @public
 347+ */
 348+ function updateUser(&$user) {
 349+ // We only set this stuff when accounts are created.
 350+ return true;
 351+ }
 352+
 353+ /**
 354+ * Return true because the wiki should create a new local account
 355+ * automatically when asked to login a user who doesn't exist locally but
 356+ * does in the external auth database.
 357+ *
 358+ * @return bool
 359+ * @public
 360+ */
 361+ function autoCreate() {
 362+ return true;
 363+ }
 364+
 365+ /**
 366+ * Return true to prevent logins that don't authenticate here from being
 367+ * checked against the local database's password fields.
 368+ *
 369+ * @return bool
 370+ * @public
 371+ */
 372+ function strict() {
 373+ return true;
 374+ }
 375+
 376+ /**
 377+ * When creating a user account, optionally fill in preferences and such.
 378+ * For instance, you might pull the email address or real name from the
 379+ * external user database.
 380+ *
 381+ * @param $user User object.
 382+ * @public
 383+ */
 384+ function initUser(&$user) {
 385+ global $_SERVER;
 386+ global $wgAuthRemoteuserName;
 387+ global $wgAuthRemoteuserMail;
 388+ global $wgAuthRemoteuserMailDomain;
 389+ global $wgAuthRemoteuserNotify;
 390+ global $wgAuthRemoteuserDomain;
 391+
 392+ if (isset($wgAuthRemoteuserDomain) && strlen($wgAuthRemoteuserDomain))
 393+ {
 394+ $username = str_replace("$wgAuthRemoteuserDomain\\","",$_SERVER['REMOTE_USER']);
 395+ $username = str_replace("@$wgAuthRemoteuserDomain","",$username);
 396+ } else {
 397+ $username = $_SERVER['REMOTE_USER'];
 398+ }
 399+
 400+ if (isset($wgAuthRemoteuserName))
 401+ $user->setRealName($wgAuthRemoteuserName);
 402+ else
 403+ $user->setRealName('');
 404+
 405+ if (isset($wgAuthRemoteuserMail))
 406+ $user->setEmail($wgAuthRemoteuserMail);
 407+ elseif (isset($wgAuthRemoteuserMailDomain))
 408+ $user->setEmail($username . '@' . $wgAuthRemoteuserMailDomain);
 409+ else
 410+ $user->setEmail($username . "@example.com");
 411+
 412+ $user->mEmailAuthenticated = wfTimestampNow();
 413+ $user->setToken();
 414+
 415+ //turn on e-mail notifications
 416+ if (isset($wgAuthRemoteuserNotify) && $wgAuthRemoteuserNotify) {
 417+ $user->setOption('enotifwatchlistpages', 1);
 418+ $user->setOption('enotifusertalkpages', 1);
 419+ $user->setOption('enotifminoredits', 1);
 420+ $user->setOption('enotifrevealaddr', 1);
 421+ }
 422+
 423+ $user->saveSettings();
 424+ }
 425+
 426+ /**
 427+ * Modify options in the login template. This shouldn't be very important
 428+ * because no one should really be bothering with the login page.
 429+ *
 430+ * @param $template UserLoginTemplate object.
 431+ * @public
 432+ */
 433+ function modifyUITemplate(&$template) {
 434+ //disable the mail new password box
 435+ $template->set('useemail', false);
 436+ //disable 'remember me' box
 437+ $template->set('remember', false);
 438+ $template->set('create', false);
 439+ $template->set('domain', false);
 440+ $template->set('usedomain', false);
 441+ }
 442+
 443+ /**
 444+ * Normalize user names to the MediaWiki standard to prevent duplicate
 445+ * accounts.
 446+ *
 447+ * @param $username String: username.
 448+ * @return string
 449+ * @public
 450+ */
 451+ function getCanonicalName($username) {
 452+ // lowercase the username
 453+ $username = strtolower($username);
 454+ // uppercase first letter to make MediaWiki happy
 455+ $username = ucfirst($username);
 456+ return $username;
 457+ }
 458+}
 459+
Property changes on: trunk/extensions/Auth_remoteuser/Auth_remoteuser.php
___________________________________________________________________
Added: svn:eol-style
1460 + native

Comments

#Comment by 😂 (talk | contribs)   17:14, 2 March 2011

Just curious: was there a huge reason to import this? Are there plans to make it less cringe-worthy?

Right now, it's a gigantic reg_globals vulnerability waiting to happen.

Status & tagging log