Merge pull request #1604 from owncloud/fix_ldap_internalname_generation
Improve generation of interal user names resp. group display names
This commit is contained in:
commit
b6ee118841
|
@ -4,7 +4,7 @@
|
||||||
* ownCloud – LDAP Access
|
* ownCloud – LDAP Access
|
||||||
*
|
*
|
||||||
* @author Arthur Schiwon
|
* @author Arthur Schiwon
|
||||||
* @copyright 2012 Arthur Schiwon blizzz@owncloud.com
|
* @copyright 2012, 2013 Arthur Schiwon blizzz@owncloud.com
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
@ -293,6 +293,10 @@ abstract class Access {
|
||||||
$query->execute(array($dn, $uuid));
|
$query->execute(array($dn, $uuid));
|
||||||
return $component;
|
return $component;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
//If the UUID can't be detected something is foul.
|
||||||
|
\OCP\Util::writeLog('user_ldap', 'Cannot determine UUID for '.$dn.'. Skipping.', \OCP\Util::INFO);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_null($ldapname)) {
|
if(is_null($ldapname)) {
|
||||||
|
@ -303,21 +307,24 @@ abstract class Access {
|
||||||
}
|
}
|
||||||
$ldapname = $ldapname[0];
|
$ldapname = $ldapname[0];
|
||||||
}
|
}
|
||||||
$ldapname = $this->sanitizeUsername($ldapname);
|
$intname = $isUser ? $this->sanitizeUsername($uuid) : $this->sanitizeUsername($ldapname);
|
||||||
|
|
||||||
//a new user/group! Add it only if it doesn't conflict with other backend's users or existing groups
|
//a new user/group! Add it only if it doesn't conflict with other backend's users or existing groups
|
||||||
if(($isUser && !\OCP\User::userExists($ldapname, 'OCA\\user_ldap\\USER_LDAP')) || (!$isUser && !\OC_Group::groupExists($ldapname))) {
|
//disabling Cache is required to avoid that the new user is cached as not-existing in fooExists check
|
||||||
if($this->mapComponent($dn, $ldapname, $isUser)) {
|
$originalTTL = $this->connection->ldapCacheTTL;
|
||||||
return $ldapname;
|
$this->connection->setConfiguration(array('ldapCacheTTL' => 0));
|
||||||
|
if(($isUser && !\OCP\User::userExists($intname))
|
||||||
|
|| (!$isUser && !\OC_Group::groupExists($intname))) {
|
||||||
|
if($this->mapComponent($dn, $intname, $isUser)) {
|
||||||
|
$this->connection->setConfiguration(array('ldapCacheTTL' => $originalTTL));
|
||||||
|
return $intname;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$this->connection->setConfiguration(array('ldapCacheTTL' => $originalTTL));
|
||||||
|
|
||||||
//doh! There is a conflict. We need to distinguish between users/groups. Adding indexes is an idea, but not much of a help for the user. The DN is ugly, but for now the only reasonable way. But we transform it to a readable format and remove the first part to only give the path where this object is located.
|
$altname = $this->createAltInternalOwnCloudName($intname, $isUser);
|
||||||
$oc_name = $this->alternateOwnCloudName($ldapname, $dn);
|
if($this->mapComponent($dn, $altname, $isUser)) {
|
||||||
if(($isUser && !\OCP\User::userExists($oc_name)) || (!$isUser && !\OC_Group::groupExists($oc_name))) {
|
return $altname;
|
||||||
if($this->mapComponent($dn, $oc_name, $isUser)) {
|
|
||||||
return $oc_name;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//if everything else did not help..
|
//if everything else did not help..
|
||||||
|
@ -400,18 +407,92 @@ abstract class Access {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief creates a hopefully unique name for owncloud based on the display name and the dn of the LDAP object
|
* @brief creates a unique name for internal ownCloud use for users. Don't call it directly.
|
||||||
* @param $name the display name of the object
|
* @param $name the display name of the object
|
||||||
* @param $dn the dn of the object
|
* @returns string with with the name to use in ownCloud or false if unsuccessful
|
||||||
* @returns string with with the name to use in ownCloud
|
|
||||||
*
|
*
|
||||||
* creates a hopefully unique name for owncloud based on the display name and the dn of the LDAP object
|
* Instead of using this method directly, call
|
||||||
|
* createAltInternalOwnCloudName($name, true)
|
||||||
*/
|
*/
|
||||||
private function alternateOwnCloudName($name, $dn) {
|
private function _createAltInternalOwnCloudNameForUsers($name) {
|
||||||
$ufn = ldap_dn2ufn($dn);
|
$attempts = 0;
|
||||||
$name = $name . '@' . trim(\OCP\Util::mb_substr_replace($ufn, '', 0, mb_strpos($ufn, ',', 0, 'UTF-8'), 'UTF-8'));
|
//while loop is just a precaution. If a name is not generated within
|
||||||
$name = $this->sanitizeUsername($name);
|
//20 attempts, something else is very wrong. Avoids infinite loop.
|
||||||
return $name;
|
while($attempts < 20){
|
||||||
|
$altName = $name . '_' . uniqid();
|
||||||
|
if(\OCP\User::userExists($altName)) {
|
||||||
|
return $altName;
|
||||||
|
}
|
||||||
|
$attempts++;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief creates a unique name for internal ownCloud use for groups. Don't call it directly.
|
||||||
|
* @param $name the display name of the object
|
||||||
|
* @returns string with with the name to use in ownCloud or false if unsuccessful.
|
||||||
|
*
|
||||||
|
* Instead of using this method directly, call
|
||||||
|
* createAltInternalOwnCloudName($name, false)
|
||||||
|
*
|
||||||
|
* Group names are also used as display names, so we do a sequential
|
||||||
|
* numbering, e.g. Developers_42 when there are 41 other groups called
|
||||||
|
* "Developers"
|
||||||
|
*/
|
||||||
|
private function _createAltInternalOwnCloudNameForGroups($name) {
|
||||||
|
$query = \OCP\DB::prepare('
|
||||||
|
SELECT `owncloud_name`
|
||||||
|
FROM `'.$this->getMapTable(false).'`
|
||||||
|
WHERE `owncloud_name` LIKE ?
|
||||||
|
');
|
||||||
|
|
||||||
|
$usedNames = array();
|
||||||
|
$res = $query->execute(array($name.'_%'));
|
||||||
|
while($row = $res->fetchRow()) {
|
||||||
|
$usedNames[] = $row['owncloud_name'];
|
||||||
|
}
|
||||||
|
if(!($usedNames) || count($usedNames) == 0) {
|
||||||
|
$lastNo = 1; //will become name_2
|
||||||
|
} else {
|
||||||
|
natsort($usedNames);
|
||||||
|
$lastname = array_pop($usedNames);
|
||||||
|
$lastNo = intval(substr($lastname, strrpos($lastname, '_') + 1));
|
||||||
|
}
|
||||||
|
$altName = $name.'_'.strval($lastNo+1);
|
||||||
|
unset($usedNames);
|
||||||
|
|
||||||
|
$attempts = 1;
|
||||||
|
while($attempts < 21){
|
||||||
|
//Pro forma check to be really sure it is unique
|
||||||
|
//while loop is just a precaution. If a name is not generated within
|
||||||
|
//20 attempts, something else is very wrong. Avoids infinite loop.
|
||||||
|
if(!\OC_Group::groupExists($altName)) {
|
||||||
|
return $altName;
|
||||||
|
}
|
||||||
|
$altName = $name . '_' . $lastNo + $attempts;
|
||||||
|
$attempts++;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief creates a unique name for internal ownCloud use.
|
||||||
|
* @param $name the display name of the object
|
||||||
|
* @param $isUser boolean, whether name should be created for a user (true) or a group (false)
|
||||||
|
* @returns string with with the name to use in ownCloud or false if unsuccessful
|
||||||
|
*/
|
||||||
|
private function createAltInternalOwnCloudName($name, $isUser) {
|
||||||
|
$originalTTL = $this->connection->ldapCacheTTL;
|
||||||
|
$this->connection->setConfiguration(array('ldapCacheTTL' => 0));
|
||||||
|
if($isUser) {
|
||||||
|
$altName = $this->_createAltInternalOwnCloudNameForUsers($name);
|
||||||
|
} else {
|
||||||
|
$altName = $this->_createAltInternalOwnCloudNameForGroups($name);
|
||||||
|
}
|
||||||
|
$this->connection->setConfiguration(array('ldapCacheTTL' => $originalTTL));
|
||||||
|
|
||||||
|
return $altName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue