How can I implement the logging in via USERNAME or EMAIL?
General developer forum
I've done that before, but it wasn't pretty. We did it by keeping the username and the email address matching rather than trying to change the core login code.
To do this we used a custom auth plug-in to handle creating new users, and profile edits so that every time the email address was changed it would change the username at the same time. And we had our own login screen, though I don't think that's essential.
If any-one has better ideas for how to do this, I'd love to hear them!
I've had to do this before (we were integrating with another system that used the email address as the login) and we did exactly the same as you. Force usernames to be the same as email addresses.
Having said that, as long as you are prepared to write a custom plugin (in Moodle 2 it's fairly easy to sub-class an existing plugin and just change the bits that matter) the actual bit of code that says YES/NO to the login is fairly simple. You only need to change that to make an additional check for the email address matching.
My only remaining concern is that (last time I looked) Moodle does not actively enforce unique emails. So you might want to modify the field to make it a unique index.
Howard, would it not be a trivial matter to make the email field in the User table a unique to ensure no duplicates allowed? What would that do to the data entry times in Moodles with a larger User base?
In theory any additional index will increase the write times to the table, but even on very large sites the user table isn't that big in the great scheme of things.
The remaining issue is that some operations might fail unpleasantly due to the lack of checks for duplicate emails. A small price to pay I suspect.
Yes you could easily do that at the database layer and I doubt it would have a significant performance implication (though I am not a performance expert, so you may wish to test).
You might get some unhelpful error messages if people edited/created user records so that they broke the database uniqueness restriction though unless you also go through the forms to add validation for that.
I'm not sure if you can do that without customising core Moodle though. So far everything Howard and I suggested could be done with a plug-in, which will be much easier for you to maintain through future Moodle upgrades.
Then it would seem that Moodle devs relied upon the idea that all emails must, of necessity, be unique. However, what then prevents users from sharing a single email address? mmm A properly ordered database and a single function would then provide a workaround for that issue? Should this be a Moodle Tracker item? A potential security issue perhaps?
Hello! Thanks for your replies.
I was able to implement the logging in using email or username already. Yey!
Of course, I made both the email and username unique first. I altered the edit_form.php's validation function to make them unique.
And then, I hacked the function authenticate_user_login in moodlelib.php
I added something like:
- check username and pw if existing and correct
- if match, log in.
- if no match, check email and pw if existing and correct...
- if match, log in.
- if no match, log in failure
Basically, I only added a little tweak in moodlelib.php the others are just functions to make sure that the email is always unique.
Forcing the email field to be unique shouldn't require much database overhead at all, at least in MySQL. All you'd need is a UNIQUE HASH index on the 'email' field. You'd need to catch the insert failure at the front-end, but that's simple too.
It's probably worth noting that, in the mdl_course table, shortname isn't required to be unique. It's enforced at the front-end, but there's nothing at the database level to prevent duplicated. Should you end up with duplicate shortnames (and you use the shortname to apply enrolments), all hell can break loose. It's an amateur mistake, but it's one I've made before.
I wrote the attached mod to the authenticate_user_login function in lib/moodlelib.php. If the supplied $username matches an email address in the mdl_user table, it makes a log entry and switches the $username variable to the value of the username field in the matched user record. It is very simple, and I've already thought of a couple problems others may have with it.
1. If e-mail addresses are not unique on your system, the wrong user may be selected and login will fail (unless the users also have the same password, in which case the user will log in to the wrong account).
2. If you authenticate against an external database or LDAP or similar method and rely on Moodle to create the account when the user logs in the first time, this mod will not help you for that initial login as the user is not yet in the mdl_user table. I run the sync_users.php program every time my external database changes, so this is not an issue for me.
3. I don't use mnet and have no idea how it works. This probably won't work for mnet users.
Patch was written with version 2.5.1+ (Build: 20130802).
1. From the page you linked:
a lot of interesting stuff happens in authenticate_user_login().
2. It looks up the username in the mdl_user table to see if they are allowed to log in, and which authentication plugin handles their login requests. (This will be the plugin that handled their first-ever login request.)
I want my users to be able to use either their username or their e-mail address when they log in. An authentication plugin won't help with this because the logic that needs "fixed" is in the core code.
2. While it's true that the program won't allow you to use an e-mail address that is already in use, that doesn't mean it can't be changed in the database. The e-mail field is not a unique field in my MySQL database.
In the default situation people can log in using their username.
So 50% of your requirement is already covered.
The other 50% is that if they do no use their username, but their email instead, they still should be able to log in.
So if it doesn't exists yet, you'd need to write a auth plugin that accepts the email address of a user and based on that checks against the password.
Because the auth plugins work via a failover/waterfall method; as long as one auth plugin does not authenticate the user the next auth plugin in line will be called, this will result in users begin able to either use their username or email to log in.
If there is a chance of email duplication (I seem to recall Moodle code really doesn't like that), you could make sure that in that case people or the admin get a warning.
I spent this afternoon trying to write the plugin you suggest.
When Moodle successfully authenticates a user during the failover/waterfall portion of authenticate_user_login() after not finding the username in the user table, it attempts to create a new account. The user already has an account, so it will likely fail because of duplicate users (or worse...it will actually create a new account and the user now has two!).
If you enable $CFG->authpreventaccountcreation to try to stop this behavior, it never gets to the failover/waterfall routine.