forked from extern/egroupware
finish migration AD to new UCS domain via EGroupware
This commit is contained in:
parent
18efbfad98
commit
18a048e5c8
@ -12,8 +12,6 @@
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage accounts
|
||||
* @access public
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
namespace EGroupware\Api;
|
||||
@ -817,6 +815,16 @@ class Accounts
|
||||
{
|
||||
if (!$account_id || !($data = $this->read($account_id)))
|
||||
{
|
||||
// non sql backends might NOT show EGw all users, but backend->id2name/name2id does
|
||||
if (is_a($this->backend, __CLASS__.'\\Univention'))
|
||||
{
|
||||
if (!is_numeric($account_id) ?
|
||||
($account_id = $this->backend->name2id($account_id)) :
|
||||
$this->backend->id2name($account_id))
|
||||
{
|
||||
return $account_id > 0 ? 1 : 2;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return $data['account_type'] == 'u' ? 1 : 2;
|
||||
@ -1152,15 +1160,19 @@ class Accounts
|
||||
// instance-wide cache
|
||||
if ($account_ids)
|
||||
{
|
||||
$instance = self::getInstance();
|
||||
|
||||
foreach((array)$account_ids as $account_id)
|
||||
{
|
||||
$instance = self::getInstance();
|
||||
|
||||
Cache::unsetCache($instance->config['install_id'], __CLASS__, 'account-'.$account_id);
|
||||
|
||||
unset(self::$request_cache[$account_id]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self::$request_cache = array();
|
||||
}
|
||||
|
||||
// session-cache
|
||||
if (self::$cache) self::$cache = array();
|
||||
|
@ -14,7 +14,6 @@
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage accounts
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
namespace EGroupware\Api\Accounts;
|
||||
@ -989,7 +988,7 @@ class Ldap
|
||||
*
|
||||
* @param int $account_id numerica account_id
|
||||
* @param string $which ='account_lid' type to convert to: account_lid (default), account_email, ...
|
||||
* @return string/false converted value or false on error ($account_id not found)
|
||||
* @return string|false converted value or false on error ($account_id not found)
|
||||
*/
|
||||
function id2name($account_id,$which='account_lid')
|
||||
{
|
||||
@ -1058,7 +1057,7 @@ class Ldap
|
||||
|
||||
foreach($group[0]['memberuid'] as $lid)
|
||||
{
|
||||
if (($id = $this->name2id($lid, 'account_lid', 'u')))
|
||||
if (($id = $this->name2id($lid, 'account_lid'))) // also return groups!
|
||||
{
|
||||
$members[$id] = $lid;
|
||||
}
|
||||
@ -1104,7 +1103,6 @@ class Ldap
|
||||
* @param int $gid gidnumber of group to set
|
||||
* @param array $objectclass =null should we set the member and uniqueMember attributes (groupOf(Unique)Names|univentionGroup) (default detect it)
|
||||
* @param string $use_cn =null if set $cn is used instead $gid and the attributes are returned, not written to ldap
|
||||
* @param boolean $uniqueMember =null should we set the uniqueMember attribute (default detect it)
|
||||
* @return boolean/array false on failure, array or true otherwise
|
||||
*/
|
||||
function set_members($members, $gid, array $objectclass=null, $use_cn=null)
|
||||
@ -1112,15 +1110,31 @@ class Ldap
|
||||
if (!($cn = $use_cn) && !($cn = $this->id2name($gid))) return false;
|
||||
|
||||
// do that group is a groupOf(Unique)Names or univentionGroup?
|
||||
if (is_null($objectclass)) $objectclass = $this->id2name($gid,'objectclass');
|
||||
if (!isset($objectclass))
|
||||
{
|
||||
$objectclass = $this->id2name($gid, 'objectclass');
|
||||
// if we cant find objectclass, we might ge in the middle of a migration
|
||||
if (!isset($objectclass))
|
||||
{
|
||||
Api\Accounts::cache_invalidate($gid);
|
||||
if (!($objectclass = $this->id2name($gid, 'objectclass')))
|
||||
{
|
||||
// group does not yet exist --> return false
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$to_write = array('memberuid' => array());
|
||||
foreach((array)$members as $key => $member)
|
||||
foreach((array)$members as $member)
|
||||
{
|
||||
if (!$member) continue;
|
||||
|
||||
$member_dn = $this->id2name($member, 'account_dn');
|
||||
if (is_numeric($member)) $member = $this->id2name($member);
|
||||
|
||||
if ($member)
|
||||
// only add a member, if we have the neccessary info / he already exists in migration
|
||||
if ($member && ($member_dn || !array_intersect(array('groupofnames','groupofuniquenames','univentiongroup'), $objectclass)))
|
||||
{
|
||||
$to_write['memberuid'][] = $member;
|
||||
if (in_array('groupofnames', $objectclass))
|
||||
@ -1154,7 +1168,7 @@ class Ldap
|
||||
if ($forward)
|
||||
{
|
||||
$to_write[$forward] = array();
|
||||
foreach($members as $key => $member)
|
||||
foreach($members as $member)
|
||||
{
|
||||
if (($email = $this->id2name($member,'account_email'))) $to_write[$forward][] = $email;
|
||||
}
|
||||
@ -1162,7 +1176,7 @@ class Ldap
|
||||
}
|
||||
if (!ldap_modify($this->ds,'cn='.Api\Ldap::quote($cn).','.$this->group_context,$to_write))
|
||||
{
|
||||
echo "ldap_modify(,'cn=$cn,$this->group_context',".print_r($to_write,true)."))\n";
|
||||
error_log(__METHOD__."(members=".array2string($members).", gid=$gid, objectclass=".array2string($objectclass).", use_cn=$use_cn) !ldap_modify(,'cn=$cn,$this->group_context', ".array2string($to_write).") --> ldap_error()=".ldap_error($this->ds));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -8,7 +8,6 @@
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage accounts
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
namespace EGroupware\Api\Accounts;
|
||||
@ -23,6 +22,8 @@ use EGroupware\Api;
|
||||
* Only difference is that new users get created via univention-directory-manager CLI program,
|
||||
* to generate necesary Kerberos stuff.
|
||||
*
|
||||
* New groups are generated via same CLI, if we have an ID/RID to set.
|
||||
*
|
||||
* Existing users and groups need to be renamed via same CLI, as removing and
|
||||
* adding entry under new dn via LDAP fails (Type or value exists).
|
||||
*/
|
||||
@ -56,11 +57,16 @@ class Univention extends Ldap
|
||||
|
||||
if (self::available())
|
||||
{
|
||||
$ssh = null;//'/usr/bin/ssh -o "UserKnownHostsFile=/dev/null" -o "StrictHostKeyChecking=no" -i /var/lib/egroupware/id_rsa root@10.44.22.194';
|
||||
$config = $this->frontend->config && $this->frontend->config['ldap_context'] ?
|
||||
$this->frontend->config : $GLOBALS['egw_info']['server'];
|
||||
|
||||
if (!$data['account_id'] && $data['account_type'] !== 'g')
|
||||
if ($data['account_type'] !== 'g' && (empty($data['account_id']) || !$this->id2name($data['account_id'])))
|
||||
{
|
||||
// empty names give an error: The property Last/First name is required is not valid
|
||||
if (empty($data['account_firstname'])) $data['account_firstname'] = 'n/a';
|
||||
if (empty($data['account_lastname'])) $data['account_lastname'] = 'n/a';
|
||||
|
||||
$params = array(
|
||||
'users/user','create',
|
||||
'--binddn', $config['ldap_root_dn'],
|
||||
@ -70,13 +76,34 @@ class Univention extends Ldap
|
||||
'--set', 'firstname='.$data['account_firstname'],
|
||||
'--set', 'lastname='.$data['account_lastname'],
|
||||
);
|
||||
if ($data['account_email'])
|
||||
|
||||
// we can't create a new user without a password, setting a randowm one for now
|
||||
$matches = null;
|
||||
if (empty($data['account_passwd']) || preg_match('/^{([a-z0-9_]+)}/i', $data['account_passwd'], $matches))
|
||||
{
|
||||
if ($matches && strtolower($matches[1]) === 'plain')
|
||||
{
|
||||
$data['account_passwd'] = substr($data['account_passwd'], 7);
|
||||
}
|
||||
else
|
||||
{
|
||||
$data['account_passwd'] = Api\Auth::randomstring(12);
|
||||
//file_put_contents('/tmp/passwords', "$data[account_lid]\t$data[account_passwd]\n", FILE_APPEND);
|
||||
}
|
||||
}
|
||||
$params[] = '--set'; $params[] = 'password='.$data['account_passwd'];
|
||||
|
||||
// if account_id is given and bigger then 1000, set it to facilitate migration
|
||||
if (!empty($data['account_id']) && $data['account_id'] >= Ads::MIN_ACCOUNT_ID)
|
||||
{
|
||||
$params[] = '--set'; $params[] = 'uidNumber='.(int)$data['account_id'];
|
||||
$params[] = '--set'; $params[] = 'sambaRID='.(int)$data['account_id'];
|
||||
}
|
||||
|
||||
if (!empty($data['account_email']))
|
||||
{
|
||||
$params[] = '--set'; $params[] = 'mailPrimaryAddress='.$data['account_email'];
|
||||
}
|
||||
if (!empty($data['account_passwd']))
|
||||
{
|
||||
$params[] = '--set'; $params[] = 'password='.$data['account_passwd'];
|
||||
|
||||
// we need to set mailHomeServer, so mailbox gets created for Dovecot
|
||||
// get_default() does not work for Adminstrator, try acc_id=1 instead
|
||||
// if everything fails try hostname ...
|
||||
@ -90,10 +117,12 @@ class Univention extends Ldap
|
||||
catch(\Exception $e) {
|
||||
unset($e);
|
||||
}
|
||||
if (empty($hostname)) $hostname = trim(system('hostname -f'));
|
||||
//$hostname='master.test-org.intranet';
|
||||
if (empty($hostname)) $hostname = trim(exec('hostname -f'));
|
||||
$params[] = '--set'; $params[] = 'mailHomeServer='.$hostname;
|
||||
}
|
||||
$cmd = self::DIRECTORY_MANAGER_BIN.' '.implode(' ', array_map('escapeshellarg', $params));
|
||||
if (isset($ssh)) $cmd = $ssh.' bash -c "\\"'.$cmd.'\\""';
|
||||
$output_arr = $ret = $matches = null;
|
||||
exec($cmd, $output_arr, $ret);
|
||||
$output = implode("\n", $output_arr);
|
||||
@ -106,6 +135,34 @@ class Univention extends Ldap
|
||||
$data['account_dn'] = $matches[1];
|
||||
$data['account_id'] = $this->name2id($data['account_lid'], 'account_lid', 'u');
|
||||
}
|
||||
// create new groups with given account_id via directory-manager too, to be able to set the RID
|
||||
elseif($data['account_type'] === 'g' && !empty($data['account_id']) &&
|
||||
$data['account_id'] >= Ads::MIN_ACCOUNT_ID && !$this->id2name($data['account_id']))
|
||||
{
|
||||
$params = array(
|
||||
'groups/group', 'create',
|
||||
'--binddn', $config['ldap_root_dn'],
|
||||
'--bindpwd', 5=>$config['ldap_root_pw'],
|
||||
'--position', empty($config['ldap_group_context']) ? $config['ldap_context'] : $config['ldap_group_context'],
|
||||
'--set', 'name='.$data['account_lid'],
|
||||
'--set', 'gidNumber='.(int)$data['account_id'],
|
||||
'--set', 'sambaRID='.(int)$data['account_id'],
|
||||
);
|
||||
|
||||
$cmd = self::DIRECTORY_MANAGER_BIN.' '.implode(' ', array_map('escapeshellarg', $params));
|
||||
if (isset($ssh)) $cmd = $ssh.' bash -c "\\"'.$cmd.'\\""';
|
||||
$output_arr = $ret = $matches = null;
|
||||
exec($cmd, $output_arr, $ret);
|
||||
$output = implode("\n", $output_arr);
|
||||
if ($ret || !preg_match('/^Object created: (cn=.*)$/mui', $output, $matches))
|
||||
{
|
||||
$params[5] = '********'; // mask out password!
|
||||
$cmd = self::DIRECTORY_MANAGER_BIN.' '.implode(' ', array_map('escapeshellarg', $params));
|
||||
throw new Api\Exception\WrongUserinput($cmd."\nreturned\n".$output);
|
||||
}
|
||||
$data['account_dn'] = $matches[1];
|
||||
$data['account_id'] = $this->name2id($data['account_lid'], 'account_lid', 'g');
|
||||
}
|
||||
elseif($data['account_id'] && ($data['old_loginid'] || ($data['old_loginid'] = $this->id2name($data['account_id']))) &&
|
||||
$data['account_lid'] != $data['old_loginid'] &&
|
||||
($data['account_dn'] = $this->id2name($data['account_id'], 'account_dn')))
|
||||
@ -118,6 +175,7 @@ class Univention extends Ldap
|
||||
'--set', ($data['account_type'] !== 'g' ? 'username' : 'name').'='.$data['account_lid'],
|
||||
);
|
||||
$cmd = self::DIRECTORY_MANAGER_BIN.' '.implode(' ', array_map('escapeshellarg', $params));
|
||||
if (isset($ssh)) $cmd = $ssh.' bash -c "\\"'.$cmd.'\\""';
|
||||
$output_arr = $ret = $matches = null;
|
||||
exec($cmd, $output_arr, $ret);
|
||||
$output = implode("\n", $output_arr);
|
||||
@ -136,6 +194,57 @@ class Univention extends Ldap
|
||||
return parent::save($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* convert an alphanumeric account-value (account_lid, account_email) to the account_id
|
||||
*
|
||||
* Reimplement to check for users outside regular user-dn eg. functional users
|
||||
*
|
||||
* @param string $_name value to convert
|
||||
* @param string $which ='account_lid' type of $name: account_lid (default), account_email, person_id, account_fullname
|
||||
* @param string $account_type u = user, g = group, default null = try both
|
||||
* @return int|false numeric account_id or false on error ($name not found)
|
||||
*/
|
||||
function name2id($_name,$which='account_lid',$account_type=null)
|
||||
{
|
||||
if ((!$id = parent::name2id($_name, $which, $account_type)))
|
||||
{
|
||||
$user_dn = $this->user_context;
|
||||
$this->user_context = preg_replace('/(cn|uid)=([^,]+),/i', '', $this->user_context);
|
||||
|
||||
$id = parent::name2id($_name, $which, $account_type);
|
||||
|
||||
$this->user_context = $user_dn;
|
||||
}
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an numeric account_id to any other value of that account (account_lid, account_email, ...)
|
||||
*
|
||||
* Reimplement to check for users outside regular user-dn eg. functional users
|
||||
*
|
||||
* @param int $account_id numerica account_id
|
||||
* @param string $which ='account_lid' type to convert to: account_lid (default), account_email, ...
|
||||
* @return string|false converted value or false on error ($account_id not found)
|
||||
*/
|
||||
function id2name($account_id,$which='account_lid')
|
||||
{
|
||||
if (($name = parent::id2name($account_id, $which)) === false)
|
||||
{
|
||||
if (!is_numeric($account_id)) $account_id = $this->name2id($account_id);
|
||||
|
||||
$user_dn = $this->user_context;
|
||||
$this->user_context = preg_replace('/(cn|uid)=([^,]+),/i', '', $this->user_context);
|
||||
|
||||
if ($account_id && ($data = $this->read($account_id)))
|
||||
{
|
||||
$name = $data[$which];
|
||||
}
|
||||
$this->user_context = $user_dn;
|
||||
}
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if our function depending on an external binary is available
|
||||
*
|
||||
@ -143,6 +252,7 @@ class Univention extends Ldap
|
||||
*/
|
||||
public static function available()
|
||||
{
|
||||
//return true;
|
||||
return file_exists(self::DIRECTORY_MANAGER_BIN) && is_executable(self::DIRECTORY_MANAGER_BIN);
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ use EGroupware\Api;
|
||||
* 1. migrate from AD --> SQL including mail-attributes
|
||||
* 2. optionaly fix user-names etc in SQL
|
||||
* 3. migrate from SQL --> Univention (make sure NOT to select existing users like "join-backup/slaves"
|
||||
* and delete "anonymous" user from EGroupware App install in UCS)
|
||||
* and delete "anonymous" user and "Admins", "Default" and "NoGroup" from EGroupware App install in UCS)
|
||||
*/
|
||||
class setup_cmd_ldap extends setup_cmd
|
||||
{
|
||||
@ -683,24 +683,27 @@ class setup_cmd_ldap extends setup_cmd
|
||||
($errors || $this->verbose ? "\n- ".implode("\n- ",$msg) : '');
|
||||
}
|
||||
// migrate addressbook data
|
||||
$GLOBALS['egw_info']['user']['apps']['admin'] = true; // otherwise migration will not run in setup!
|
||||
$addressbook = new Api\Contacts\Storage();
|
||||
foreach($this->as_array() as $name => $value)
|
||||
if ($to !== 'univention') // ToDo: univentions currently gives only Oject class violation
|
||||
{
|
||||
if (substr($name, 5) == 'ldap_' || substr($name, 4) == 'ads_')
|
||||
$GLOBALS['egw_info']['user']['apps']['admin'] = true; // otherwise migration will not run in setup!
|
||||
$addressbook = new Api\Contacts\Storage();
|
||||
foreach($this->as_array() as $name => $value)
|
||||
{
|
||||
$GLOBALS['egw_info']['server'][$name] = $value;
|
||||
if (substr($name, 5) == 'ldap_' || substr($name, 4) == 'ads_')
|
||||
{
|
||||
$GLOBALS['egw_info']['server'][$name] = $value;
|
||||
}
|
||||
}
|
||||
ob_start();
|
||||
$addressbook->migrate2ldap($to != 'sql' ? 'accounts' : 'accounts-back'.
|
||||
($this->account_repository == 'ads' ? '-ads' : ''));
|
||||
$msg = array_merge($msg, explode("\n", strip_tags(ob_get_clean())));
|
||||
}
|
||||
ob_start();
|
||||
$addressbook->migrate2ldap($to != 'sql' ? 'accounts' : 'accounts-back'.
|
||||
($this->account_repository == 'ads' ? '-ads' : ''));
|
||||
$msgs = array_merge($msg, explode("\n", strip_tags(ob_get_clean())));
|
||||
|
||||
$this->restore_db();
|
||||
|
||||
return lang('%1 users and %2 groups created, %3 errors',$accounts_created,$groups_created,$errors).
|
||||
($errors || $this->verbose ? "\n- ".implode("\n- ",$msgs) : '');
|
||||
($errors || $this->verbose ? "\n- ".implode("\n- ",$msg) : '');
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user