-
-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Modify user_ldap checkPassword to not fetch records from ldap each time because of extremely high CPU usage! #35867
Modify user_ldap checkPassword to not fetch records from ldap each time because of extremely high CPU usage! #35867
Conversation
Hello, thanks for looking into this!
This means that the new users will not be able to login until cache expires, which may lead to worse user experience on some setups.
Same thing here, forcing attributes update from LDAP on login is most likely to improve user experience and avoid having to wait on background job to see a change applied in Nextcloud. So, I think it was on purpose that cache is not used in checkPassword. That said, it’s of course a big problem if that gets triggered on each request for DAV requests in some cases. We should try to see if we can find a middle ground here, maybe look into cache but if user does not exist, force an LDAP search? @blizzz Thoughts? |
This is fine imo(new users will be able to login) as the function
This is true for sure; my only counter-point is that the cache usually does reset much quicker than the background job run time(especially with lots of users) so the user is fetched from LDAP much more frequently than the bg job(just not everytime). Otherwise, maybe we could even set a config value in
This is already done, please see my point about the
For me its okay to update once on every cache reset but if other users want the update every time, we can use a config option for this as mentioned above. |
No, if the user does not exists server/apps/user_ldap/lib/User_LDAP.php Line 138 in 7ee61dd
On the next call if server/apps/user_ldap/lib/User_LDAP.php Lines 121 to 123 in 7ee61dd
|
Fair point. My bad, didn't notice the strict comparison against null. I try to see how we can achieve correct behaviour where we fetch if not cached. But also, this seems like an edge case(an important one maybe?) to me. How often can we expect users to try login with a non-existent username and then a new user with that same username is added within the cache timeout time? |
@come-nc What about something like: public function loginName2UserName($loginName, bool $overrideCacheIfFalse = false) {
$cacheKey = 'loginName2UserName-' . $loginName;
$username = $this->access->connection->getFromCache($cacheKey);
$overrideCache = $overrideCacheIfFalse && $username === false;
if ($username !== null && !$overrideCache) {
return $username;
}
....
} And then: public function checkPassword($uid, $password) {
$username = $this->loginName2UserName($uid, true);
... |
@come-nc @blizzz @icewind1991 Anything? Please comment if possible if it is okay overall(does not break authentication) so I can test on our servers to see if load goes down a lot by this.. Thanks a lot :) |
Yes it looks good enough that you can test it. |
Mh, Attributes are not processed i.e. not updated anymore now on login despite no cache hit. It will be done only for newly mapped users. Unless I oversaw something? |
server/apps/user_ldap/lib/User_LDAP.php Line 126 in 5c4b4bd
Looks like I am mistaken.. Seems like over here, an empty array is sent even after cache invalidation. server/apps/user_ldap/lib/Access.php Line 881 in 5c4b4bd
You are right, let me see how this can be handled. |
@blizzz Handled now. Please check. |
@blizzz Seems like I removed reviewers by mistake and am unable to re-add :/ Please do re-add @come-nc and @icewind1991 when possible |
@come-nc @blizzz @icewind1991 It seems good on test servers. Do you think it's okay to put into production as it is currently as server load is crazy high.. |
0f73108
to
49f3fa8
Compare
Nice PR! Let's see that we get it added to 31 🚀 |
@sorbaugh Do you need anything from my side to make the merge? |
@akhil1508 if possible, could you fix the ldap test failure in
|
@skjnldsv Yes please. It doesn't seem like my changes should break unit tests. Is it maybe related to being up to date with master? Should I merge master into the branch again? |
@akhil1508 could you enable us to make modifications to this branch? If possible avoid merging master into this branch, it's preferable if you rebase instead (to avoid creating a merge commit) :) |
@skjnldsv Is it OK if I add a new PR from a personal fork? Organization forks don't allow maintainer modifications https://github.com/orgs/community/discussions/5634 |
Oh! I didn't know that :) |
b33e884
to
2c85165
Compare
Signed-off-by: Akhil <akhil@e.email>
ddbe21b
to
b1230cd
Compare
@skjnldsv Rebased and also attempted to fix the unit test |
Amazing! Looks good! I approved the tests, let's see if they pass 🤞 |
|
Thank you for your patience and commitment @akhil1508 !! 🎉 🎉 |
And thanks to you too! :) |
Summary
Currently on each
checkPassword
call, the functiongetLDAPUserByLoginName
is calledThis calls
fetchListOfUsers
which is defined hereSo on each authentication request:
batchApplyUserAttributes
DAV mobile clients(for example DAVx5) don't support token auth or oauth yet. This means that they pass the username and password on every single sync request
We have an NC instance serving around 100 DAV sync requests every second
For every sync request the LDAP logs look like(admin bind + search for user):
Proposed solution here
$user->processAttributes
here seems redundant as it is already done during thegetLDAPUserByLoginName
function callUNBIND
happens in the destructor of theConnection
class so pretty sure it is done only after all these SQL commands are completed, which means the LDAP bind stays open till thenPlease do let me know if there are any pitfalls to this and if the ldap record fetching and processing on every single authentication request happens for an unavoidable reason I am not aware of..
Checklist