Repository navigation
Infinite loop when there is more than one LDAP entry for a user in file sharing #6986
Description
Context
A organization uses Nextcloud with LDAP backend.
Some employees of that organization work for two departments.
Organization keeps one entry for each employee in each department.
So, there are more than a entry for a same employee into LDAP backend.
Steps to reproduce
- Create two entries for same user in a LDAP where beyond of uid only description and one of occurrences of OU are different.
- Access Nextcloud as admin user.
- Share one file with that duplicated user.
- Get out from Nextcloud.
- Log in again as admin.
- Click on link "Shared" of file mentioned in step 3.
Expected behaviour
Right frame shows sharings of file.
Actual behaviour
Right frame does not show sharings of file.
Server configuration
Operating system: Debian 8
Web server: Apache 2.4
Database: Postgresql 9.4
PHP version: php 5.6
Nextcloud version: 12.0.3
Updated from an older Nextcloud/ownCloud or fresh install: Fresh install
Where did you install Nextcloud from: https://download.nextcloud.com/server/releases
Signing status: No errors have been found.
Are you using external storage, if yes which one: no
Are you using encryption: no
Are you using an external user-backend, if yes which one: LDAP
Solution proposal
Method OCA\User_LDAP\User_LDAP->getLDAPUserByLoginName calls method OCA\User_LDAP\Access->fetchUsersByLoginName. This last calls method fetchListOfUsers without limit parameter.
See that method getLDAPUserByLoginName assumes that result must be only one record so returns $users[0]. So, I believe that class Access must return only one record too.
If method User_LDAP->fetchListOfUsers receives third parameter ($limit) as 1, the problem is solved.
So, I think that there is some ways to implement that and I would like to know which of them can be submitted as a change.
1) Create a new method and change another one
1.1) Create method fetchUserByLoginName in class Access. It is almost equals to fetchUsersByLoginName, except to detail of third parameter passed to method fetchListOfUsers.
public function fetchUserByLoginName($loginName, $attributes = array('dn')) {
$loginName = $this->escapeFilterPart($loginName);
$filter = str_replace('%uid', $loginName, $this->connection->ldapLoginFilter);
$users = $this->fetchListOfUsers($filter, $attributes, 1); // SEE HERE
return $users;
}1.2) Change method getLDAPUserByLoginName of class User_LDAP
public function getLDAPUserByLoginName($loginName) {
//find out dn of the user name
$attrs = $this->access->userManager->getAttributes();
$users = $this->access->fetchUserByLoginName($loginName, $attrs); // SEE HERE
if(count($users) < 1) {
throw new NotOnLDAP('No user available for the given login name on ' .
$this->access->connection->ldapHost . ':' . $this->access->connection->ldapPort);
}
return $users[0];
}2) Change two existent methods
2.1) Change method fetchUsersByLoginName of class Access. It is almost equals to fetchUsersByLoginName, except to detail of third parameter passed to method fetchListOfUsers.
public function fetchUsersByLoginName($loginName, $attributes = array('dn'), $limit = null) {// SEE HERE
$loginName = $this->escapeFilterPart($loginName);
$filter = str_replace('%uid', $loginName, $this->connection->ldapLoginFilter);
$users = $this->fetchListOfUsers($filter, $attributes, $limit); // SEE HERE
return $users;
}2.2) Change method getLDAPUserByLoginName of class User_LDAP
public function getLDAPUserByLoginName($loginName) {
//find out dn of the user name
$attrs = $this->access->userManager->getAttributes();
$users = $this->access->fetchUsersByLoginName($loginName, $attrs, 1); // SEE HERE
if(count($users) < 1) {
throw new NotOnLDAP('No user available for the given login name on ' .
$this->access->connection->ldapHost . ':' . $this->access->connection->ldapPort);
}
return $users[0];
}3) Change two existent methods and create a configuration
3.1) Change method fetchUsersByLoginName of class Access. It is almost equals to fetchUsersByLoginName, except to detail of third parameter passed to method fetchListOfUsers.
public function fetchUsersByLoginName($loginName, $attributes = array('dn'), $limit = null) {// SEE HERE
$loginName = $this->escapeFilterPart($loginName);
$filter = str_replace('%uid', $loginName, $this->connection->ldapLoginFilter);
$users = $this->fetchListOfUsers($filter, $attributes, $limit); // SEE HERE
return $users;
}3.2) Change method getLDAPUserByLoginName of class User_LDAP
public function getLDAPUserByLoginName($loginName) {
//find out dn of the user name
$attrs = $this->access->userManager->getAttributes();
$users = $this->access->fetchUsersByLoginName($loginName, $attrs, \OC::$server->getConfig()->getSystemValue('ldap_user_by_login_name_limit', null); // SEE HERE
if(count($users) < 1) {
throw new NotOnLDAP('No user available for the given login name on ' .
$this->access->connection->ldapHost . ':' . $this->access->connection->ldapPort);
}
return $users[0];
}3.3) Add item in config.php
\\ docblock...
$CONFIG = array(
\\ many lines...
'ldap_user_by_login_name_limit'
);I suggest first way.
Activity
MorrisJobke commentedon Dec 14, 2017
cc @nextcloud/ldap
blizzz commentedon Dec 14, 2017
@fgsl thanks for the report, investigatio and suggestions!
This is probably also related to #7445, no reason to call
fetchUsersByLoginNamesince we save the userid.Need to check again, I believe to remember that we have a check somewhere (probably Config wizard) were we check whether more than one result is returned.
blizzz commentedon Dec 28, 2017
@fgsl can you try whether it works with #7611 ?
fgsl commentedon Dec 28, 2017
@blizzz, I will try that change and give a feedback. Thank you.
fgsl commentedon Jan 3, 2018
@blizzz, code from #7611 solves this issue! Thanks!
blizzz commentedon Jan 3, 2018
@fgsl great, thanks for testing!
MorrisJobke commentedon Jan 3, 2018
Fixed by #7611