diff -x CVS -x OpenID_Store -x LocalSettings.php -x Auth -crN phase3-pristine/docs/openid.txt phase3/docs/openid.txt
*** phase3-pristine/docs/openid.txt	1969-12-31 16:00:00.000000000 -0800
--- phase3/docs/openid.txt	2006-02-06 09:39:33.000000000 -0800
***************
*** 0 ****
--- 1,93 ----
+ 
+ MediaWiki OpenID Support
+ ------------------------
+ 
+ MediaWiki supports the OpenID identity protocol so you can use an
+ OpenID identity URL to authenticate and log into MediaWiki!  OpenID
+ support was added by Dan Libby (danda@videntity.org) with
+ modifications by JanRain, Inc (openid@janrain.com).
+ 
+ Installation
+ ------------
+ 
+ 1. To use OpenID logins with MediaWiki, you'll need the PHP OpenID
+    library, version 0.9.1 or greater, which you can obtain from
+ 
+    http://www.openidenabled.com/openid/libraries/php/
+ 
+ 2. After you've installed the PHP OpenID library, turn on OpenID in
+    MediaWiki by setting this in your LocalSettings.php file:
+ 
+    $wgUseOpenID = true;
+ 
+ 3. Next, you'll need to make sure that either:
+ 
+    A) MediaWiki can create directories in your MediaWiki installation
+    path
+ 
+    or
+ 
+    B) you have created a directory called 'OpenID_Store' in your
+    MediaWiki installation path and this directory is owned and
+    writabale by the web server's account.
+ 
+ 4. IMPORTANT!  Add this to your apache configuration so the
+    OpenID_Store directory is not publicly viewable:
+
+    <Directory /path/to/mediawiki/OpenID_Store>
+      <Limit GET PUT POST>
+        Order allow,deny
+        Deny from all
+      </Limit>
+    </Directory>
+
+ 5. If you did everything above, the login form on your MediaWiki will
+    say "Username or OpenID" instead of "Username".  You can use an
+    OpenID URL to log in.
+ 
+ Notes About OpenID Support
+ --------------------------
+ 
+ MediaWiki OpenID support is intended to play nicely with preexisting
+ authentication mechanisms.  Some things to note:
+ 
+  - OpenID support works in *addition* to normal wiki logins, including
+    any external authentication plugin configured by the MediaWiki
+    administrator.  If a username looks like a URL (i.e., has a
+    scheme), OpenID auth is tried; otherwise, the regular
+    authentication rules apply.
+ 
+  - If OpenID support cannot be verified (either because the library is
+    missing or because the store directory can't be initialized -- see
+    step (3) in Installation), MediaWiki will function normally even if
+    $wgUseOpenID is set to true.
+ 
+  - The account creation form cannot currently be used to create
+    accounts with OpenID identity URLs.  If you want to create an
+    account with your OpenID, just log in.  The account will be created
+    automatically.
+ 
+ Troubleshooting
+ ---------------
+ 
+ If you've gone through the steps above and OpenID support still
+ doesn't work, things may not be configured quite right:
+ 
+  1) Make sure the PHP OpenID library is installed in your PHP include
+     path.  This means that the 'Auth' directory included in the PHP
+     OpenID library package should be installed into one of the
+     directories in your PHP include_path setting.
+ 
+  2) Turn on debug logging in MediaWiki by setting $wgDebugLogFile to a
+     log file path that is writable by the web server's account:
+ 
+     $wgDebugLogFile = "/path/to/log/file";
+ 
+     The file will contain a message like this one if your store
+     directory doesn't exist or isn't properly configured:
+ 
+     "AuthPluginOpenID setup - cannot initialize store directory .../OpenID_Store"
+ 
+     This means that either the store directory doesn't exist or it
+     doesn't have the right permissions.  See step (3) in Installation
+     above.
diff -x CVS -x OpenID_Store -x LocalSettings.php -x Auth -crN phase3-pristine/includes/AuthPluginOpenID.php phase3/includes/AuthPluginOpenID.php
*** phase3-pristine/includes/AuthPluginOpenID.php	1969-12-31 16:00:00.000000000 -0800
--- phase3/includes/AuthPluginOpenID.php	2006-01-31 14:31:56.000000000 -0800
***************
*** 0 ****
--- 1,354 ----
+ <?php
+ # Copyright (C) 2005 Dan Libby <danda@videntity.org>
+ # Copyright (C) 2005 JanRain, Inc. <openid@janrain.com>
+ # http://videntity.org/
+ # 
+ # 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, write to the Free Software Foundation, Inc.,
+ # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ # http://www.gnu.org/copyleft/gpl.html
+ 
+ /**
+  * OpenID Authentication plugin. This is a subclass of AuthPlugin
+  * to allow logging into MediaWiki via OpenID Identities authenticated
+  * by remote servers.
+  *
+  * This plugin is a bit complex as it requires a multi-page authentication
+  * process.  It required a few changes to the core mediawiki code.
+  *
+  * @package MediaWiki
+  */
+  
+ /* Known Todos: 
+  *   - Add a MemCached based AssociationManager to make remote logins more efficient
+  *   - Handle SSL ( https:// ) return to URLs
+  *
+  */
+  
+ /**
+  * Note:
+  * - OpenID logins appear with first character upper-cased.  This is
+  * because mediawiki logins are typically stored and displayed that
+  * way.  This does not make sense for OpenID identities which are
+  * URLs.  Thus, identities appear like "Http://johndoe.videntity.org/"
+  * instead of "http://johndoe.videntity.org/".
+  */
+ 
+ require_once( 'AuthPlugin.php' );
+ require_once( 'LocalSettings.php' );
+ 
+ if ($wgUseOpenID &&
+     @include_once( 'Auth/OpenID/Consumer/Consumer.php' )) {
+ 
+     include_once( 'Auth/OpenID/Store/FileStore.php' );
+     include_once( 'Auth/OpenID/Util.php' );
+ 
+     // Try to go ahead and initialize the store.  If it fails, don't
+     // define OPENID_SUPPORT.
+ 
+     $store_dir = 'OpenID_Store';
+     $store_path = $IP . DIRECTORY_SEPARATOR . $store_dir;
+     $store = new Auth_OpenID_FileStore($store_path);
+ 
+     if ($store->_setup()) {
+         define('OPENID_SUPPORT', true);
+         define('OPENID_STORE_DIR', $store_dir);
+         define('OPENID_STORE_PATH', $store_path);
+     } else {
+         wfDebug( "AuthPluginOpenID setup - cannot initialize store directory $store_path\n" );
+     }
+ } else {
+     // The absence of OPENID_SUPPORT means it isn't supported.  Be
+     // sure to check defined('OPENID_SUPPORT') in code that cares!
+ }
+ 
+ class AuthPluginOpenID extends AuthPlugin {
+     var $authenticated = null;
+     var $identity;
+ 
+         function AuthPluginOpenID() {
+             session_start();
+             $this->message = null;
+             $this->store = new Auth_OpenID_FileStore( OPENID_STORE_PATH );
+             $this->consumer = new Auth_OpenID_Consumer( $this->store );
+         }
+ 
+ 	/**
+ 	 * Check whether there exists a user account with the given
+ 	 * name.  The name will be normalized to MediaWiki's
+ 	 * requirements, so you might need to munge it (for instance,
+ 	 * for lowercase initial letters).
+ 	 *
+ 	 * @param string $username
+ 	 * @return bool
+ 	 * @access public
+ 	 */
+ 	function userExists( $username ) {
+ 		// We can't possibly know this until we've checked the
+ 		// remote server.
+ 		return $this->authenticated == true;
+ 	}
+ 	
+ 	/**
+ 	 * Check if a username+password pair is a valid login.  The
+ 	 * name will be normalized to MediaWiki's requirements, so you
+ 	 * might need to munge it (for instance, for lowercase initial
+ 	 * letters).
+ 	 *
+ 	 * @param string $username
+ 	 * @param string $password
+ 	 * @return bool
+ 	 * @access public
+ 	 */
+ 	function authenticate( $username, $password ) {
+ 		// Override this!
+ 		return $this->authenticated == true;
+ 	}
+ 	
+ 	/**
+ 	 * Return true if 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.
+ 	 *
+ 	 * If you don't automatically create accounts, you must still
+ 	 * create accounts in some way. It's not possible to
+ 	 * authenticate without a local account.
+ 	 *
+ 	 * This is just a question, and shouldn't perform any actions.
+ 	 *
+ 	 * @return bool
+ 	 * @access 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.
+ 	 *
+ 	 * This is just a question, and shouldn't perform any actions.
+ 	 *
+ 	 * @return bool
+ 	 * @access public
+ 	 */
+ 	function strict() {
+ 		return false;
+ 	}
+ 	
+ 	/**
+ 	 * 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.
+ 	 *
+ 	 * The User object is passed by reference so it can be
+ 	 * modified; don't forget the & on your function declaration.
+ 	 *
+ 	 * @param User $user
+ 	 * @access public
+ 	 */
+ 	function initUser( &$user ) {
+             // The OpenID protocol doesn't provide any profile
+             // information.  Just authentication.
+ 	}
+ 
+ 	/**
+ 	 * Check to see if the specific domain is a valid domain.
+ 	 *
+ 	 * @param string $domain
+ 	 * @return bool
+ 	 * @access public
+ 	 */
+ 	function validDomain( $domain ) {
+ 		# Override this!
+                 return false;
+ 	}
+ 
+ 	/**
+ 	 * If you want to munge the case of an account name before the
+ 	 * final check, now is your chance.
+ 	 */
+ 	function getCanonicalName( $username ) {
+             // This function properly folds an OpenID URL so it's all
+             // lowercase, except for the first letter, which is a
+             // transformation MediaWiki expects.
+             if ( $this->is_openid_login( $username ) ) {
+                 if ( $username == ucfirst( strtolower( $username ) ) ) {
+                     return $username;
+                 } else {
+                     return Auth_OpenID_normalizeUrl( strtolower( $username ) );
+                 }
+             } else {
+                 return $username;
+             }
+ 	}    
+     
+ 	/**
+ 	 * Allows the AuthPlugin to take full control of execution for
+          * this request and bypass normal login processing. This can be used to
+          * extend authentication over several page requests. This is necessary
+          * for an OpenID login, and possibly other situations.
+ 	 *
+ 	 * This function should return true if it has handled the
+          * request, or false to continue with normal mediawiki processing.
+ 	 *
+ 	 * @return bool
+ 	 * @access public
+ 	 */
+ 	function processLogin( $username, $password ) {
+ 
+             $this->message = null;
+ 
+             // If the username doesn't look like an OpenID URL, then
+             // we bail.  Processing will return to the default login
+             // handler.
+             if( !$this->is_openid_login( $username ) ) {
+                 $this->message = "Username is not a valid OpenID identity URL.";
+                 return false;
+             }
+ 
+             // Lump all our get/post params together.
+             $query = array_merge( $_GET, $_POST );
+         
+             // Any request but the first should have the is_open_id flag set.
+             $is_open_id = isset( $query['is_open_id'] ) ? $query['is_open_id'] : null;
+ 
+             // If this is our first time called, then the login form
+             // has just been submitted.  We need to kick off the
+             // OpenID login process.
+             if( !$is_open_id ) {
+                 if( !$this->_start_openid_login( $username ) ) {
+                     // something went wrong starting the OpenID
+                     // login. Generally, this means the OpenID URL was
+                     // invalid or the returned page did not contain
+                     // the proper openid.server link tag.  In any
+                     // event, we return false, indicating that
+                     // mediawiki processing should continue.  That
+                     // will cause mediawiki to attempt to log the user
+                     // in using the standard auth.
+                     return false;
+                 } else {
+                     // Cool, we found a valid OpenID URL/page, and
+                     // kicked things off.  Return true so mediawiki
+                     // won't try to do anything else.  We should never
+                     // get here if the OpenID auth beginning works,
+                     // because the user agent will be redirected.
+                     return true;
+                 }
+             }
+         
+             // Got here, so this is not the first time called.  We are
+             // somewhere in the middle of the OpenID login sequence.
+         
+             // Determine the OpenID identity and setup a request
+             // object, representing browser request.
+             $openid = $_GET['wpName'];
+ 
+             // Get the token out of the session.
+             $token = $_SESSION['openid_token'];
+             unset($_SESSION['openid_token']);
+ 
+             // Begin the OpenID auth.
+             list($status, $info) = $this->consumer->completeAuth($token, $_GET);
+ 
+             if (($status != Auth_OpenID_SUCCESS) ||
+                 (!$info)){
+                 $this->authenticated = false;
+                 if (!$info) {
+                     $this->message = "OpenID authentication cancelled.";
+                 } else {
+                     $this->message = "OpenID authentication failed.";
+                 }
+                 return false;
+             }
+         
+             $this->identity = $info;
+ 
+             if ($this->identity &&
+                 $status == Auth_OpenID_SUCCESS) {
+                 $this->authenticated = true;
+             }
+             return false;
+ 	}
+     
+         // private.  returns true if the username appears to be an
+         // OpenID Identity ( URL )
+         function is_openid_login( $username ) {
+             return strstr( $username, '://' ) || strstr( $username, '.' );
+         }
+ 
+         function has_scheme( $username ) {
+             return strstr( $username, '://' );
+         }
+     
+         /**
+          * private. Begins the OpenID auth sequence.
+          */
+         function _start_openid_login( $login_url ) {
+     
+             // The OpenID library handles loading the OpenID url and
+             // parsing for openid.server.
+             list($status, $info) = $this->consumer->beginAuth( $login_url );
+             if( $status != Auth_OpenID_SUCCESS ) {
+                 if ($status == Auth_OpenID_PARSE_ERROR) {
+                     $this->message = "The server returned an invalid response.";
+                 } else if ($status == Auth_OpenID_HTTP_FAILURE) {
+                     $this->message = "The OpenID server could not be contacted.";
+                 } else {
+                     $this->message = "OpenID authentication failed.";
+                 }
+                 return false;
+             } else {
+ 
+                 $_SESSION['openid_token'] = $info->token;
+ 
+                 // build trust root - this examines the script env and
+                 // builds based on your running location.  In practice
+                 // this may be static.
+                 $trust_root = sprintf("http://%s/",
+                                       $_SERVER['SERVER_NAME']);
+ 
+                 $site_url = 'http://'.$_SERVER['SERVER_NAME'].
+                     $_SERVER['REQUEST_URI'];
+ 
+                 $return_url = Auth_OpenID_appendArgs($site_url,
+                                                      array(
+                                                            'wpName' => $login_url,
+                                                            'wpLoginattempt' => '1',
+                                                            'is_open_id' => 1));
+ 
+                 // Create return_to url from app_url.
+                 $redirect_url = $this->consumer->constructRedirect($info, $return_url,
+                                                                    $trust_root);
+ 
+                 // Redirect the user-agent to the server.
+                 $this->_redirect($redirect_url);
+             }
+         }
+     
+         // private. performs a browser redirect.
+         function _redirect( $url ) {
+             header( "Location: $url" );
+         }
+ 
+         function dumb() {
+             return false;
+         }
+ 
+         function lastError() {
+             return $this->message;
+         }
+ }
+ 
+ ?>
diff -x CVS -x OpenID_Store -x LocalSettings.php -x Auth -crN phase3-pristine/includes/AuthPlugin.php phase3/includes/AuthPlugin.php
*** phase3-pristine/includes/AuthPlugin.php	2006-01-25 10:07:50.000000000 -0800
--- phase3/includes/AuthPlugin.php	2006-01-27 10:21:58.000000000 -0800
***************
*** 211,216 ****
--- 211,233 ----
  		# Override this to do something.
  	}
  
+         /**
+          * Allows the AuthPlugin to take full control of execution for
+          * this request and bypass normal login processing. This can
+          * be used to extend authentication over several page
+          * requests.  This is necessary for an OpenID login, and
+          * possibly other situations.
+          *
+          * This function should return true if it has handled the request, or
+          * false to continue with normal mediawiki processing.
+          *
+          * @return bool
+          * @access public
+          */
+         function processLogin( $username, $password ) {
+             return false;
+         }
+ 
  	/**
  	 * If you want to munge the case of an account name before the final
  	 * check, now is your chance.
***************
*** 218,223 ****
--- 235,259 ----
  	function getCanonicalName( $username ) {
  		return $username;
  	}
+ 
+         /**
+          * Returns true for this class only; override and return false
+          * for any plugin class that actually authenticates!  You
+          * REALLY shouldn't pay attention to anything this plugin says
+          * because it doesn't do anything; it's a placeholder for a
+          * real auth plugin.  Subclasses should return false from this
+          * method so you can be sure their responses mean something.
+          */
+         function dumb() {
+             return true;
+         }
+ 
+         /**
+          * Return an error message from the last authentication.  If
+          * no error occurred, return null.
+          */
+         function lastError() {
+         }
  }
  
  ?>
diff -x CVS -x OpenID_Store -x LocalSettings.php -x Auth -crN phase3-pristine/includes/DefaultSettings.php phase3/includes/DefaultSettings.php
*** phase3-pristine/includes/DefaultSettings.php	2006-01-31 14:26:14.000000000 -0800
--- phase3/includes/DefaultSettings.php	2006-01-31 14:27:17.000000000 -0800
***************
*** 1630,1635 ****
--- 1630,1653 ----
  $wgAuth = null;
  
  /**
+  * Use OpenID if available?  Note that if available, OpenID auth will
+  * be used IN ADDITION TO normal $wgAuth-based user auth, not as a
+  * replacement for the auth tasks performed by the $wgAuth.
+  */
+ $wgUseOpenID = false;
+ 
+ /**
+  * Store an openid auth plugin object here.  This will be used to
+  * verify OpenID URL logins if they are entered instead of usernames.
+  * If OpenID support is not used (wgUseOpenID = false) or not found
+  * (OPENID_SUPPORT is undefined), this object will NOT be used in the
+  * auth process.  Editors of DefaultSettings.php and LocalSettings.php
+  * should NOT actually set this variable's value; this is a
+  * placeholder for AuthPluginOpenID.php.
+  */
+ $wgAuth_OpenID = null;
+ 
+ /**
   * Global list of hooks.
   * Add a hook by doing:
   *     $wgHooks['event_name'][] = $function;
diff -x CVS -x OpenID_Store -x LocalSettings.php -x Auth -crN phase3-pristine/includes/Setup.php phase3/includes/Setup.php
*** phase3-pristine/includes/Setup.php	2006-01-25 10:07:50.000000000 -0800
--- phase3/includes/Setup.php	2006-01-26 12:09:14.000000000 -0800
***************
*** 205,212 ****
  }
  
  if( !is_object( $wgAuth ) ) {
! 	require_once( 'AuthPlugin.php' );
! 	$wgAuth = new AuthPlugin();
  }
  
  if( $wgCommandLineMode ) {
--- 205,219 ----
  }
  
  if( !is_object( $wgAuth ) ) {
!     require_once( 'AuthPlugin.php' );
!     $wgAuth = new AuthPlugin();
! }
! 
! if ($wgUseOpenID) {
!     require_once( 'AuthPluginOpenID.php' );
!     if (defined('OPENID_SUPPORT')) {
!         $wgAuth_OpenID = new AuthPluginOpenID();
!     }
  }
  
  if( $wgCommandLineMode ) {
diff -x CVS -x OpenID_Store -x LocalSettings.php -x Auth -crN phase3-pristine/includes/SpecialUserlogin.php phase3/includes/SpecialUserlogin.php
*** phase3-pristine/includes/SpecialUserlogin.php	2006-01-30 12:34:07.000000000 -0800
--- phase3/includes/SpecialUserlogin.php	2006-01-31 15:05:38.000000000 -0800
***************
*** 28,33 ****
--- 28,34 ----
  	var $mName, $mPassword, $mRetype, $mReturnto, $mCookieCheck, $mPosted;
  	var $mAction, $mCreateaccount, $mCreateaccountMail, $mMailmypassword;
  	var $mLoginattempt, $mRemember, $mEmail, $mDomain;
+         var $request;
  
  	/**
  	 * Constructor
***************
*** 87,96 ****
  				return $this->addNewAccountMailPassword();
  			} else if ( $this->mMailmypassword ) {
  				return $this->mailPassword();
- 			} else if ( ( 'submitlogin' == $this->mAction ) || $this->mLoginattempt ) {
- 				return $this->processLogin();
  			}
  		}
  		$this->mainLoginForm( '' );
  	}
  
--- 88,102 ----
  				return $this->addNewAccountMailPassword();
  			} else if ( $this->mMailmypassword ) {
  				return $this->mailPassword();
  			}
  		}
+ 
+                 // This is necessary to let the OpenID code be called
+                 // in both GET and POST cases.
+                 if ( ( 'submitlogin' == $this->mAction ) || $this->mLoginattempt ) {
+                         return $this->processLogin();
+                 }
+ 
  		$this->mainLoginForm( '' );
  	}
  
***************
*** 164,170 ****
  		global $wgUser, $wgOut;
  		global $wgEnableSorbs, $wgProxyWhitelist;
  		global $wgMemc, $wgAccountCreationThrottle, $wgDBname;
! 		global $wgAuth, $wgMinimalPasswordLength;
  
  		// If the user passes an invalid domain, something is fishy
  		if( !$wgAuth->validDomain( $this->mDomain ) ) {
--- 170,176 ----
  		global $wgUser, $wgOut;
  		global $wgEnableSorbs, $wgProxyWhitelist;
  		global $wgMemc, $wgAccountCreationThrottle, $wgDBname;
! 		global $wgAuth, $wgMinimalPasswordLength, $wgAuth_OpenID;
  
  		// If the user passes an invalid domain, something is fishy
  		if( !$wgAuth->validDomain( $this->mDomain ) ) {
***************
*** 205,211 ****
  		}
  
  		$name = trim( $this->mName );
! 		$u = User::newFromName( $name );
  		if ( is_null( $u ) ) {
  			$this->mainLoginForm( wfMsg( 'noname' ) );
  			return false;
--- 211,230 ----
  		}
  
  		$name = trim( $this->mName );
!                 $u = null;
! 
!                 // Don't allow account creation for OpenID usernames;
!                 // they can be created just by logging in.  This check
!                 // needs to be a local check only.
!                 if ( defined('OPENID_SUPPORT') &&
!                      strstr( $name, '://' ) ) {
!                     return false;
!                 }
! 
!                 $u = User::newFromName( $name );
! 
!                 if (is_null($u)) { print "NOOOOO"; }
! 
  		if ( is_null( $u ) ) {
  			$this->mainLoginForm( wfMsg( 'noname' ) );
  			return false;
***************
*** 285,328 ****
  	 * @access private
  	 */
  	function processLogin() {
! 		global $wgUser;
! 		global $wgAuth;
  
  		if ( '' == $this->mName ) {
  			$this->mainLoginForm( wfMsg( 'noname' ) );
  			return;
  		}
! 		$u = User::newFromName( $this->mName );
  		if( is_null( $u ) ) {
  			$this->mainLoginForm( wfMsg( 'noname' ) );
  			return;
  		}
  		if ( 0 == $u->getID() ) {
- 			global $wgAuth;
  			/**
  			 * If the external authentication plugin allows it,
  			 * automatically create a new account for users that
  			 * are externally defined but have not yet logged in.
  			 */
! 			if ( $wgAuth->autoCreate() && $wgAuth->userExists( $u->getName() ) ) {
! 				if ( $wgAuth->authenticate( $u->getName(), $this->mPassword ) ) {
  					$u =& $this->initUser( $u );
  				} else {
  					$this->mainLoginForm( wfMsg( 'wrongpassword' ) );
  					return;
  				}
  			} else {
  				$this->mainLoginForm( wfMsg( 'nosuchuser', $u->getName() ) );
! 				return;
  			}
! 		} else {
! 			$u->loadFromDatabase();
! 		}
  
! 		if (!$u->checkPassword( $this->mPassword )) {
! 			$this->mainLoginForm( wfMsg( $this->mPassword == '' ? 'wrongpasswordempty' : 'wrongpassword' ) );
! 			return;
! 		}
  
  		# We've verified now, update the real record
  		#
--- 304,406 ----
  	 * @access private
  	 */
  	function processLogin() {
! 		global $wgUser, $wgUseOpenID;
  
  		if ( '' == $this->mName ) {
  			$this->mainLoginForm( wfMsg( 'noname' ) );
  			return;
  		}
! 
!                 $authPlugin = null;
! 
!                 // If the username being tried is an OpenID, use the
!                 // OpenID auth plugin; otherwise, use whatever is in
!                 // $wgAuth.  This is because we want to allow OpenID
!                 // auth whenever it's desired, while still allowing
!                 // the locally-chosen external auth.
!                 if ( $wgUseOpenID &&
!                      defined('OPENID_SUPPORT') &&
!                      AuthPluginOpenID::is_openid_login( $this->mName ) ) {
!                     global $wgAuth_OpenID;
!                     $authPlugin =& $wgAuth_OpenID;
!                 } else {
!                     global $wgAuth;
!                     $authPlugin =& $wgAuth;
!                 }
! 
!                 // Try to find out of the entered username corresponds
!                 // to a preexisting account.
!                 $pre_check = User::newFromName( $this->mName );
!                 
!                 // If the username DOES correspond to a preexisting
!                 // account and it STILL looks like an OpenID, DO NOT
!                 // use OpenID auth.  Use normal auth.
!                 if ( ( $authPlugin == $wgAuth_OpenID ) &&
!                      ( ! $wgAuth_OpenID->has_scheme( $this->mName ) ) &&
!                      ( is_null( $pre_check ) ||
!                        0 != $pre_check->getID() ) ) {
!                     print "CANCELLING OPENID";
!                     global $wgAuth;
!                     $authPlugin =& $wgAuth;
!                 }
! 
! 		$u = User::newFromName( $authPlugin->getCanonicalName( $this->mName ) );
! 
!                 if ( $authPlugin->processLogin( $this->mName, $this->mPassword ) ) {
!                     return;
!                 }
! 
  		if( is_null( $u ) ) {
  			$this->mainLoginForm( wfMsg( 'noname' ) );
  			return;
  		}
+ 
  		if ( 0 == $u->getID() ) {
  			/**
  			 * If the external authentication plugin allows it,
  			 * automatically create a new account for users that
  			 * are externally defined but have not yet logged in.
  			 */
! 			if ( $authPlugin->autoCreate() && $authPlugin->userExists( $u->getName() ) ) {
! 				if ( $authPlugin->authenticate( $u->getName(), $this->mPassword ) ) {
  					$u =& $this->initUser( $u );
  				} else {
  					$this->mainLoginForm( wfMsg( 'wrongpassword' ) );
  					return;
  				}
  			} else {
+ 
+                             if ( !$authPlugin->dumb() ) {
+                                 $this->mainLoginForm( $authPlugin->lastError() );
+                             } else {
  				$this->mainLoginForm( wfMsg( 'nosuchuser', $u->getName() ) );
!                             }
!                             return;
  			}
! 		} else if ( !$authPlugin->dumb() &&
!                             $authPlugin->authenticate( $u->getName(), $this->mPassword ) ) {
!                     // If the above clause is false, just go on to the
!                     // local password check as a fallback.  If it's
!                     // true, the external auth succeeded.
! 
!                 } else if ( !$authPlugin->dumb() ) {
! 
!                     // If the external auth plugin is not dumb and
!                     // authentication failed, be sure to return the
!                     // exact error message from the plugin.
!                     $this->mainLoginForm( $authPlugin->lastError() );
!                     return;
! 
!                 } else if ( $this->mPassword &&
!                             !$u->checkPassword( $this->mPassword )) {
!                         $this->mainLoginForm( wfMsg( 'wrongpassword' ) );
! 			return;
!                 } else if ( !$this->mPassword ) {
!                         $this->mainLoginForm( wfMsg( 'wrongpasswordempty' ) );
!                         return;
!                 }
  
!                 $u->loadFromDatabase();
  
  		# We've verified now, update the real record
  		#
***************
*** 333,339 ****
  		}
  		$u->setOption( 'rememberpassword', $r );
  
! 		$wgAuth->updateUser( $u );
  
  		$wgUser = $u;
  		$wgUser->setCookies();
--- 411,417 ----
  		}
  		$u->setOption( 'rememberpassword', $r );
  
! 		$authPlugin->updateUser( $u );
  
  		$wgUser = $u;
  		$wgUser->setCookies();
diff -x CVS -x OpenID_Store -x LocalSettings.php -x Auth -crN phase3-pristine/includes/templates/Userlogin.php phase3/includes/templates/Userlogin.php
*** phase3-pristine/includes/templates/Userlogin.php	2006-01-30 12:34:25.000000000 -0800
--- phase3/includes/templates/Userlogin.php	2006-01-30 12:35:50.000000000 -0800
***************
*** 33,39 ****
  	<div id="userloginprompt"><?php  $this->msgWiki('loginprompt') ?></div>
  	<table>
  		<tr>
! 			<td align='right'><label for='wpName1'><?php $this->msg('yourname') ?>:</label></td>
  			<td align='left'>
  				<input type='text' class='loginText' name="wpName" id="wpName1"
  					value="<?php $this->text('name') ?>" size='20' />
--- 33,39 ----
  	<div id="userloginprompt"><?php  $this->msgWiki('loginprompt') ?></div>
  	<table>
  		<tr>
! 			<td align='right'><label for='wpName1'><?php ($GLOBALS['wgUseOpenID'] && defined('OPENID_SUPPORT')) ? $this->msgHtml('yournameoropenid') : $this->msg('yourname') ?>:</label></td>
  			<td align='left'>
  				<input type='text' class='loginText' name="wpName" id="wpName1"
  					value="<?php $this->text('name') ?>" size='20' />
***************
*** 45,50 ****
--- 45,51 ----
  				<input type='password' class='loginPassword' name="wpPassword" id="wpPassword1"
  					value="<?php $this->text('password') ?>" size='20' />
  			</td>
+                         <?php if ($GLOBALS['wgUseOpenID'] && defined('OPENID_SUPPORT')) { echo '<tr><td></td><td>'; $this->msg('yourpasswordopenid'); echo '</td></tr>'; } ?>
  		</tr>
  	<?php if( $this->data['usedomain'] ) {
  		$doms = "";
diff -x CVS -x OpenID_Store -x LocalSettings.php -x Auth -crN phase3-pristine/includes/Title.php phase3/includes/Title.php
*** phase3-pristine/includes/Title.php	2006-01-25 10:07:50.000000000 -0800
--- phase3/includes/Title.php	2006-01-25 15:37:50.000000000 -0800
***************
*** 754,760 ****
  			$url = $this->getFullURL();
  		} else {
  			$dbkey = wfUrlencode( $this->getPrefixedDBkey() );
! 			if ( $query == '' ) {
  				$url = str_replace( '$1', $dbkey, $wgArticlePath );
  			} else {
  				global $wgActionPaths;
--- 754,760 ----
  			$url = $this->getFullURL();
  		} else {
  			$dbkey = wfUrlencode( $this->getPrefixedDBkey() );
! 			if ( $query == '' && !strstr( $dbkey, '//' ) ) {
  				$url = str_replace( '$1', $dbkey, $wgArticlePath );
  			} else {
  				global $wgActionPaths;
***************
*** 774,780 ****
  					if ( $query == '-' ) {
  						$query = '';
  					}
! 					$url = "{$wgScript}?title={$dbkey}&{$query}";
  				}
  			}
  			
--- 774,781 ----
  					if ( $query == '-' ) {
  						$query = '';
  					}
!                                         $amp = $query ? '&' : '';
! 					$url = "{$wgScript}?title={$dbkey}{$amp}{$query}";
  				}
  			}
  			
diff -x CVS -x OpenID_Store -x LocalSettings.php -x Auth -crN phase3-pristine/includes/User.php phase3/includes/User.php
*** phase3-pristine/includes/User.php	2006-01-31 14:26:39.000000000 -0800
--- phase3/includes/User.php	2006-01-31 14:43:26.000000000 -0800
***************
*** 63,70 ****
  
  		# Reject various classes of invalid names
  		$canonicalName = $t->getText();
! 		global $wgAuth;
! 		$canonicalName = $wgAuth->getCanonicalName( $t->getText() );
  
  		if( !User::isValidUserName( $canonicalName ) ) {
  			return null;
--- 63,79 ----
  
  		# Reject various classes of invalid names
  		$canonicalName = $t->getText();
! 		global $wgAuth, $wgUseOpenID, $wgAuth_OpenID;
! 
!                 if ( $wgUseOpenID &&
!                      defined('OPENID_SUPPORT') &&
!                      $wgAuth_OpenID->is_openid_login( $name ) ) {
!                         $canonicalName = $wgAuth_OpenID->getCanonicalName( $name );
!                         $canonicalNameDiffers = ($canonicalName != $name);
!                 } else {
!                         $canonicalName = $wgAuth->getCanonicalName( $t->getText() );
!                         $canonicalNameDiffers = false;
!                 }
  
  		if( !User::isValidUserName( $canonicalName ) ) {
  			return null;
***************
*** 72,78 ****
  
  		$u = new User();
  		$u->setName( $canonicalName );
! 		$u->setId( $u->idFromName( $canonicalName ) );
  		return $u;
  	}
  
--- 81,87 ----
  
  		$u = new User();
  		$u->setName( $canonicalName );
! 		$u->setId( $u->idFromName( $canonicalName, $canonicalNameDiffers ) );
  		return $u;
  	}
  
***************
*** 139,154 ****
  	 * @return integer|null Database user id (null: if non existent
  	 * @static
  	 */
! 	function idFromName( $name ) {
  		$fname = "User::idFromName";
  
! 		$nt = Title::newFromText( $name );
! 		if( is_null( $nt ) ) {
! 			# Illegal name
  			return null;
! 		}
  		$dbr =& wfGetDB( DB_SLAVE );
! 		$s = $dbr->selectRow( 'user', array( 'user_id' ), array( 'user_name' => $nt->getText() ), $fname );
  
  		if ( $s === false ) {
  			return 0;
--- 148,167 ----
  	 * @return integer|null Database user id (null: if non existent
  	 * @static
  	 */
! 	function idFromName( $name, $canonical_differs = false ) {
  		$fname = "User::idFromName";
  
!                 if (!$canonical_differs) {
!                     $nt = Title::newFromText( $name );
!                     if( is_null( $nt ) ) {
!                         // Illegal name
  			return null;
!                     }
!                     $name = $nt->getText();
!                 }
! 
  		$dbr =& wfGetDB( DB_SLAVE );
! 		$s = $dbr->selectRow( 'user', array( 'user_id' ), array( 'user_name' => $name ), $fname );
  
  		if ( $s === false ) {
  			return 0;
***************
*** 184,216 ****
  	/**
  	 * Is the input a valid username?
  	 *
! 	 * Checks if the input is a valid username, we don't want an empty string,
! 	 * an IP address, anything that containins slashes (would mess up subpages),
! 	 * is longer than the maximum allowed username size or doesn't begin with
! 	 * a capital letter.
  	 *
  	 * @param string $name
  	 * @return bool
  	 * @static
  	 */
  	function isValidUserName( $name ) {
! 		global $wgContLang, $wgMaxNameChars;
  
  		if ( $name == ''
  		|| User::isIP( $name )
! 		|| strpos( $name, '/' ) !== false
! 		|| strlen( $name ) > $wgMaxNameChars
! 		|| $name != $wgContLang->ucfirst( $name ) )
  			return false;
  
  		// Ensure that the name can't be misresolved as a different title,
  		// such as with extra namespace keys at the start.
  		$parsed = Title::newFromText( $name );
  		if( is_null( $parsed )
! 			|| $parsed->getNamespace()
! 			|| strcmp( $name, $parsed->getPrefixedText() ) )
  			return false;
! 		else
  			return true;
  	}
  
--- 197,246 ----
  	/**
  	 * Is the input a valid username?
  	 *
! 	 * Checks if the input is a valid username, we don't want an
! 	 * empty string, an IP address, anything that containins
! 	 * slashes (would mess up subpages), is longer than the
! 	 * maximum allowed username size or doesn't begin with a
! 	 * capital letter.  If the $name is a valid OpenID identity
! 	 * URL and OpenID support is found and used ($wgUseOpenID =
! 	 * true), slashes will be allowed and character case will not
! 	 * be considered.
  	 *
  	 * @param string $name
  	 * @return bool
  	 * @static
  	 */
  	function isValidUserName( $name ) {
!                 global $wgContLang, $wgMaxNameChars, $wgUseOpenID, $wgAuth_OpenID;
! 
!                 $is_openid = false;
! 
!                 // If OpenID support is both present and desired AND
!                 // the username being checked is an OpenID, relax the
!                 // rules a little.
!                 if ( $wgUseOpenID &&
!                      defined('OPENID_SUPPORT') &&
!                      $wgAuth_OpenID->is_openid_login( $name ) ) {
!                     $is_openid = true;
!                 }
  
  		if ( $name == ''
  		|| User::isIP( $name )
!                 || ( ( strpos( $name, '/' ) !== false ) && !$is_openid )
!                 || ( ( strpos( $name, '?' ) !== false ) && !$is_openid )
!                 || ( strlen( $name ) > $wgMaxNameChars )
!                 || ( $name != $wgContLang->ucfirst( $name ) && !$is_openid ) ) {
  			return false;
+                 }
  
  		// Ensure that the name can't be misresolved as a different title,
  		// such as with extra namespace keys at the start.
  		$parsed = Title::newFromText( $name );
  		if( is_null( $parsed )
!                     || $parsed->getNamespace()
!                     || ( strcmp( $name, $parsed->getPrefixedText() ) && !$is_openid ) )
  			return false;
!                 else
  			return true;
  	}
  
diff -x CVS -x OpenID_Store -x LocalSettings.php -x Auth -crN phase3-pristine/languages/Messages.php phase3/languages/Messages.php
*** phase3-pristine/languages/Messages.php	2006-01-30 12:34:51.000000000 -0800
--- phase3/languages/Messages.php	2006-01-30 12:36:01.000000000 -0800
***************
*** 343,350 ****
--- 343,352 ----
  
  'loginpagetitle' => 'User login',
  'yourname'		=> 'Username',
+ 'yournameoropenid' => 'Username or <a href="http://www.openid.net/">OpenID</a>',
  'yourpassword'	=> 'Password',
  'yourpasswordagain' => 'Retype password',
+ 'yourpasswordopenid' => '(password not required for OpenID login)',
  'newusersonly'	=> ' (new users only)',
  'remembermypassword' => 'Remember me',
  'yourdomainname'       => 'Your domain',
