mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-22 07:53:39 +01:00
* LDAP/ActiveDirectory Sync: permanently store DN+entryUUID and use the latter to detect renamed user or accounts
This commit is contained in:
parent
10a7a4bd7e
commit
9888a681e7
@ -11,7 +11,7 @@
|
||||
/* Basic information about this app */
|
||||
$setup_info['api']['name'] = 'api';
|
||||
$setup_info['api']['title'] = 'EGroupware API';
|
||||
$setup_info['api']['version'] = '23.1.007';
|
||||
$setup_info['api']['version'] = '23.1.008';
|
||||
$setup_info['api']['versions']['current_header'] = '1.29';
|
||||
// maintenance release in sync with changelog in doc/rpm-build/debian.changes
|
||||
$setup_info['api']['versions']['maintenance_release'] = '23.1.20240624';
|
||||
|
@ -64,7 +64,9 @@ $phpgw_baseline = array(
|
||||
'account_expires' => array('type' => 'int','precision' => '4'),
|
||||
'account_type' => array('type' => 'char','precision' => '1'),
|
||||
'account_primary_group' => array('type' => 'int','meta' => 'group','precision' => '4','nullable' => False,'default' => '0'),
|
||||
'account_description' => array('type' => 'varchar','precision' => '255','comment' => 'group description')
|
||||
'account_description' => array('type' => 'varchar','precision' => '255','comment' => 'group description'),
|
||||
'account_uuid' => array('type' => 'ascii','precision' => '64','comment' => 'UUID of synced (LDAP) entries'),
|
||||
'account_dn' => array('type' => 'varchar','precision' => '255','comment' => 'DN or container')
|
||||
),
|
||||
'pk' => array('account_id'),
|
||||
'fk' => array(),
|
||||
@ -553,4 +555,4 @@ $phpgw_baseline = array(
|
||||
'ix' => array('account_id'),
|
||||
'uc' => array()
|
||||
)
|
||||
);
|
||||
);
|
@ -976,4 +976,20 @@ function api_upgrade23_1_006()
|
||||
));
|
||||
|
||||
return $GLOBALS['setup_info']['api']['currentver'] = '23.1.007';
|
||||
}
|
||||
|
||||
function api_upgrade23_1_007()
|
||||
{
|
||||
$GLOBALS['egw_setup']->oProc->AddColumn('egw_accounts','account_uuid',array(
|
||||
'type' => 'ascii',
|
||||
'precision' => '64',
|
||||
'comment' => 'UUID of synced (LDAP) entries'
|
||||
));
|
||||
$GLOBALS['egw_setup']->oProc->AddColumn('egw_accounts','account_dn',array(
|
||||
'type' => 'varchar',
|
||||
'precision' => '255',
|
||||
'comment' => 'DN or container'
|
||||
));
|
||||
|
||||
return $GLOBALS['setup_info']['api']['currentver'] = '23.1.008';
|
||||
}
|
@ -113,7 +113,7 @@ class Ads
|
||||
* @var array
|
||||
*/
|
||||
protected static $default_attributes = array(
|
||||
'objectsid', 'samaccounttype', 'samaccountname',
|
||||
'objectsid', 'samaccounttype', 'samaccountname', 'entryuuid',
|
||||
);
|
||||
|
||||
/**
|
||||
@ -122,7 +122,7 @@ class Ads
|
||||
* @var array
|
||||
*/
|
||||
protected static $user_attributes = array(
|
||||
'objectsid', 'samaccounttype', 'samaccountname',
|
||||
'objectsid', 'samaccounttype', 'samaccountname', 'entryuuid',
|
||||
'primarygroupid', 'givenname', 'sn', 'mail', 'displayname', 'telephonenumber',
|
||||
'objectguid', 'useraccountcontrol', 'accountexpires', 'pwdlastset', 'whencreated', 'whenchanged', 'lastlogon',
|
||||
'jpegphoto',
|
||||
@ -134,7 +134,7 @@ class Ads
|
||||
* @var array
|
||||
*/
|
||||
protected static $group_attributes = array(
|
||||
'objectsid', 'samaccounttype', 'samaccountname',
|
||||
'objectsid', 'samaccounttype', 'samaccountname', 'entryuuid',
|
||||
'objectguid', 'mail', 'whencreated', 'whenchanged', 'description',
|
||||
);
|
||||
|
||||
@ -565,6 +565,7 @@ class Ads
|
||||
|
||||
$group = array(
|
||||
'account_dn' => $data['dn'],
|
||||
'account_uuid' => $data['entryuuid'][0],
|
||||
'account_id' => $account_id,
|
||||
'account_sid' => $sid,
|
||||
'account_guid' => $this->adldap->utilities()->decodeGuid($data['objectguid'][0]),
|
||||
@ -644,6 +645,7 @@ class Ads
|
||||
|
||||
$user = array(
|
||||
'account_dn' => $data['dn'],
|
||||
'account_uuid' => $data['entryuuid'][0],
|
||||
'account_id' => $account_id,
|
||||
'account_sid' => $sid,
|
||||
'account_guid' => $this->adldap->utilities()->decodeGuid($data['objectguid'][0]),
|
||||
@ -1327,6 +1329,8 @@ class Ads
|
||||
'account_fullname' => 'cn',
|
||||
'account_sid' => 'objectsid',
|
||||
'account_guid' => 'objectguid',
|
||||
'account_uuid' => 'entryuuid',
|
||||
'account_dn' => 'dn',
|
||||
);
|
||||
$ret = false;
|
||||
if (isset($to_ldap[$which]))
|
||||
|
@ -325,7 +325,8 @@ class Import
|
||||
$hide_binary = ['jpegphoto' => $contact['jpegphoto'] ? bytes($contact['jpegphoto']).' bytes binary data' : null];
|
||||
$this->logger(++$num.'. User: '.json_encode($hide_binary + $contact + $account, JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE), 'debug');
|
||||
// check if account exists in sql
|
||||
if (!($account_id = $this->accounts_sql->name2id($account['account_lid'])))
|
||||
if (!($account_id = $this->accounts_sql->name2id($account['account_uuid'], 'account_uuid')) &&
|
||||
!($account_id = $this->accounts_sql->name2id($account['account_lid'])))
|
||||
{
|
||||
$sql_account = $account;
|
||||
// if only users are imported set primary group as configured
|
||||
@ -702,10 +703,14 @@ class Import
|
||||
$local_groups = in_array('local', explode('+', $GLOBALS['egw_info']['server']['account_import_type']));
|
||||
|
||||
// query all groups in SQL
|
||||
$sql_groups = $groups = $set_members = [];
|
||||
foreach($GLOBALS['egw']->db->select(Sql::TABLE, 'account_id,account_lid', ['account_type' => 'g'], __LINE__, __FILE__) as $row)
|
||||
$sql_groups = $uuid2account_id = $groups = $set_members = [];
|
||||
foreach($GLOBALS['egw']->db->select(Sql::TABLE, 'account_id,account_lid,account_uuid', ['account_type' => 'g'], __LINE__, __FILE__) as $row)
|
||||
{
|
||||
$sql_groups[-$row['account_id']] = self::strtolower($row['account_lid']);
|
||||
if (!empty($row['account_uuid']))
|
||||
{
|
||||
$uuid2account_id[$row['account_uuid']] = -$row['account_id'];
|
||||
}
|
||||
}
|
||||
// fill groups with existing ones, for incremental sync, but only if we have NO local groups, otherwise we need to query them all
|
||||
$filter = ['type' => 'groups'];
|
||||
@ -733,7 +738,13 @@ class Import
|
||||
}
|
||||
$this->logger(++$num.'. Group: '.json_encode($group, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES), 'debug');
|
||||
|
||||
if (!($sql_id = array_search(self::strtolower($group['account_lid']), $sql_groups)))
|
||||
$sql_id = null;
|
||||
// found group by uuid
|
||||
if ($uuid2account_id && ($sql_id = $uuid2account_id[$group['account_uuid']] ?? false))
|
||||
{
|
||||
|
||||
}
|
||||
if (!$sql_id && !($sql_id = array_search(self::strtolower($group['account_lid']), $sql_groups)))
|
||||
{
|
||||
if ($this->accounts_sql->name2id($group['account_lid']) > 0)
|
||||
{
|
||||
@ -754,7 +765,7 @@ class Import
|
||||
}
|
||||
if (($sql_id = $group['account_id'] = $this->accounts_sql->save($group, true)) < 0)
|
||||
{
|
||||
// run addgroup hook to create eg. home-directory or mail account
|
||||
// run addgroup hook to create e.g. home-directory or mail account
|
||||
Api\Hooks::process($group+array(
|
||||
'location' => 'addgroup'
|
||||
),False,True); // called for every app now, not only enabled ones)
|
||||
|
@ -535,7 +535,7 @@ class Ldap
|
||||
}
|
||||
}
|
||||
if (!($data = $this->_ldap_search($this->group_context,'(&(objectClass=posixGroup)(gidnumber=' . abs($account_id).'))',
|
||||
array('dn', 'gidnumber', 'cn', 'objectclass', static::MAIL_ATTR, 'memberuid', 'description'))))
|
||||
array('dn', 'gidnumber', 'cn', 'objectclass', static::MAIL_ATTR, 'memberuid', 'description', 'entryuuid'))))
|
||||
{
|
||||
return false; // group not found
|
||||
}
|
||||
@ -543,6 +543,7 @@ class Ldap
|
||||
|
||||
$group += array(
|
||||
'account_dn' => $data['dn'],
|
||||
'account_uuid' => $data['entryuuid'][0],
|
||||
'account_id' => -$data['gidnumber'][0],
|
||||
'account_lid' => $data['cn'][0],
|
||||
'account_type' => 'g',
|
||||
@ -585,7 +586,7 @@ class Ldap
|
||||
|
||||
if (!($data = $this->_ldap_search($this->user_context, '(&(objectclass=posixAccount)(uidnumber=' . (int)$account_id.")$account_filter)",
|
||||
array('dn','uidnumber','uid','gidnumber','givenname','sn','cn',static::MAIL_ATTR,'userpassword','telephonenumber',
|
||||
'shadowexpire','shadowlastchange','homedirectory','loginshell','createtimestamp','modifytimestamp'))))
|
||||
'shadowexpire','shadowlastchange','homedirectory','loginshell','createtimestamp','modifytimestamp','entryuuid'))))
|
||||
{
|
||||
return false; // user not found
|
||||
}
|
||||
@ -593,6 +594,7 @@ class Ldap
|
||||
$utc_diff = date('Z');
|
||||
$user = array(
|
||||
'account_dn' => $data['dn'],
|
||||
'account_uuid' => $data['entryuuid'][0],
|
||||
'account_id' => (int)$data['uidnumber'][0],
|
||||
'account_lid' => $data['uid'][0],
|
||||
'account_type' => 'u',
|
||||
@ -893,7 +895,7 @@ class Ldap
|
||||
{
|
||||
$allValues = $this->vlvSortQuery($this->user_context, $filter,
|
||||
['uid', 'uidNumber', 'givenname', 'sn', static::MAIL_ATTR, 'shadowExpire', 'createtimestamp',
|
||||
'modifytimestamp', 'objectclass', 'gidNumber', 'jpegphoto'],
|
||||
'modifytimestamp', 'objectclass', 'gidNumber', 'jpegphoto', 'entryuuid'],
|
||||
$order_by, $start, $offset, $totalcount);
|
||||
|
||||
$utc_diff = date('Z');
|
||||
@ -904,6 +906,7 @@ class Ldap
|
||||
{
|
||||
$account = array(
|
||||
'account_dn' => $allVals['dn'],
|
||||
'account_uuid' => $allVals['entryuuid'][0],
|
||||
'account_id' => $allVals['uidnumber'][0],
|
||||
'account_lid' => Api\Translation::convert($allVals['uid'][0], 'utf-8'),
|
||||
'account_type' => 'u',
|
||||
@ -963,7 +966,7 @@ class Ldap
|
||||
$filter .= "(modifytimestamp>=".gmdate('YmdHis', $param['modified']).".0Z)";
|
||||
}
|
||||
$filter .= ')';
|
||||
$allValues = $this->vlvSortQuery($this->group_context, $filter, ['cn', 'gidNumber'], $order_by, $start, $offset, $group_total);
|
||||
$allValues = $this->vlvSortQuery($this->group_context, $filter, ['cn', 'gidNumber', 'entryuuid'], $order_by, $start, $offset, $group_total);
|
||||
$totalcount += $group_total;
|
||||
foreach($allValues ?: [] as $allVals)
|
||||
{
|
||||
@ -972,6 +975,7 @@ class Ldap
|
||||
{
|
||||
$accounts[(string)-$allVals['gidnumber'][0]] = Array(
|
||||
'account_dn' => $allVals['dn'],
|
||||
'account_uuid' => $allVals['entryuuid'][0],
|
||||
'account_id' => -$allVals['gidnumber'][0],
|
||||
'account_lid' => Api\Translation::convert($allVals['cn'][0],'utf-8'),
|
||||
'account_type' => 'g',
|
||||
@ -1085,32 +1089,38 @@ class Ldap
|
||||
{
|
||||
$name = Api\Ldap::quote(Api\Translation::convert($_name,Api\Translation::charset(),'utf-8'));
|
||||
|
||||
if (in_array($which, array('account_lid','account_email')) && $account_type !== 'u') // groups only support account_(lid|email)
|
||||
$to_ldap = [
|
||||
'account_lid' => 'cn',
|
||||
'account_email' => static::MAIL_ATTR,
|
||||
'account_uuid' => 'entryuuid',
|
||||
'account_dn' => 'dn',
|
||||
];
|
||||
if (isset($to_ldap[$which]) && $account_type !== 'u') // groups only support account_(lid|email)
|
||||
{
|
||||
$attr = $which == 'account_lid' ? 'cn' : static::MAIL_ATTR;
|
||||
|
||||
if (($sri = ldap_search($this->ds, $this->group_context, '(&('.$attr.'=' . $name . ")(objectclass=posixgroup)$this->group_filter)", array('gidNumber'))) &&
|
||||
($allValues = ldap_get_entries($this->ds, $sri)) &&
|
||||
!empty($allValues[0]['gidnumber'][0]))
|
||||
if (($data = ldap_search($this->group_context, '(&('.$attr.'=' . $name . ")(objectclass=posixgroup)$this->group_filter)", ['gidNumber'])) &&
|
||||
!empty($data['gidnumber'][0]))
|
||||
{
|
||||
return -$allValues[0]['gidnumber'][0];
|
||||
return -$data['gidnumber'][0];
|
||||
}
|
||||
}
|
||||
$to_ldap = array(
|
||||
$to_ldap = [
|
||||
'account_lid' => 'uid',
|
||||
'account_email' => static::MAIL_ATTR,
|
||||
'account_fullname' => 'cn',
|
||||
);
|
||||
'account_uuid' => 'entryuuid',
|
||||
'account_dn' => 'dn',
|
||||
];
|
||||
if (!isset($to_ldap[$which]) || $account_type === 'g')
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
if (($sri = ldap_search($this->ds, $this->user_context, '(&('.$to_ldap[$which].'=' . $name . ')(objectclass=posixaccount))', array('uidNumber'))) &&
|
||||
($allValues = ldap_get_entries($this->ds, $sri)) &&
|
||||
!empty($allValues[0]['uidnumber'][0]))
|
||||
if (($data = $this->_ldap_search($this->user_context, '(&('.$to_ldap[$which].'=' . $name . ')(objectclass=posixaccount))', array('uidNumber'))) &&
|
||||
!empty($data['uidNumber'][0]))
|
||||
{
|
||||
return (int)$allValues[0]['uidnumber'][0];
|
||||
return (int)$data['uidnumber'][0];
|
||||
}
|
||||
return False;
|
||||
}
|
||||
@ -1181,15 +1191,14 @@ class Ldap
|
||||
|
||||
$gid = abs($_gid); // our gid is negative!
|
||||
|
||||
$sri = ldap_search($this->ds,$this->group_context,"(&(objectClass=posixGroup)(gidnumber=$gid))",array('memberuid'));
|
||||
$group = ldap_get_entries($this->ds, $sri);
|
||||
$group = $this->_ldap_search($this->group_context,"(&(objectClass=posixGroup)(gidnumber=$gid))", ['memberuid']);
|
||||
|
||||
$members = array();
|
||||
if (isset($group[0]['memberuid']))
|
||||
if ($group && isset($group['memberuid']))
|
||||
{
|
||||
unset($group[0]['memberuid']['count']);
|
||||
unset($group['memberuid']['count']);
|
||||
|
||||
foreach($group[0]['memberuid'] as $lid)
|
||||
foreach($group['memberuid'] as $lid)
|
||||
{
|
||||
if (($id = $this->name2id($lid, 'account_lid'))) // also return groups!
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user