To implement an oauth2 authentication plugin, Moodle needs to log the user in even though the user auth method is set to "manual". I think Moodle should support multiple auth methods for one Moodle account.
Note: we still keep the auth field in 'mdl_user' table as primary auth method.
Use case: login with a second auth method during login
- Case 1: Moodle finds that the second auth method can be linked to the account (example with Google oauth2: the user email address sent by Google matches a Moodle account. This email address is marked as verified.).
- Case 2: Moodle doesn't find a linkable account. Moodle suggest the user to create a new user.
The user is logged in. In the edit profile page, the user connects with the second auth method and is redirect to the same edit profile page. No attempt to re-log the user in. Moodle just adds a record to mdl_user_auth_methods.
- add checkbox to allow to remove an authentication method. If the plugin is set to true, then if the authentication method is not the primary auth method, the user can remove it from the edit profile.
Old proposal: Some random notes about multi-auth in Moodle
Moodle1.8 Before starting to code anything about Multi Authentication support in Moodle, I would like to share what I have in mind, so others can see the flaws and everybody can spot the problems with this approach.
There are some big questions (see below) I don't know the answer for, so if others with more knowledge of Moodle internals (specially authentication internals) than me could answer them, that would be great.
Following text does not describe current auth implementation in 1.8! Skodak
- Multiple simultaneous sources for authentication
- Multiples authentication instances (instances for short) of the same source type (LDAP, database, etc)
- Each instance has its own configuration
- The order in which we try the instances is configurable
How it works
- Each source (and thus each instance) has at least the auth_user_login function, like now. (this may change to class function user_login() once Jonathan Harker and Martin Langhoff work in multi-authentication is merged).
- This function can return one of the following values:
- AUTH_OK: the user and the password are valid
- AUTH_DECLINED: The user or the password are not correct or unknown to this source
- AUTH_DENIED: This user cannot login, even if the username and password are valid
- AUTH_ERROR: The source found and error during user and password validation and can't say wether they are valid or not.
- We try each instance in the configured order.
- For each instance, we call auth_user_login() (or user_login()) with the user credentials, and test the result.
- if the result is AUTH_DENIED, we break out of the loop and deny the user login.
- if the result is AUTH_OK, we break out of the loop and allow the user login.
- in any other case, we continue the loop.
- If we finish the loop, we deny the user login (all the instances returned either AUTH_DECLINED or AUTH_ERROR, so we can't let the user log in).
The (proposed) database tables
(MySQL syntax, Postgresql syntax omitted for shortness)
CREATE TABLE `prefix_auth_type` ( `id` integer(10) NOT NULL auto_increment, `name` varchar(20) NOT NULL default '', `isinternal` tinyint(1) NOT NULL default '0', `multiple` tinyint(1) NOT NULL default '1', `candisable` tinyint(1) NOT NULL default '0', `removable` tinyint(1) NOT NULL default '0', PRIMARY_KEY(`id`), UNIQUE KEY(`name`) )
This table stores the different authentication types (sources) present in this Moodle installation: internal, none, ldap, db, cas, etc.
Each auth type has to autoregister in this table when it's installed, specifying:
- 'id': the primary key of the record.
- 'name': The name of the autentication type: 'manual', 'none', 'ldap', 'db', etc. There can't be duplicated values in this field.
- 'isinternal' if this auth type is internal to Moodle (1) or not(0), i.e., if it doesn't depend on any external entity to provide authentication. Tipically this is for 'manual', 'email' and 'none'.
- 'multiple': if this auth type supports multiple instances (1) or not (0).
- 'candisable': if this auth type can be temporarily disabled (1) or not (0)
- 'removable': if this auth type can be removed from the system (1) or not (0).
If we decide that 'manual', 'none' and/or 'email' are special authentication types and are handled separately form the rest, then this last field can be removed.
BIG QUESTION HERE: Can 'manual' be disabled? I'm not sure about this, as all the admin users can be locked out of Moodle if we mistakenly disable all the auth types needed for admin users.
BIG QUESTION HERE: Should 'manual' auth type be handled separately from all this multi-auth mess? I guess there are some benefits to it, but I'm not sure about it. For one, it would make the above question irrelevant.
CREATE TABLE `prefix_auth_instance` ( `id` integer(10) NOT NULL auto_increment, `typeid` integer(10) NOT NULL default '0', `name` varchar(20) NOT NULL default '', `description` varchar(50) NOT NULL default '', `sortorder` integer(10) NOT NULL default '0', `enabled` tinyint(1) NOT NULL default '1', PRIMARY_KEY(`id`), UNIQUE KEY(`name`) )
This table stores the different auth instances available for each auth type. It's managed from the authentication setup page, using the add/modify/delete functionality available there. We can also specify the order in which we want to use each auth-instance when authenticating users.
The meaning of the fields are:
- 'id': the primary key of the record. We will put this value into the 'auth' field in prefix_user table when we correctly authenticate a user using this auth instance (to later track where to update values from, where to check for password expiration, etc.)
- 'typeid': the auth type id of this instance. It's a foreign key into the 'type' field of auth_type table. We need this to check if there is already an instance of a given auth type, in case that auth type doesn't allow for multiple instances.
- 'name': the name of this instance. It's the text shown in the authentication setup page to refer to this instance.
- 'description': a short description text for this instance (e.g., 'UK Students LDAP server').
- 'sortorder': the order in which we use each auth instance when trying to authenticate users.
- 'enabled': if this instance is enabled (1) or not (0).
BIG QUESTION HERE: If we use 'id' to fill in the 'auth' field in prefix_user, then we should only use 'sortorder' when the user has that field empty (i.e., we don't know where to authenticate this user so far). Otherwise we could directly authenticate with the known auth-instance. But this prevents users from "moving" between authentication instances (i.e, this user "was" in our UK student's LDAP server, but now "is" in our US staff database server). Is this good or bad?
ANSWER TO BIG QUESTION: After talking with Martin Langhoff at MoodleMoot Spain '06, this is clearly a Bad(tm) thing. If we allow users to "float" between authentication instances, things like auth_ldap_sync_users.php could break havoc, deleting users it doesn't know about in this auth_instance (but perfectly valid in other auth_instance's). So storing the auth_instance 'id' in prefix_user and using it accordingly is The Right Thing(tm).
CREATE TABLE `prefix_auth_instance_settings` ( `id` integer(10) NOT NULL auto_increment, `instanceid` integer(10) NOT NULL default '0', `name` varchar(255) NOT NULL default '', `value` text NOT NULL PRIMARY_KEY(`id`), UNIQUE KEY `instancesetting` (`instanceid`,`name`) )
This table stores each auth instance configuration settings.
- 'id': the primary key for the record.
- 'instanceid': foreign key into the 'id' field of auth_instance table.
- 'name': name of the setting.
- 'value': value for that setting.
There can't be two (or more) identical 'name' values for the same 'instanceid'.
Some additional questions before starting to code all this mess
- If we store the 'prefix_auth_intance.id' value in the 'prefix_user.auth' field as suggested above, what should we do when we remove that auth instance from our system? Should we allow removal if any users are using that instance? Should we move those users to the default auth instance (internal)? Should we choose a new auth instance for those users as part of the removal? Or should we just ignore the 'prefix_user.auth' field during login and just proceed through the whole loop and try to find which new auth instance allows the user to login (if any)?
- Multiple instances login: If we use multiple Moodle instances, from my point it means that a user can have access to several instances. So it will be a good idea to think about a kind of Moodle portal that shows all the instances a user can access.
- I hadn't thought about this when posting the original questions, because I was thinking about one Moodle site and multiple authentication sources (our problem at the moment), but with Moodle Network around the corner, this is a real issue. Well thought out Hélène :-) -- Iñaki Arenaza 07:56, 22 November 2006 (CST)