-
Notifications
You must be signed in to change notification settings - Fork 134
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Existing user account not used when user has multiple Moodle accounts with same email address #790
base: MOODLE_39_STABLE
Are you sure you want to change the base?
Conversation
…accounts with same email address This fixes a bug that occured when a users tried to login using SAML2. The conditions are: - User has multiple Moodle accounts with the same email address (or other mapped idP field attributes that are being used to find and login the user in Moodle). The condition was count($records == 1) so a user was being found only when there was exactly 1 user account found. This would make the hole reset() call on the next line redundant because there would always be exactly 0 or 1 records... So I think this needs to be count($records) > 0 so every scenario where the sql query returns multiple users from the Moodle database, the forst one will always be used.
I'm leaning towards objecting towards this change... If the system has 2 user accounts for the same user - arbitrarily "choosing" one to use is IMO the wrong approach. Can you provide a bit more information here on the reason your site has 2 active accounts with the same email? - is it an accidental duplication (which IMO should be fixed manually rather than hiding it in auth_saml2) - or is there some other case for multiple accounts with the same email? |
Hi Dan Thank you for your quick response. I Agree that arbitrarily choosing the first account from the list of records is not ideal. This however was already the logic in your plugin (the line 88) but was never very relevant due to the condition always resulting in only 1 record. Some context on our case: I hope this provides some better insights on my thoughts leading to this PR. Thanks for looking into this. |
The way I read that existing code is - get all the user records that match, If we get more than 1 record - something went wrong and we can't match the user so don't let them login. - the reset call just simplifies the array returned into a single record so it can be used in the API call below it. There are probably other ways that the same code could be written but the end result is the same - if we get more than 1 user in the response, we haven't got a unique indentifier so don't log the user in. My opinion is that existing code provides correct behavior and my vote is to decline this change. If we can't match a unique user with a unique identifier, the correct process should be to not let the user login. But I'm happy for others to pitch in and disagree and try to convince me otherwise! :-) |
Before I read this issue I came up with this same scenario and I agree this is valid. What I think is the better middle ground is if the get_user function looks for users in 2 passes:
If anyauth is off then the second step would not run. If the first step finds two saml2 users which match then that should still be an error. So I think we need to move the 'anyauth' out from the saml_login_complete into the user_extractor::get_user function |
Took me a bit to understand what Brendan was suggesting as an improvement there... (thanks Brendan) If the user has 2 accounts - eg one account with the auth column in their record set to "saml2" and one account with the auth method set to "manual" and they both have the same email - it should choose the saml one and let the user login. However - if the user has multiple accounts with the auth method set to "email" or "oauth" or something else - it should just recognise that there are multiple accounts that it can't match, preventing the user from being able to login. So we should modify the code like he suggests.. First look to see if we can find one user account with auth = "saml2" that matches the email - if we find one record we use it. (if we find multiple saml2 accounts with that email we prevent login). Then - after the initial search for auth_saml2 accounts, if "anyauth" is enabled, we use similar code to what's there right now - get all users that match the email, if we find one record, log them in, if we find more than one, don't let them login. Does that make sense and would it meet your needs? - do you think you could modify the pull request to do something similar? |
Hi @danmarsden and @brendanheywood Thank you for all the thorough answers and critique. I agree that my current pull-request is not sufficient enough and could use some improvements. I made it too quick looking at it now. I will create a new improved pull request with your suggestions. However due to my limited time the coming weeks it will take some time to complete and update this PR. |
This fixes a bug that ocured when a users tried to login using SAML2. The conditions are:
The condition was count($records == 1) so a user was being found only when there was exactly 1 user account found. This would make the whole reset() call on the next line redundant because there would always be exactly 0 or 1 records...
So I think this needs to be
if (count($records) > 0) {
so every scenario where the sql query returns multiple users from the Moodle database, the first one will always be used.