aboutsummaryrefslogtreecommitdiffstats
path: root/apps/user_ldap/lib
diff options
context:
space:
mode:
Diffstat (limited to 'apps/user_ldap/lib')
-rw-r--r--apps/user_ldap/lib/access.php123
-rw-r--r--apps/user_ldap/lib/connection.php6
2 files changed, 105 insertions, 24 deletions
diff --git a/apps/user_ldap/lib/access.php b/apps/user_ldap/lib/access.php
index 68cbe4a5e75..4aa8ae8e8a4 100644
--- a/apps/user_ldap/lib/access.php
+++ b/apps/user_ldap/lib/access.php
@@ -4,7 +4,7 @@
* ownCloud – LDAP Access
*
* @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
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
@@ -57,8 +57,8 @@ abstract class Access {
\OCP\Util::writeLog('user_ldap', 'LDAP resource not available.', \OCP\Util::DEBUG);
return false;
}
- $rr = @ldap_read($cr, $dn, $filter, array($attr));
$dn = $this->DNasBaseParameter($dn);
+ $rr = @ldap_read($cr, $dn, $filter, array($attr));
if(!is_resource($rr)) {
\OCP\Util::writeLog('user_ldap', 'readAttribute failed for DN '.$dn, \OCP\Util::DEBUG);
//in case an error occurs , e.g. object does not exist
@@ -293,6 +293,10 @@ abstract class Access {
$query->execute(array($dn, $uuid));
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)) {
@@ -303,21 +307,24 @@ abstract class Access {
}
$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
- if(($isUser && !\OCP\User::userExists($ldapname, 'OCA\\user_ldap\\USER_LDAP')) || (!$isUser && !\OC_Group::groupExists($ldapname))) {
- if($this->mapComponent($dn, $ldapname, $isUser)) {
- return $ldapname;
+ //disabling Cache is required to avoid that the new user is cached as not-existing in fooExists check
+ $originalTTL = $this->connection->ldapCacheTTL;
+ $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.
- $oc_name = $this->alternateOwnCloudName($ldapname, $dn);
- if(($isUser && !\OCP\User::userExists($oc_name)) || (!$isUser && !\OC_Group::groupExists($oc_name))) {
- if($this->mapComponent($dn, $oc_name, $isUser)) {
- return $oc_name;
- }
+ $altname = $this->createAltInternalOwnCloudName($intname, $isUser);
+ if($this->mapComponent($dn, $altname, $isUser)) {
+ return $altname;
}
//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 $dn the dn of the object
- * @returns string with with the name to use in ownCloud
+ * @returns string with with the name to use in ownCloud or false if unsuccessful
*
- * 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) {
- $ufn = ldap_dn2ufn($dn);
- $name = $name . '@' . trim(\OCP\Util::mb_substr_replace($ufn, '', 0, mb_strpos($ufn, ',', 0, 'UTF-8'), 'UTF-8'));
- $name = $this->sanitizeUsername($name);
- return $name;
+ private function _createAltInternalOwnCloudNameForUsers($name) {
+ $attempts = 0;
+ //while loop is just a precaution. If a name is not generated within
+ //20 attempts, something else is very wrong. Avoids infinite loop.
+ 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;
}
/**
diff --git a/apps/user_ldap/lib/connection.php b/apps/user_ldap/lib/connection.php
index 933f2f42074..0bf2efe35af 100644
--- a/apps/user_ldap/lib/connection.php
+++ b/apps/user_ldap/lib/connection.php
@@ -192,7 +192,7 @@ class Connection {
private function getValue($varname) {
static $defaults;
- if(is_null($defaults)){
+ if(is_null($defaults)) {
$defaults = $this->getDefaults();
}
return \OCP\Config::getAppValue($this->configID,
@@ -235,7 +235,7 @@ class Connection {
$this->config['turnOffCertCheck']
= $this->$v('ldap_turn_off_cert_check');
$this->config['ldapUserDisplayName']
- = mb_strtolower($this->$v('ldap_display_name'),'UTF-8');
+ = mb_strtolower($this->$v('ldap_display_name'), 'UTF-8');
$this->config['ldapUserFilter']
= $this->$v('ldap_userlist_filter');
$this->config['ldapGroupFilter'] = $this->$v('ldap_group_filter');
@@ -336,7 +336,7 @@ class Connection {
case 'ldapBaseGroups':
case 'ldapAttributesForUserSearch':
case 'ldapAttributesForGroupSearch':
- if(is_array($value)){
+ if(is_array($value)) {
$value = implode("\n", $value);
}
break;