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:


 * $wgGroupPermissions, $wgRevokePermissions, and about five other global variables
 * User::crypt, User::comparePasswords, User::loadFromSession, etc.
 * The AuthPlugin interface and $wgAuth

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

This RFC hopes to fix just a section of this problem: external authentication, i.e., the first two bullet points. This will be done by deprecating the AuthPlugin system and replacing it will a comprehensive authentication and authorization layer. The job of this system will be to perform original authentication on users and to determine what user groups a user is in. Any further authentication, e.g., authentication via session cookies, is out of scope for this RFC. Additionally, the resolution of user groups to actual permissions is also out of scope.

Existing usage
This is a list of extensions in Gerrit which subclass AuthPlugin and comments about them:
 * LdapAuthenticationPlugin
 * Adds ChainAuth hook to allow for multiple authentication methods
 * Hooks: UserLoadAfterLoadFromSession
 * Auth_remoteuser
 * Sets $wgMinimalPasswordLength = 0;
 * Does a Fake login to LoginForm inside the AuthPlugin???
 * CentralAuthPlugin
 * Scary stuff, uses way too many hooks to list.
 * GoogleLoginPlugin
 * Redirects login requests to its own login page?
 * Hooks: UserLogoutComplete, UserLoginForm, UserCreateForm
 * MediaWikiAuthPlugin
 * Requires core patch to display a custom error message on Special:Userlogin

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).

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

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

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:


 * User::checkPassword, User::comparePasswords
 * The AuthPlugin system

Additionally, the backend logic will be moved out of LoginForm and into a separate backend class. SpecialUserLogin and ApiLogin would both then call this backend class.

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.