Requests for comment/AuthManager

The current authentication and authorization system is very limited and restricted in terms of the allowed customization, for both system administrators and extension developers.

Current problems
Our current authnz system consists of:


 * User::comparePassword, User::crypt, and custom authentication entry point code
 * $wgGroupPermissions, $wgRevokePermissions, and about five other global variables
 * The AuthPlugin interface and $wgAuth
 * User::loadFromSession and User::setCookies for session authentication

This combination of completely hard-coded code paths has led to a number of restrictions and problems:
 * Only one external authentication service can be used at a time
 * Users in an external service must be identified by a username and password
 * System administrators who want to customize permissions must switch between multiple global variables, and even then some combinations of access policies are not possible
 * There is a massive mix of concerns within the User class, which handles model logic as well as authentication and session logic

AuthStack
This RFC proposes the implementation of a new system for authentication and authorization that will allow system administrators to have better control over their wiki's access policies and extension developers to make cleaner implementations of authnz extensions for use in MediaWiki.

AuthProvider, AuthPolicy, and ExternalUser
The primary infrastructure for the system will be implemented using three classes: AuthProvider, AuthPolicy, and ExternalUser. These classes combined will provide three services to the MediaWiki core:
 * 1) authenticate a user based on certain authentication data,
 * 2) retrieve a list of user groups the user is in from that service,
 * 3) and determine what a specific provider supports and what policies MediaWiki should enforce for that service.

The separation of concerns is as follows:
 * AuthProvider - responsible for communication with the external authentication service and the retrieval and sending of data to/from the provider
 * AuthPolicy - responsible for telling MediaWiki what services the provider supports and whether strict authentication and/or authorization is allowed
 * ExternalUser (tentative name) - responsible for bridging the provider itself (from AuthProvider) and the MediaWiki core; will handle the actual authentication logic for the provider as well as interpreting and returning which groups the user is in

An AuthProvider is considered a central service, and will maintain the actual connection to the external service. Thus only one instance of a specific AuthProvider should be instantiated at a given time. Additionally, an AuthPolicy should be as static as possible (most AuthPolicy objects will have one-line functions that return a static boolean value) and should also be instantiated only once.

The (AuthProvider, AuthPolicy, ExternalUser) combination is considered unique, but any subset of the three is not. In other words, a single AuthProvider or a single AuthPolicy may be re-used between different layers of the stack. For example, if there are two LDAP-based authentication extensions, but one looks at one server and the other at a different server, they can share the same AuthPolicy (and possibly even the same AuthProvider).

Permissions
The Permissions class is a final class that handles the translation of groups into actual permissions. In this class, there is no concept of User, ExternalUser, AuthProvider, etc. There are only arrays. In other words, this class is *purely* for translating groups into permissions. The class will also be responsible for maintaining the list of valid permissions.

AuthStack
The top layer of the new authnz system is the AuthStack class, and is responsible for the following:


 * Maintaining a stack of (AuthProvider, AuthPolicy, ExternalUser) combinations
 * Querying the entire stack when performing authentication and authorization
 * Handling autopromotion (rather than the Autopromote class)

The AuthStack object shall provide an external interface for the MediaWiki core to interact with the authentication and authorization stack without worrying about the internal implementations of various providers.

Built-in stack members
MediaWiki will come installed with a number of default authentication and authorization providers:
 * LocalProvider - Authentication and authorization provider for the local database password hashes (see below for the new password hashing interface)
 * AuthPluginProvider - Backwards-compatibility provider for extensions that use the AuthPlugin class to provide authnz logic

ClientSession
The AuthStack is intended to handle initial back-end authentication and authorization of a user. However, logic for handling session authentication, i.e., determining the identity of a client post-login, will be separate from this. Right now this logic resides in the user class, specifically User::loadFromSession.

A new class named ClientSession will be created. This will represent a session with the current client, and will contain logic for initiating, authenticating, and destroying the session. The reasons for this separation are: See below for an example interface for the ClientSession class.
 * It allows developers to inherit this class, and thus change or supplement session logic (currently the only way to do this is through the UserLoadFromSession hook).
 * The User class should only handle logic relating to users, and while the client session may have a user associated with it, the logic of authenticating the session and determining that user is not within the scope of a model class.

Password and PasswordHash
This is the final new component of the framework. The Password and PasswordHash classes will reside primarily within the LocalProvider authentication provider inside the AuthStack, but they may be used by other providers where applicable. The intention is to provide an extensible interface for password hashing.

As mentioned, the framework consists of two classes:
 * PasswordHash - represents a hashed password. This class contains the actual logic for hashing a plaintext password and parsing an existing hash
 * Password - represents a user's password. This class is merely a wrapper for the PasswordHash class. Whereas the PasswordHash class contains hashing logic, the Password class is used for actually comparing hashes and updating a user's password hash when necessary.

Built-in password hashes
MediaWiki will come built-in with support for using the following methods of password hashing:
 * Backwards-compatible unsalted MD5 password hashing
 * Backwards-compatible salted MD5 password hashing
 * Bcrypt
 * PBKDF2? (this is questionable, since this algorithm is not really made for password hashing)

Code interface
This is an example function interface for what the components of this new system would look like. Of course, this is subject to change.

User interface
Below is an example interface of how users will interact with the new system.

For system administrators
System administrators will interact primarily with the Permissions class, which handles the translation of groups into permissions.

For extension developers
Extension developers will add their own providers onto the AuthStack.

Note that when registering, AuthStack takes the provider and policy as an object, since they are shared across the entire service, but takes the ExternalUser as a class name instead, since a new ExternalUser will be instantiated for each user being authenticated.

For core developers
Core developers will need to use the AuthStack to perform authentication and authorization before performing actions.

Deprecated interfaces
The following interfaces will be deprecated by the AuthStack system:


 * $wgGroupPermission, $wgRevokePermissions, $wgEmailConfirmToEdit, $wgImplicitGroups
 * $wgGroupsAddToSelf, $wgGroupsRemoveFromSelf, $wgAddGroups, $wgRemoveGroups
 * The Autopromote class, $wgAutopromote, $wgAutopromoteOnce
 * User::checkPassword, User::comparePasswords, User::getGroupPermissions, User::getGroupsWithPermission, User::groupHasPermission, User::getGroupName, User::getGroupMember, User::getAllGroups, User::getAllRights, User::getImplicitGroups, User::getGroupPage, User::changeableByGroup, User::changeableGroups, User::getRightDescription
 * User::crypt, User::oldCrypt, User::comparePassword, User::checkPassword, User::setPassword
 * User::newFromSession, User::loadFromSession, User::setCookies, User::setCookie, User::clearCookie
 * The AuthPlugin system

In addition, the Block, SpecialBlock, Special:BlockList, and Special:Blockme classes will all be adjusted to account for the fact that now permission can be granted to block *any* permission, rather than just editing.

Effect on Special:Userlogin
Right now the process of logging in on Special:Userlogin consists of a number of concise steps:


 * 1) Check the token (will be moved to HTMLForm logic by 27022)
 * 2) Check the login throttle (will be moved to Throttle class by 34677 and into HTMLForm from there in 27022)
 * 3) Attempt to autocreate the user (will be moved from AuthPlugin to AuthStack framework)
 * 4) Check the user's password (will be moved into new AuthStack framework)
 * 5) If failed, check the user's temporary password (will be moved to separate page in 27472)
 * 6) Check if the user is blocked
 * 7) Log the user in (will be moved to ClientSession class)

Once the mentioned patches are merged, the SpecialUserlogin class will only be responsible for communicating with other components.