| Index: trunk/phase3/maintenance/archives/patch-external_user.sql |
| — | — | @@ -0,0 +1,9 @@ |
| | 2 | +CREATE TABLE /*_*/external_user ( |
| | 3 | + -- Foreign key to user_id |
| | 4 | + eu_wiki_id int unsigned NOT NULL PRIMARY KEY, |
| | 5 | + |
| | 6 | + -- Some opaque identifier provided by the external database |
| | 7 | + eu_external_id varchar(255) binary NOT NULL |
| | 8 | +) /*$wgDBTableOptions*/; |
| | 9 | + |
| | 10 | +CREATE UNIQUE INDEX /*i*/eu_external_id ON /*_*/external_user (eu_external_id); |
| Property changes on: trunk/phase3/maintenance/archives/patch-external_user.sql |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| 1 | 11 | + native |
| Index: trunk/phase3/maintenance/updaters.inc |
| — | — | @@ -162,6 +162,7 @@ |
| 163 | 163 | array( 'do_log_search_population' ), |
| 164 | 164 | array( 'add_field', 'logging', 'log_user_text', 'patch-log_user_text.sql' ), |
| 165 | 165 | array( 'add_table', 'l10n_cache', 'patch-l10n_cache.sql' ), |
| | 166 | + array( 'add_table', 'external_user', 'patch-external_user.sql' ), |
| 166 | 167 | ), |
| 167 | 168 | |
| 168 | 169 | 'sqlite' => array( |
| Index: trunk/phase3/maintenance/tables.sql |
| — | — | @@ -575,6 +575,20 @@ |
| 576 | 576 | CREATE INDEX /*i*/el_index ON /*_*/externallinks (el_index(60)); |
| 577 | 577 | |
| 578 | 578 | |
| | 579 | +-- |
| | 580 | +-- Track external user accounts, if ExternalAuth is used |
| | 581 | +-- |
| | 582 | +CREATE TABLE /*_*/external_user ( |
| | 583 | + -- Foreign key to user_id |
| | 584 | + eu_wiki_id int unsigned NOT NULL PRIMARY KEY, |
| | 585 | + |
| | 586 | + -- Some opaque identifier provided by the external database |
| | 587 | + eu_external_id varchar(255) binary NOT NULL |
| | 588 | +) /*$wgDBTableOptions*/; |
| | 589 | + |
| | 590 | +CREATE UNIQUE INDEX /*i*/eu_external_id ON /*_*/external_user (eu_external_id); |
| | 591 | + |
| | 592 | + |
| 579 | 593 | -- |
| 580 | 594 | -- Track interlanguage links |
| 581 | 595 | -- |
| Index: trunk/phase3/includes/User.php |
| — | — | @@ -3569,6 +3569,10 @@ |
| 3570 | 3570 | } |
| 3571 | 3571 | |
| 3572 | 3572 | protected function saveOptions() { |
| | 3573 | + global $wgAllowPrefChange; |
| | 3574 | + |
| | 3575 | + $extuser = ExternalUser::newFromUser( $this ); |
| | 3576 | + |
| 3573 | 3577 | $this->loadOptions(); |
| 3574 | 3578 | $dbw = wfGetDB( DB_MASTER ); |
| 3575 | 3579 | |
| — | — | @@ -3582,7 +3586,8 @@ |
| 3583 | 3587 | return; |
| 3584 | 3588 | |
| 3585 | 3589 | foreach( $saveOptions as $key => $value ) { |
| 3586 | | - if ( ( is_null(self::getDefaultOption($key)) && |
| | 3590 | + # Don't bother storing default values |
| | 3591 | + if ( ( is_null( self::getDefaultOption( $key ) ) && |
| 3587 | 3592 | !( $value === false || is_null($value) ) ) || |
| 3588 | 3593 | $value != self::getDefaultOption( $key ) ) { |
| 3589 | 3594 | $insert_rows[] = array( |
| — | — | @@ -3591,6 +3596,14 @@ |
| 3592 | 3597 | 'up_value' => $value, |
| 3593 | 3598 | ); |
| 3594 | 3599 | } |
| | 3600 | + if ( $extuser && isset( $wgAllowPrefChange[$key] ) ) { |
| | 3601 | + switch ( $wgAllowPrefChange[$key] ) { |
| | 3602 | + case 'local': case 'message': |
| | 3603 | + break; |
| | 3604 | + case 'semiglobal': case 'global': |
| | 3605 | + $extuser->setPref( $key, $value ); |
| | 3606 | + } |
| | 3607 | + } |
| 3595 | 3608 | } |
| 3596 | 3609 | |
| 3597 | 3610 | $dbw->begin(); |
| Index: trunk/phase3/includes/ExternalUser.php |
| — | — | @@ -0,0 +1,288 @@ |
| | 2 | +<?php |
| | 3 | + |
| | 4 | +# Copyright (C) 2009 Aryeh Gregor |
| | 5 | +# |
| | 6 | +# This program is free software; you can redistribute it and/or modify |
| | 7 | +# it under the terms of the GNU General Public License as published by |
| | 8 | +# the Free Software Foundation; either version 2 of the License, or |
| | 9 | +# (at your option) any later version. |
| | 10 | +# |
| | 11 | +# This program is distributed in the hope that it will be useful, |
| | 12 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | 13 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | 14 | +# GNU General Public License for more details. |
| | 15 | +# |
| | 16 | +# You should have received a copy of the GNU General Public License along |
| | 17 | +# with this program; if not, write to the Free Software Foundation, Inc., |
| | 18 | +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| | 19 | +# http://www.gnu.org/copyleft/gpl.html |
| | 20 | + |
| | 21 | +/** |
| | 22 | + * A class intended to supplement, and perhaps eventually replace, AuthPlugin. |
| | 23 | + * See: http://www.mediawiki.org/wiki/ExternalAuth |
| | 24 | + * |
| | 25 | + * The class represents a user whose data is in a foreign database. The |
| | 26 | + * database may have entirely different conventions from MediaWiki, but it's |
| | 27 | + * assumed to at least support the concept of a user id (possibly not an |
| | 28 | + * integer), a user name (possibly not meeting MediaWiki's username |
| | 29 | + * requirements), and a password. |
| | 30 | + */ |
| | 31 | +abstract class ExternalUser { |
| | 32 | + protected function __construct() {} |
| | 33 | + |
| | 34 | + /** |
| | 35 | + * Wrappers around initFrom*(). |
| | 36 | + */ |
| | 37 | + |
| | 38 | + /** |
| | 39 | + * @param $name string |
| | 40 | + * @return mixed ExternalUser, or false on failure |
| | 41 | + */ |
| | 42 | + public static function newFromName( $name ) { |
| | 43 | + global $wgExternalAuthType; |
| | 44 | + if ( is_null( $wgExternalAuthType ) ) { |
| | 45 | + return false; |
| | 46 | + } |
| | 47 | + $class = "ExternalUser_$wgExternalAuthType"; |
| | 48 | + $obj = new $class; |
| | 49 | + if ( !$obj->initFromName( $name ) ) { |
| | 50 | + return false; |
| | 51 | + } |
| | 52 | + return $obj; |
| | 53 | + } |
| | 54 | + |
| | 55 | + /** |
| | 56 | + * @param $id string |
| | 57 | + * @return mixed ExternalUser, or false on failure |
| | 58 | + */ |
| | 59 | + public static function newFromId( $id ) { |
| | 60 | + global $wgExternalAuthType; |
| | 61 | + if ( is_null( $wgExternalAuthType ) ) { |
| | 62 | + return false; |
| | 63 | + } |
| | 64 | + $class = "ExternalUser_$wgExternalAuthType"; |
| | 65 | + $obj = new $class; |
| | 66 | + if ( !$obj->initFromId( $id ) ) { |
| | 67 | + return false; |
| | 68 | + } |
| | 69 | + return $obj; |
| | 70 | + } |
| | 71 | + |
| | 72 | + /** |
| | 73 | + * @param $cookie string |
| | 74 | + * @return mixed ExternalUser, or false on failure |
| | 75 | + */ |
| | 76 | + public static function newFromCookie( $cookie ) { |
| | 77 | + global $wgExternalAuthType; |
| | 78 | + if ( is_null( $wgExternalAuthType ) ) { |
| | 79 | + return false; |
| | 80 | + } |
| | 81 | + $class = "ExternalUser_$wgExternalAuthType"; |
| | 82 | + $obj = new $class; |
| | 83 | + if ( !$obj->initFromCookie( $cookie ) ) { |
| | 84 | + return false; |
| | 85 | + } |
| | 86 | + return $obj; |
| | 87 | + } |
| | 88 | + |
| | 89 | + /** |
| | 90 | + * Creates the object corresponding to the given User object, assuming the |
| | 91 | + * user exists on the wiki and is linked to an external account. If either |
| | 92 | + * of these is false, this will return false. |
| | 93 | + * |
| | 94 | + * This is a wrapper around newFromId(). |
| | 95 | + * |
| | 96 | + * @param $user User |
| | 97 | + * @return mixed ExternalUser or false |
| | 98 | + */ |
| | 99 | + public static function newFromUser( $user ) { |
| | 100 | + global $wgExternalAuthType; |
| | 101 | + if ( is_null( $wgExternalAuthType ) ) { |
| | 102 | + # Short-circuit to avoid database query in common case so no one |
| | 103 | + # kills me |
| | 104 | + return false; |
| | 105 | + } |
| | 106 | + |
| | 107 | + $dbr = wfGetDB( DB_SLAVE ); |
| | 108 | + $id = $dbr->selectField( 'external_user', 'eu_external_id', |
| | 109 | + array( 'eu_wiki_id' => $user->getId() ), __METHOD__ ); |
| | 110 | + if ( $id === false ) { |
| | 111 | + return false; |
| | 112 | + } |
| | 113 | + return self::newFromId( $id ); |
| | 114 | + } |
| | 115 | + |
| | 116 | + /** |
| | 117 | + * Given a name, which is a string exactly as input by the user in the |
| | 118 | + * login form but with whitespace stripped, initialize this object to be |
| | 119 | + * the corresponding ExternalUser. Return true if successful, otherwise |
| | 120 | + * false. |
| | 121 | + * |
| | 122 | + * @param $name string |
| | 123 | + * @return bool Success? |
| | 124 | + */ |
| | 125 | + protected abstract function initFromName( $name ); |
| | 126 | + |
| | 127 | + /** |
| | 128 | + * Given an id, which was at some previous point in history returned by |
| | 129 | + * getId(), initialize this object to be the corresponding ExternalUser. |
| | 130 | + * Return true if successful, false otherwise. |
| | 131 | + * |
| | 132 | + * @param $id string |
| | 133 | + * @return bool Success? |
| | 134 | + */ |
| | 135 | + protected abstract function initFromId( $id ); |
| | 136 | + |
| | 137 | + /** |
| | 138 | + * Given the user's cookie, initialize this object to the correct user if |
| | 139 | + * the cookie indicates that the user is logged into the external database. |
| | 140 | + * If successful, return true. If the external database doesn't support |
| | 141 | + * cookie-based authentication, or if the cookies don't belong to a |
| | 142 | + * logged-in user, return false. |
| | 143 | + * |
| | 144 | + * TODO: Actually use this. |
| | 145 | + * |
| | 146 | + * @param $cookie string |
| | 147 | + * @return bool Success? |
| | 148 | + */ |
| | 149 | + protected function initFromCookie( $cookie ) { |
| | 150 | + return false; |
| | 151 | + } |
| | 152 | + |
| | 153 | + /** |
| | 154 | + * This must return some identifier that stably, uniquely identifies the |
| | 155 | + * user. In a typical web application, this could be an integer |
| | 156 | + * representing the "user id". In other cases, it might be a string. In |
| | 157 | + * any event, the return value should be a string between 1 and 255 |
| | 158 | + * characters in length; must uniquely identify the user in the foreign |
| | 159 | + * database; and, if at all possible, should be permanent. |
| | 160 | + * |
| | 161 | + * This will only ever be used to reconstruct this ExternalUser object via |
| | 162 | + * newFromId(). The resulting object in that case should correspond to the |
| | 163 | + * same user, even if details have changed in the interim (e.g., renames or |
| | 164 | + * preference changes). |
| | 165 | + * |
| | 166 | + * @return string |
| | 167 | + */ |
| | 168 | + abstract public function getId(); |
| | 169 | + |
| | 170 | + /** |
| | 171 | + * This must return the name that the user would normally use for login to |
| | 172 | + * the external database. It is subject to no particular restrictions |
| | 173 | + * beyond rudimentary sanity, and in particular may be invalid as a |
| | 174 | + * MediaWiki username. It's used to auto-generate an account name that |
| | 175 | + * *is* valid for MediaWiki, either with or without user input, but |
| | 176 | + * basically is only a hint. |
| | 177 | + * |
| | 178 | + * @return string |
| | 179 | + */ |
| | 180 | + abstract public function getName(); |
| | 181 | + |
| | 182 | + /** |
| | 183 | + * Is the given password valid for the external user? The password is |
| | 184 | + * provided in plaintext, with whitespace stripped but not otherwise |
| | 185 | + * modified. |
| | 186 | + * |
| | 187 | + * @param $password string |
| | 188 | + * @return bool |
| | 189 | + */ |
| | 190 | + abstract public function authenticate( $password ); |
| | 191 | + |
| | 192 | + /** |
| | 193 | + * Retrieve the value corresponding to the given preference key. The most |
| | 194 | + * important values are: |
| | 195 | + * |
| | 196 | + * - emailaddress |
| | 197 | + * - language |
| | 198 | + * |
| | 199 | + * The value must meet MediaWiki's requirements for values of this type, |
| | 200 | + * and will be checked for validity before use. If the preference makes no |
| | 201 | + * sense for the backend, or it makes sense but is unset for this user, or |
| | 202 | + * is unrecognized, return null. |
| | 203 | + * |
| | 204 | + * $pref will never equal 'password', since passwords are usually hashed |
| | 205 | + * and cannot be directly retrieved. authenticate() is used for this |
| | 206 | + * instead. |
| | 207 | + * |
| | 208 | + * TODO: Currently this is only called for 'emailaddress'; generalize! Add |
| | 209 | + * some config option to decide which values are grabbed on user |
| | 210 | + * initialization. |
| | 211 | + * |
| | 212 | + * @param $pref string |
| | 213 | + * @return mixed |
| | 214 | + */ |
| | 215 | + public function getPref( $pref ) { |
| | 216 | + return null; |
| | 217 | + } |
| | 218 | + |
| | 219 | + /** |
| | 220 | + * Return an array of identifiers for all the foreign groups that this user |
| | 221 | + * has. The identifiers are opaque objects that only need to be |
| | 222 | + * specifiable by the administrator in LocalSettings.php when configuring |
| | 223 | + * $wgAutopromote. They may be, for instance, strings or integers. |
| | 224 | + * |
| | 225 | + * TODO: Support this in $wgAutopromote. |
| | 226 | + * |
| | 227 | + * @return array |
| | 228 | + */ |
| | 229 | + public function getGroups() { |
| | 230 | + return array(); |
| | 231 | + } |
| | 232 | + |
| | 233 | + /** |
| | 234 | + * Given a preference key (e.g., 'emailaddress'), provide an HTML message |
| | 235 | + * telling the user how to change it in the external database. The |
| | 236 | + * administrator has specified that this preference cannot be changed on |
| | 237 | + * the wiki, and may only be changed in the foreign database. If no |
| | 238 | + * message is available, such as for an unrecognized preference, return |
| | 239 | + * false. |
| | 240 | + * |
| | 241 | + * TODO: Use this somewhere. |
| | 242 | + * |
| | 243 | + * @param $pref string |
| | 244 | + * @return mixed String or false |
| | 245 | + */ |
| | 246 | + public static function prefMessage( $pref ) { |
| | 247 | + return false; |
| | 248 | + } |
| | 249 | + |
| | 250 | + /** |
| | 251 | + * Set the given preference key to the given value. Two important |
| | 252 | + * preference keys that you might want to implement are 'password' and |
| | 253 | + * 'emailaddress'. If the set fails, such as because the preference is |
| | 254 | + * unrecognized or because the external database can't be changed right |
| | 255 | + * now, return false. If it succeeds, return true. |
| | 256 | + * |
| | 257 | + * If applicable, you should make sure to validate the new value against |
| | 258 | + * any constraints the external database may have, since MediaWiki may have |
| | 259 | + * more limited constraints (e.g., on password strength). |
| | 260 | + * |
| | 261 | + * TODO: Untested. |
| | 262 | + * |
| | 263 | + * @param $key string |
| | 264 | + * @param $value string |
| | 265 | + * @return bool Success? |
| | 266 | + */ |
| | 267 | + public static function setPref( $key, $value ) { |
| | 268 | + return false; |
| | 269 | + } |
| | 270 | + |
| | 271 | + /** |
| | 272 | + * Create a link for future reference between this object and the provided |
| | 273 | + * user_id. If the user was already linked, the old link will be |
| | 274 | + * overwritten. |
| | 275 | + * |
| | 276 | + * This is part of the core code and is not overridable by specific |
| | 277 | + * plugins. It's in this class only for convenience. |
| | 278 | + * |
| | 279 | + * @param $id int user_id |
| | 280 | + */ |
| | 281 | + public final function link( $id ) { |
| | 282 | + $dbw = wfGetDB( DB_MASTER ); |
| | 283 | + $dbw->replace( 'external_user', |
| | 284 | + array( 'eu_wiki_id', 'eu_external_id' ), |
| | 285 | + array( 'eu_wiki_id' => $id, |
| | 286 | + 'eu_external_id' => $this->getId() ), |
| | 287 | + __METHOD__ ); |
| | 288 | + } |
| | 289 | +} |
| Property changes on: trunk/phase3/includes/ExternalUser.php |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| 1 | 290 | + native |
| Index: trunk/phase3/includes/AutoLoader.php |
| — | — | @@ -74,6 +74,8 @@ |
| 75 | 75 | 'ExternalStoreDB' => 'includes/ExternalStoreDB.php', |
| 76 | 76 | 'ExternalStoreHttp' => 'includes/ExternalStoreHttp.php', |
| 77 | 77 | 'ExternalStore' => 'includes/ExternalStore.php', |
| | 78 | + 'ExternalUser' => 'includes/ExternalUser.php', |
| | 79 | + 'ExternalUser_vB' => 'includes/extauth/vB.php', |
| 78 | 80 | 'FatalError' => 'includes/Exception.php', |
| 79 | 81 | 'FakeTitle' => 'includes/FakeTitle.php', |
| 80 | 82 | 'FauxRequest' => 'includes/WebRequest.php', |
| Index: trunk/phase3/includes/DefaultSettings.php |
| — | — | @@ -4028,3 +4028,60 @@ |
| 4029 | 4029 | * ); |
| 4030 | 4030 | */ |
| 4031 | 4031 | $wgPoolCounterConf = null; |
| | 4032 | + |
| | 4033 | +/** |
| | 4034 | + * Use some particular type of external authentication. The specific |
| | 4035 | + * authentication module you use will normally require some extra settings to |
| | 4036 | + * be specified. |
| | 4037 | + * |
| | 4038 | + * null indicates no external authentication is to be used. Otherwise, |
| | 4039 | + * "ExternalUser_$wgExternalAuthType" must be the name of a non-abstract class |
| | 4040 | + * that extends ExternalUser. |
| | 4041 | + * |
| | 4042 | + * Core authentication modules can be found in includes/extauth/. |
| | 4043 | + */ |
| | 4044 | +$wgExternalAuthType = null; |
| | 4045 | + |
| | 4046 | +/** |
| | 4047 | + * Configuration for the external authentication. This may include arbitrary |
| | 4048 | + * keys that depend on the authentication mechanism. For instance, |
| | 4049 | + * authentication against another web app might require that the database login |
| | 4050 | + * info be provided. Check the file where your auth mechanism is defined for |
| | 4051 | + * info on what to put here. |
| | 4052 | + */ |
| | 4053 | +$wgExternalAuthConfig = array(); |
| | 4054 | + |
| | 4055 | +/** |
| | 4056 | + * When should we automatically create local accounts when external accounts |
| | 4057 | + * already exist, if using ExternalAuth? Can have three values: 'never', |
| | 4058 | + * 'login', 'view'. 'view' requires the external database to support cookies, |
| | 4059 | + * and implies 'login'. |
| | 4060 | + * |
| | 4061 | + * TODO: Implement 'view' (currently behaves like 'login'). |
| | 4062 | + */ |
| | 4063 | +$wgAutocreatePolicy = 'login'; |
| | 4064 | + |
| | 4065 | +/** |
| | 4066 | + * Policies for how each preference is allowed to be changed, in the presence |
| | 4067 | + * of external authentication. The keys are preference keys, e.g., 'password' |
| | 4068 | + * or 'emailaddress' (see Preferences.php et al.). The value can be one of the |
| | 4069 | + * following: |
| | 4070 | + * |
| | 4071 | + * - local: Allow changes to this pref through the wiki interface but only |
| | 4072 | + * apply them locally (default). |
| | 4073 | + * - semiglobal: Allow changes through the wiki interface and try to apply them |
| | 4074 | + * to the foreign database, but continue on anyway if that fails. |
| | 4075 | + * - global: Allow changes through the wiki interface, but only let them go |
| | 4076 | + * through if they successfully update the foreign database. |
| | 4077 | + * - message: Allow no local changes for linked accounts; replace the change |
| | 4078 | + * form with a message provided by the auth plugin, telling the user how to |
| | 4079 | + * change the setting externally (maybe providing a link, etc.). If the auth |
| | 4080 | + * plugin provides no message for this preference, hide it entirely. |
| | 4081 | + * |
| | 4082 | + * Accounts that are not linked to an external account are never affected by |
| | 4083 | + * this setting. You may want to look at $wgHiddenPrefs instead. |
| | 4084 | + * $wgHiddenPrefs supersedes this option. |
| | 4085 | + * |
| | 4086 | + * TODO: Implement message, global. |
| | 4087 | + */ |
| | 4088 | +$wgAllowPrefChange = array(); |
| Index: trunk/phase3/includes/specials/SpecialUserlogin.php |
| — | — | @@ -40,6 +40,8 @@ |
| 41 | 41 | var $mLoginattempt, $mRemember, $mEmail, $mDomain, $mLanguage; |
| 42 | 42 | var $mSkipCookieCheck, $mReturnToQuery; |
| 43 | 43 | |
| | 44 | + private $mExtUser = null; |
| | 45 | + |
| 44 | 46 | /** |
| 45 | 47 | * Constructor |
| 46 | 48 | * @param WebRequest $request A WebRequest object passed by reference |
| — | — | @@ -363,6 +365,14 @@ |
| 364 | 366 | |
| 365 | 367 | $wgAuth->initUser( $u, $autocreate ); |
| 366 | 368 | |
| | 369 | + if ( $this->mExtUser ) { |
| | 370 | + $this->mExtUser->link( $u->getId() ); |
| | 371 | + $email = $this->mExtUser->getPref( 'emailaddress' ); |
| | 372 | + if ( $email && !$this->mEmail ) { |
| | 373 | + $u->setEmail( $email ); |
| | 374 | + } |
| | 375 | + } |
| | 376 | + |
| 367 | 377 | $u->setOption( 'rememberpassword', $this->mRemember ? 1 : 0 ); |
| 368 | 378 | $u->saveSettings(); |
| 369 | 379 | |
| — | — | @@ -417,6 +427,11 @@ |
| 418 | 428 | wfDebug( __METHOD__.": already logged in as {$this->mName}\n" ); |
| 419 | 429 | return self::SUCCESS; |
| 420 | 430 | } |
| | 431 | + |
| | 432 | + $this->mExtUser = ExternalUser::newFromName( $this->mName ); |
| | 433 | + |
| | 434 | + # TODO: Allow some magic here for invalid external names, e.g., let the |
| | 435 | + # user choose a different wiki name. |
| 421 | 436 | $u = User::newFromName( $this->mName ); |
| 422 | 437 | if( is_null( $u ) || !User::isUsableName( $u->getName() ) ) { |
| 423 | 438 | return self::ILLEGAL; |
| — | — | @@ -496,27 +511,41 @@ |
| 497 | 512 | * @return integer Status code |
| 498 | 513 | */ |
| 499 | 514 | function attemptAutoCreate( $user ) { |
| 500 | | - global $wgAuth, $wgUser; |
| | 515 | + global $wgAuth, $wgUser, $wgAutocreatePolicy; |
| | 516 | + |
| | 517 | + if ( $wgUser->isBlockedFromCreateAccount() ) { |
| | 518 | + wfDebug( __METHOD__.": user is blocked from account creation\n" ); |
| | 519 | + return self::CREATE_BLOCKED; |
| | 520 | + } |
| | 521 | + |
| 501 | 522 | /** |
| 502 | 523 | * If the external authentication plugin allows it, automatically cre- |
| 503 | 524 | * ate a new account for users that are externally defined but have not |
| 504 | 525 | * yet logged in. |
| 505 | 526 | */ |
| 506 | | - if ( !$wgAuth->autoCreate() ) { |
| 507 | | - return self::NOT_EXISTS; |
| | 527 | + if ( $this->mExtUser ) { |
| | 528 | + # mExtUser is neither null nor false, so use the new ExternalAuth |
| | 529 | + # system. |
| | 530 | + if ( $wgAutocreatePolicy == 'never' ) { |
| | 531 | + return self::NOT_EXISTS; |
| | 532 | + } |
| | 533 | + if ( !$this->mExtUser->authenticate( $this->mPassword ) ) { |
| | 534 | + return self::WRONG_PLUGIN_PASS; |
| | 535 | + } |
| | 536 | + } else { |
| | 537 | + # Old AuthPlugin. |
| | 538 | + if ( !$wgAuth->autoCreate() ) { |
| | 539 | + return self::NOT_EXISTS; |
| | 540 | + } |
| | 541 | + if ( !$wgAuth->userExists( $user->getName() ) ) { |
| | 542 | + wfDebug( __METHOD__.": user does not exist\n" ); |
| | 543 | + return self::NOT_EXISTS; |
| | 544 | + } |
| | 545 | + if ( !$wgAuth->authenticate( $user->getName(), $this->mPassword ) ) { |
| | 546 | + wfDebug( __METHOD__.": \$wgAuth->authenticate() returned false, aborting\n" ); |
| | 547 | + return self::WRONG_PLUGIN_PASS; |
| | 548 | + } |
| 508 | 549 | } |
| 509 | | - if ( !$wgAuth->userExists( $user->getName() ) ) { |
| 510 | | - wfDebug( __METHOD__.": user does not exist\n" ); |
| 511 | | - return self::NOT_EXISTS; |
| 512 | | - } |
| 513 | | - if ( !$wgAuth->authenticate( $user->getName(), $this->mPassword ) ) { |
| 514 | | - wfDebug( __METHOD__.": \$wgAuth->authenticate() returned false, aborting\n" ); |
| 515 | | - return self::WRONG_PLUGIN_PASS; |
| 516 | | - } |
| 517 | | - if ( $wgUser->isBlockedFromCreateAccount() ) { |
| 518 | | - wfDebug( __METHOD__.": user is blocked from account creation\n" ); |
| 519 | | - return self::CREATE_BLOCKED; |
| 520 | | - } |
| 521 | 550 | |
| 522 | 551 | wfDebug( __METHOD__.": creating account\n" ); |
| 523 | 552 | $user = $this->initUser( $user, true ); |
| — | — | @@ -526,8 +555,7 @@ |
| 527 | 556 | function processLogin() { |
| 528 | 557 | global $wgUser, $wgAuth; |
| 529 | 558 | |
| 530 | | - switch ($this->authenticateUserData()) |
| 531 | | - { |
| | 559 | + switch ( $this->authenticateUserData() ) { |
| 532 | 560 | case self::SUCCESS: |
| 533 | 561 | # We've verified now, update the real record |
| 534 | 562 | if( (bool)$this->mRemember != (bool)$wgUser->getOption( 'rememberpassword' ) ) { |
| Index: trunk/phase3/includes/extauth/vB.php |
| — | — | @@ -0,0 +1,97 @@ |
| | 2 | +<?php |
| | 3 | + |
| | 4 | +# Copyright (C) 2009 Aryeh Gregor |
| | 5 | +# |
| | 6 | +# This program is free software; you can redistribute it and/or modify |
| | 7 | +# it under the terms of the GNU General Public License as published by |
| | 8 | +# the Free Software Foundation; either version 2 of the License, or |
| | 9 | +# (at your option) any later version. |
| | 10 | +# |
| | 11 | +# This program is distributed in the hope that it will be useful, |
| | 12 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | 13 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | 14 | +# GNU General Public License for more details. |
| | 15 | +# |
| | 16 | +# You should have received a copy of the GNU General Public License along |
| | 17 | +# with this program; if not, write to the Free Software Foundation, Inc., |
| | 18 | +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| | 19 | +# http://www.gnu.org/copyleft/gpl.html |
| | 20 | + |
| | 21 | +/** |
| | 22 | + * This class supports the proprietary vBulletin forum system |
| | 23 | + * <http://www.vbulletin.com>, versions 3.5 and up. It calls no functions or |
| | 24 | + * code, only reads from the database. Example lines to put in |
| | 25 | + * LocalSettings.php: |
| | 26 | + * |
| | 27 | + * $wgExternalAuthType = 'vB'; |
| | 28 | + * $wgExternalAuthConf = array( |
| | 29 | + * 'server' => 'localhost', |
| | 30 | + * 'username' => 'forum', |
| | 31 | + * 'password' => 'udE,jSqDJ<""p=fI.K9', |
| | 32 | + * 'dbname' => 'forum', |
| | 33 | + * 'tableprefix' => '' |
| | 34 | + * ); |
| | 35 | + */ |
| | 36 | +class ExternalUser_vB extends ExternalUser { |
| | 37 | + private $mDb, $mRow; |
| | 38 | + |
| | 39 | + protected function initFromName( $name ) { |
| | 40 | + return $this->initFromCond( array( 'username' => $name ) ); |
| | 41 | + } |
| | 42 | + |
| | 43 | + protected function initFromId( $id ) { |
| | 44 | + return $this->initFromCond( array( 'userid' => $id ) ); |
| | 45 | + } |
| | 46 | + |
| | 47 | + # initFromCookie() not yet implemented |
| | 48 | + |
| | 49 | + private function initFromCond( $cond ) { |
| | 50 | + global $wgExternalAuthConf; |
| | 51 | + |
| | 52 | + $this->mDb = new Database( |
| | 53 | + $wgExternalAuthConf['server'], |
| | 54 | + $wgExternalAuthConf['username'], |
| | 55 | + $wgExternalAuthConf['password'], |
| | 56 | + $wgExternalAuthConf['dbname'], |
| | 57 | + false, 0, |
| | 58 | + $wgExternalAuthConf['tableprefix'] |
| | 59 | + ); |
| | 60 | + |
| | 61 | + $row = $this->mDb->selectRow( |
| | 62 | + 'user', |
| | 63 | + array( 'userid', 'username', 'password', 'salt', 'email', 'usergroupid', |
| | 64 | + 'membergroupids' ), |
| | 65 | + $cond, |
| | 66 | + __METHOD__ |
| | 67 | + ); |
| | 68 | + if ( !$row ) { |
| | 69 | + return false; |
| | 70 | + } |
| | 71 | + $this->mRow = $row; |
| | 72 | + |
| | 73 | + return true; |
| | 74 | + } |
| | 75 | + |
| | 76 | + public function getId() { return $this->mRow->userid; } |
| | 77 | + public function getName() { return $this->mRow->username; } |
| | 78 | + |
| | 79 | + public function authenticate( $password ) { |
| | 80 | + return $this->mRow->password == md5( md5( $password ) |
| | 81 | + . $this->mRow->salt ); |
| | 82 | + } |
| | 83 | + |
| | 84 | + public function getPref( $pref ) { |
| | 85 | + if ( $pref == 'emailaddress' && $this->mRow->email ) { |
| | 86 | + # TODO: only return if validated? |
| | 87 | + return $this->mRow->email; |
| | 88 | + } |
| | 89 | + return null; |
| | 90 | + } |
| | 91 | + |
| | 92 | + public function getGroups() { |
| | 93 | + $groups = array( $this->mRow->usergroupid ); |
| | 94 | + $groups = array_merge( $groups, explode( ',', $this->mRow->membergroupids ) ); |
| | 95 | + $groups = array_unique( $groups ); |
| | 96 | + return $groups; |
| | 97 | + } |
| | 98 | +} |
| Property changes on: trunk/phase3/includes/extauth/vB.php |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| 1 | 99 | + native |
| Index: trunk/phase3/RELEASE-NOTES |
| — | — | @@ -150,6 +150,7 @@ |
| 151 | 151 | thumbnails to be stored in a separate location to the source images. |
| 152 | 152 | * If config/ directory is not executable, the command to make it executable |
| 153 | 153 | now asks the user to cd to the correct directory |
| | 154 | +* Add experimental new external authentication framework, ExternalAuth. |
| 154 | 155 | |
| 155 | 156 | === Bug fixes in 1.16 === |
| 156 | 157 | |