Merge pull request #5114 from owncloud/ldap_uuid_attr_groups

LDAP: allow different UUID attributes for groups and users
This commit is contained in:
blizzz 2013-10-10 03:27:28 -07:00
commit 666e52a46b
6 changed files with 106 additions and 151 deletions

View file

@ -1,20 +1,5 @@
<?php
//from version 0.1 to 0.2
//ATTENTION
//Upgrade from ownCloud 3 (LDAP backend 0.1) to ownCloud 4.5 (LDAP backend 0.3) is not supported!!
//You must do upgrade to ownCloud 4.0 first!
//The upgrade stuff in the section from 0.1 to 0.2 is just to minimize the bad effects.
//settings
$pw = OCP\Config::getAppValue('user_ldap', 'ldap_password');
if(!is_null($pw)) {
$pwEnc = base64_encode($pw);
OCP\Config::setAppValue('user_ldap', 'ldap_agent_password', $pwEnc);
OC_Appconfig::deleteKey('user_ldap', 'ldap_password');
}
//detect if we can switch on naming guidelines. We won't do it on conflicts.
//it's a bit spaghetti, but hey.
$state = OCP\Config::getSystemValue('ldapIgnoreNamingRules', 'unset');
@ -22,75 +7,21 @@ if($state === 'unset') {
OCP\Config::setSystemValue('ldapIgnoreNamingRules', false);
}
//from version 0.2 to 0.3 (0.2.0.x dev version)
$objects = array('user', 'group');
$configPrefixes = OCA\user_ldap\lib\Helper::getServerConfigurationPrefixes(true);
$ldap = new OCA\user_ldap\lib\LDAP();
foreach($configPrefixes as $config) {
$connection = new OCA\user_ldap\lib\Connection($ldap, $config);
$value = \OCP\Config::getAppValue('user_ldap',
$config.'ldap_uuid_attribute', 'auto');
\OCP\Config::setAppValue('user_ldap',
$config.'ldap_uuid_user_attribute', $value);
\OCP\Config::setAppValue('user_ldap',
$config.'ldap_uuid_group_attribute', $value);
$connector = new \OCA\user_ldap\lib\Connection();
$userBE = new \OCA\user_ldap\USER_LDAP();
$userBE->setConnector($connector);
$groupBE = new \OCA\user_ldap\GROUP_LDAP();
$groupBE->setConnector($connector);
foreach($objects as $object) {
$fetchDNSql = '
SELECT `ldap_dn`, `owncloud_name`, `directory_uuid`
FROM `*PREFIX*ldap_'.$object.'_mapping`';
$updateSql = '
UPDATE `*PREFIX*ldap_'.$object.'_mapping`
SET `ldap_DN` = ?, `directory_uuid` = ?
WHERE `ldap_dn` = ?';
$query = OCP\DB::prepare($fetchDNSql);
$res = $query->execute();
$DNs = $res->fetchAll();
$updateQuery = OCP\DB::prepare($updateSql);
foreach($DNs as $dn) {
$newDN = escapeDN(mb_strtolower($dn['ldap_dn'], 'UTF-8'));
if(!empty($dn['directory_uuid'])) {
$uuid = $dn['directory_uuid'];
} elseif($object === 'user') {
$uuid = $userBE->getUUID($newDN);
//fix home folder to avoid new ones depending on the configuration
$userBE->getHome($dn['owncloud_name']);
} else {
$uuid = $groupBE->getUUID($newDN);
}
try {
$updateQuery->execute(array($newDN, $uuid, $dn['ldap_dn']));
} catch(Exception $e) {
\OCP\Util::writeLog('user_ldap',
'Could not update '.$object.' '.$dn['ldap_dn'].' in the mappings table. ',
\OCP\Util::WARN);
}
}
$value = \OCP\Config::getAppValue('user_ldap',
$config.'ldap_expert_uuid_attr', 'auto');
\OCP\Config::setAppValue('user_ldap',
$config.'ldap_expert_uuid_user_attr', $value);
\OCP\Config::setAppValue('user_ldap',
$config.'ldap_expert_uuid_group_attr', $value);
}
function escapeDN($dn) {
$aDN = ldap_explode_dn($dn, false);
unset($aDN['count']);
foreach($aDN as $key => $part) {
$value = substr($part, strpos($part, '=')+1);
$escapedValue = strtr($value, Array(','=>'\2c', '='=>'\3d', '+'=>'\2b',
'<'=>'\3c', '>'=>'\3e', ';'=>'\3b', '\\'=>'\5c',
'"'=>'\22', '#'=>'\23'));
$part = str_replace($part, $value, $escapedValue);
}
$dn = implode(',', $aDN);
return $dn;
}
// SUPPORTED UPGRADE FROM Version 0.3 (ownCloud 4.5) to 0.4 (ownCloud 5)
if(!isset($connector)) {
$connector = new \OCA\user_ldap\lib\Connection();
}
//it is required, that connections do have ldap_configuration_active setting stored in the database
$connector->getConfiguration();
$connector->saveConfiguration();
// we don't save it anymore, was a well-meant bad idea. Clean up database.
$query = OC_DB::prepare('DELETE FROM `*PREFIX*preferences` WHERE `appid` = ? AND `configkey` = ?');
$query->execute(array('user_ldap' , 'homedir'));

View file

@ -1 +1 @@
0.4.0
0.4.1

View file

@ -288,7 +288,7 @@ class Access extends LDAPUtility {
}
//second try: get the UUID and check if it is known. Then, update the DN and return the name.
$uuid = $this->getUUID($dn);
$uuid = $this->getUUID($dn, $isUser);
if($uuid) {
$query = \OCP\DB::prepare('
SELECT `owncloud_name`
@ -580,7 +580,9 @@ class Access extends LDAPUtility {
');
//feed the DB
$insRows = $insert->execute(array($dn, $ocname, $this->getUUID($dn), $dn, $ocname));
$insRows = $insert->execute(array($dn, $ocname,
$this->getUUID($dn, $isUser), $dn,
$ocname));
if(\OCP\DB::isError($insRows)) {
return false;
@ -905,55 +907,67 @@ class Access extends LDAPUtility {
* @param $force the detection should be run, even if it is not set to auto
* @returns true on success, false otherwise
*/
private function detectUuidAttribute($dn, $force = false) {
if(($this->connection->ldapUuidAttribute !== 'auto') && !$force) {
private function detectUuidAttribute($dn, $isUser = true, $force = false) {
if($isUser) {
$uuidAttr = 'ldapUuidUserAttribute';
$uuidOverride = $this->connection->ldapExpertUUIDUserAttr;
} else {
$uuidAttr = 'ldapUuidGroupAttribute';
$uuidOverride = $this->connection->ldapExpertUUIDGroupAttr;
}
if(($this->connection->$uuidAttr !== 'auto') && !$force) {
return true;
}
$fixedAttribute = $this->connection->ldapExpertUUIDAttr;
if(!empty($fixedAttribute)) {
$this->connection->ldapUuidAttribute = $fixedAttribute;
if(!empty($uuidOverride) && !$force) {
$this->connection->$uuidAttr = $uuidOverride;
return true;
}
//for now, supported (known) attributes are entryUUID, nsuniqueid, objectGUID
//for now, supported attributes are entryUUID, nsuniqueid, objectGUID
$testAttributes = array('entryuuid', 'nsuniqueid', 'objectguid', 'guid');
foreach($testAttributes as $attribute) {
\OCP\Util::writeLog('user_ldap', 'Testing '.$attribute.' as UUID attr', \OCP\Util::DEBUG);
$value = $this->readAttribute($dn, $attribute);
if(is_array($value) && isset($value[0]) && !empty($value[0])) {
\OCP\Util::writeLog('user_ldap', 'Setting '.$attribute.' as UUID attr', \OCP\Util::DEBUG);
$this->connection->ldapUuidAttribute = $attribute;
\OCP\Util::writeLog('user_ldap',
'Setting '.$attribute.' as '.$uuidAttr,
\OCP\Util::DEBUG);
$this->connection->$uuidAttr = $attribute;
return true;
}
\OCP\Util::writeLog('user_ldap',
'The looked for uuid attr is not '.$attribute.', result was '.print_r($value, true),
\OCP\Util::DEBUG);
}
\OCP\Util::writeLog('user_ldap',
'Could not autodetect the UUID attribute',
\OCP\Util::ERROR);
return false;
}
public function getUUID($dn) {
if($this->detectUuidAttribute($dn)) {
\OCP\Util::writeLog('user_ldap',
'UUID Checking \ UUID for '.$dn.' using '. $this->connection->ldapUuidAttribute,
\OCP\Util::DEBUG);
$uuid = $this->readAttribute($dn, $this->connection->ldapUuidAttribute);
if(!is_array($uuid) && $this->connection->ldapOverrideUuidAttribute) {
$this->detectUuidAttribute($dn, true);
$uuid = $this->readAttribute($dn, $this->connection->ldapUuidAttribute);
public function getUUID($dn, $isUser = true) {
if($isUser) {
$uuidAttr = 'ldapUuidUserAttribute';
$uuidOverride = $this->connection->ldapExpertUUIDUserAttr;
} else {
$uuidAttr = 'ldapUuidGroupAttribute';
$uuidOverride = $this->connection->ldapExpertUUIDGroupAttr;
}
$uuid = false;
if($this->detectUuidAttribute($dn, $isUser)) {
$uuid = $this->readAttribute($dn, $this->connection->$uuidAttr);
if( !is_array($uuid)
&& !empty($uuidOverride)
&& $this->detectUuidAttribute($dn, $isUser, true)) {
$uuid = $this->readAttribute($dn,
$this->connection->$uuidAttr);
}
if(is_array($uuid) && isset($uuid[0]) && !empty($uuid[0])) {
$uuid = $uuid[0];
} else {
$uuid = false;
}
} else {
$uuid = false;
}
return $uuid;
}

View file

@ -60,7 +60,8 @@ class Connection extends LDAPUtility {
'ldapQuotaDefault' => null,
'ldapEmailAttribute' => null,
'ldapCacheTTL' => null,
'ldapUuidAttribute' => 'auto',
'ldapUuidUserAttribute' => 'auto',
'ldapUuidGroupAttribute' => 'auto',
'ldapOverrideUuidAttribute' => null,
'ldapOverrideMainServer' => false,
'ldapConfigurationActive' => false,
@ -69,7 +70,8 @@ class Connection extends LDAPUtility {
'homeFolderNamingRule' => null,
'hasPagedResultSupport' => false,
'ldapExpertUsernameAttr' => null,
'ldapExpertUUIDAttr' => null,
'ldapExpertUUIDUserAttr' => null,
'ldapExpertUUIDGroupAttr' => null,
);
/**
@ -120,11 +122,11 @@ class Connection extends LDAPUtility {
public function __set($name, $value) {
$changed = false;
//only few options are writable
if($name === 'ldapUuidAttribute') {
\OCP\Util::writeLog('user_ldap', 'Set config ldapUuidAttribute to '.$value, \OCP\Util::DEBUG);
if($name === 'ldapUuidUserAttribute' || $name === 'ldapUuidGroupAttribute') {
\OCP\Util::writeLog('user_ldap', 'Set config '.$name.' to '.$value, \OCP\Util::DEBUG);
$this->config[$name] = $value;
if(!empty($this->configID)) {
\OCP\Config::setAppValue($this->configID, $this->configPrefix.'ldap_uuid_attribute', $value);
\OCP\Config::setAppValue($this->configID, $this->configPrefix.$name, $value);
}
$changed = true;
}
@ -285,8 +287,10 @@ class Connection extends LDAPUtility {
$this->config['ldapIgnoreNamingRules']
= \OCP\Config::getSystemValue('ldapIgnoreNamingRules', false);
$this->config['ldapCacheTTL'] = $this->$v('ldap_cache_ttl');
$this->config['ldapUuidAttribute']
= $this->$v('ldap_uuid_attribute');
$this->config['ldapUuidUserAttribute']
= $this->$v('ldap_uuid_user_attribute');
$this->config['ldapUuidGroupAttribute']
= $this->$v('ldap_uuid_group_attribute');
$this->config['ldapOverrideUuidAttribute']
= $this->$v('ldap_override_uuid_attribute');
$this->config['homeFolderNamingRule']
@ -299,8 +303,10 @@ class Connection extends LDAPUtility {
= preg_split('/\r\n|\r|\n/', $this->$v('ldap_attributes_for_group_search'));
$this->config['ldapExpertUsernameAttr']
= $this->$v('ldap_expert_username_attr');
$this->config['ldapExpertUUIDAttr']
= $this->$v('ldap_expert_uuid_attr');
$this->config['ldapExpertUUIDUserAttr']
= $this->$v('ldap_expert_uuid_user_attr');
$this->config['ldapExpertUUIDGroupAttr']
= $this->$v('ldap_expert_uuid_group_attr');
$this->configured = $this->validateConfiguration();
}
@ -339,7 +345,8 @@ class Connection extends LDAPUtility {
'ldap_attributes_for_user_search' => 'ldapAttributesForUserSearch',
'ldap_attributes_for_group_search' => 'ldapAttributesForGroupSearch',
'ldap_expert_username_attr' => 'ldapExpertUsernameAttr',
'ldap_expert_uuid_attr' => 'ldapExpertUUIDAttr',
'ldap_expert_uuid_user_attr' => 'ldapExpertUUIDUserAttr',
'ldap_expert_uuid_group_attr' => 'ldapExpertUUIDGroupAttr',
);
return $array;
}
@ -413,7 +420,8 @@ class Connection extends LDAPUtility {
break;
case 'ldapIgnoreNamingRules':
case 'ldapOverrideUuidAttribute':
case 'ldapUuidAttribute':
case 'ldapUuidUserAttribute':
case 'ldapUuidGroupAttribute':
case 'hasPagedResultSupport':
continue 2;
}
@ -476,13 +484,23 @@ class Connection extends LDAPUtility {
}
$uuidAttributes = array(
'auto', 'entryuuid', 'nsuniqueid', 'objectguid', 'guid');
if(!in_array($this->config['ldapUuidAttribute'], $uuidAttributes)
&& (!is_null($this->configID))) {
\OCP\Config::setAppValue($this->configID, $this->configPrefix.'ldap_uuid_attribute', 'auto');
\OCP\Util::writeLog('user_ldap',
'Illegal value for the UUID Attribute, reset to autodetect.',
\OCP\Util::INFO);
$uuidSettings = array(
'ldapUuidUserAttribute' => 'ldapExpertUUIDUserAttr',
'ldapUuidGroupAttribute' => 'ldapExpertUUIDGroupAttr');
$cta = array_flip($this->getConfigTranslationArray());
foreach($uuidSettings as $defaultKey => $overrideKey) {
if( !in_array($this->config[$defaultKey], $uuidAttributes)
&& is_null($this->config[$overrideKey])
&& !is_null($this->configID)) {
\OCP\Config::setAppValue($this->configID,
$this->configPrefix.$cta[$defaultKey],
'auto');
\OCP\Util::writeLog('user_ldap',
'Illegal value for'.$defaultKey.', reset to autodetect.',
\OCP\Util::DEBUG);
}
}
if(empty($this->config['ldapBackupPort'])) {
//force default
$this->config['ldapBackupPort'] = $this->config['ldapPort'];
@ -502,8 +520,6 @@ class Connection extends LDAPUtility {
\OCP\Util::INFO);
}
//second step: critical checks. If left empty or filled wrong, set as unconfigured and give a warning.
$configurationOK = true;
if(empty($this->config['ldapHost'])) {
@ -552,8 +568,11 @@ class Connection extends LDAPUtility {
$configurationOK = false;
}
if(!empty($this->config['ldapExpertUUIDAttr'])) {
$this->config['ldapUuidAttribute'] = $this->config['ldapExpertUUIDAttr'];
if(!empty($this->config['ldapExpertUUIDUserAttr'])) {
$this->config['ldapUuidUserAttribute'] = $this->config['ldapExpertUUIDUserAttr'];
}
if(!empty($this->config['ldapExpertUUIDGroupAttr'])) {
$this->config['ldapUuidGroupAttribute'] = $this->config['ldapExpertUUIDGroupAttr'];
}
return $configurationOK;
@ -587,15 +606,17 @@ class Connection extends LDAPUtility {
'ldap_email_attr' => '',
'ldap_group_member_assoc_attribute' => 'uniqueMember',
'ldap_cache_ttl' => 600,
'ldap_uuid_attribute' => 'auto',
'ldap_uuid_user_attribute' => 'auto',
'ldap_uuid_group_attribute' => 'auto',
'ldap_override_uuid_attribute' => 0,
'home_folder_naming_rule' => '',
'ldap_turn_off_cert_check' => 0,
'ldap_configuration_active' => 1,
'ldap_attributes_for_user_search' => '',
'ldap_attributes_for_group_search' => '',
'ldap_expert_username_attr' => '',
'ldap_expert_uuid_attr' => '',
'ldap_expert_username_attr' => '',
'ldap_expert_uuid_user_attr' => '',
'ldap_expert_uuid_group_attr' => '',
);
}

View file

@ -25,18 +25,6 @@
OC_Util::checkAdminUser();
$params = array('ldap_host', 'ldap_port', 'ldap_backup_host',
'ldap_backup_port', 'ldap_override_main_server', 'ldap_dn',
'ldap_agent_password', 'ldap_base', 'ldap_base_users',
'ldap_base_groups', 'ldap_userlist_filter',
'ldap_login_filter', 'ldap_group_filter', 'ldap_display_name',
'ldap_group_display_name', 'ldap_tls',
'ldap_turn_off_cert_check', 'ldap_nocase', 'ldap_quota_def',
'ldap_quota_attr', 'ldap_email_attr',
'ldap_group_member_assoc_attribute', 'ldap_cache_ttl',
'home_folder_naming_rule'
);
OCP\Util::addscript('user_ldap', 'settings');
OCP\Util::addstyle('user_ldap', 'settings');

View file

@ -100,7 +100,8 @@
<p class="ldapIndent"><label for="ldap_expert_username_attr"><?php p($l->t('Internal Username Attribute:'));?></label><input type="text" id="ldap_expert_username_attr" name="ldap_expert_username_attr" data-default="<?php p($_['ldap_expert_username_attr_default']); ?>" /></p>
<p><strong><?php p($l->t('Override UUID detection'));?></strong></p>
<p class="ldapIndent"><?php p($l->t('By default, the UUID attribute is automatically detected. The UUID attribute is used to doubtlessly identify LDAP users and groups. Also, the internal username will be created based on the UUID, if not specified otherwise above. You can override the setting and pass an attribute of your choice. You must make sure that the attribute of your choice can be fetched for both users and groups and it is unique. Leave it empty for default behavior. Changes will have effect only on newly mapped (added) LDAP users and groups.'));?></p>
<p class="ldapIndent"><label for="ldap_expert_uuid_attr"><?php p($l->t('UUID Attribute:'));?></label><input type="text" id="ldap_expert_uuid_attr" name="ldap_expert_uuid_attr" data-default="<?php p($_['ldap_expert_uuid_attr_default']); ?>" /></p>
<p class="ldapIndent"><label for="ldap_expert_uuid_user_attr"><?php p($l->t('UUID Attribute for Users:'));?></label><input type="text" id="ldap_expert_uuid_user_attr" name="ldap_expert_uuid_user_attr" data-default="<?php p($_['ldap_expert_uuid_user_attr_default']); ?>" /></p>
<p class="ldapIndent"><label for="ldap_expert_uuid_group_attr"><?php p($l->t('UUID Attribute for Groups:'));?></label><input type="text" id="ldap_expert_uuid_group_attr" name="ldap_expert_uuid_group_attr" data-default="<?php p($_['ldap_expert_uuid_group_attr_default']); ?>" /></p>
<p><strong><?php p($l->t('Username-LDAP User Mapping'));?></strong></p>
<p class="ldapIndent"><?php p($l->t('Usernames are used to store and assign (meta) data. In order to precisely identify and recognize users, each LDAP user will have a internal username. This requires a mapping from username to LDAP user. The created username is mapped to the UUID of the LDAP user. Additionally the DN is cached as well to reduce LDAP interaction, but it is not used for identification. If the DN changes, the changes will be found. The internal username is used all over. Clearing the mappings will have leftovers everywhere. Clearing the mappings is not configuration sensitive, it affects all LDAP configurations! Never clear the mappings in a production environment, only in a testing or experimental stage.'));?></p>
<p class="ldapIndent"><button id="ldap_action_clear_user_mappings" name="ldap_action_clear_user_mappings"><?php p($l->t('Clear Username-LDAP User Mapping'));?></button><br/><button id="ldap_action_clear_group_mappings" name="ldap_action_clear_group_mappings"><?php p($l->t('Clear Groupname-LDAP Group Mapping'));?></button></p>