User:Legoktm/authn

Hopefully readable summary:
 * Everything is a mess, but I think we already knew that.
 * AuthPlugin handles policy questions, actual doing of things (authenticate), and modifying the UI
 * AuthPluginUser is only used by CentralAuth
 * Code in core split across User, LoginForm (SpecialUserlogin), AuthPlugin, AuthPluginUser. Majority of logic in SpecialUserlogin, which API calls internally (ewww)
 * Mixture of hooks and AuthPlugin subclassing
 * Need multiple layers - so you could could have TwoFactorAuth on top of CentralAuth
 * Extensions that just use hooks and modify the UI like OATHAuth don't support the API properly.
 * Hooks like UserLoginComplete which allow for injecting raw HTML are terrible hacks.

LoginForm::execute LoginForm::processLogin LoginForm::authenticateUserData LoginForm::attemptAutoCreate * AbuseFilter, Titleblacklist hook in here to stop bad accounts * CentralAuth hooks in to stop new account creation if a global rename is in progress...why???? * CentralAuthHooks::attemptAddUser calls this hook and appears to replicate logic from LoginForm (LdapAutoAuthentication::attemptAddUser also looks similar) LoginForm::initUser
 * If no session exists, wfSetupSession is called
 * LoginForm::load calls $wgAuth->setDomain if the wpDomain parameter was passed
 * Redirect to HTTPS happens if necessary ($wgSecureLogin/wfCanIPUseHTTPS)
 * Check to make sure the client supports cookies
 * Validate non-empty username, token is valid, and checks login throttle (which is different from the normal MW ping limiter system)
 * Load the current user from the session, invoking the UserLoadFromSession hook which might auto-create the user. Tim calls this hook evil, more on it later.
 * LoginUserMigrated hook is run, which was for CentralAuth to say a user had been renamed
 * If the user still does not exist, LoginForm::attemptAutoCreate is called.
 * Checks to see if User::isBlockedFromCreateAccount, then if $wgAuth->autoCreate, $wgAuth->userExists, and $wgAuth->AbortAutoAccount.
 * AbortAutoAccount hook is called:
 * Add user object to database, then set email, realname, token
 * Call $wgAuth->initUser
 * Update SiteStats and add user's userpage+talk page to watchlist

If autocreation failed, we're back in authenticateUserData * OATHAuth - verifies wpOATHAuth token (the way this extension uses hooks feels like a hack that we don't support multiple auth layers) * CentralAuth - checks user is currently not being globally renamed and is not locked * ConfirmEdit - verify captcha, if you go over 3 bad logins and fail captcha, claims a bad password was entered * SSLClientAuthentication - does some weird ORM stuff, but just authenticating with SSL certificates * TwoFactorAuthentication - either does a redirect to Special:TwoFactorAuth/auth or verifies an external token * SecureSessions
 * AbortLogin hook is run, provides User, raw password, abort constant, message key

If hook was not aborted, we check the user's password using User::checkPassword: * Calls $wgAuth->authenticate, if it returns false, $wgAuth->strict and $wgAuth->strictUserAuth (used by CA) is called to check whether we can use local authentication. * If $wgAuth didn't do anything, the Password object is checked, and PasswordFactory might also update the password back in LoginForm::authenticateUserData ...and we're back in LoginForm::processLogin! There's a giant switch statement that processes the return value of authenticateUserData:
 * If password didn't match, there is legacy code to check for a temporary password
 * Check if they're blocked and $wgBlockDisablesLogin (typically true on private wikis)
 * if their password is expired, force a password reset without login
 * If the password *did* match, $wgAuth->updateUser, set $wgUser and the context user. Clear login throttle.
 * If autocreated, call AuthPluginAutoCreate hook (CheckUser and NewUserMessage)
 * Call LoginAuthenticateAudit hook (for good and bad logins), used by ConfirmEdit to clear captcha count, hook also used in WMF prod to log failed logins to sysop accounts
 * Success: Invalidate the User's cache, check whether the user requires HTTPS ('prefershttps' preference, UserRequiresHTTPS hook, wfCanIPUseHTTPS), set some cookies accordingly, clear the login token, reset password throttle, set $wgLang/context lang to user's preferred language (re-implementing a bit of RequestContext logic :/), if "soft" expired password or length too short, show reset form. Calls LoginForm::successfulLogin, triggers UserLoginComplete hook, which allows for injecting raw HTML into the response...ewwwwww. If no hook adds HTML, the user will be redirected to back where they came from.
 * If it's not sucess, then an error message is picked and formatted to be displayed to the user.