* LDAP/AD: automatic retry, if connection to LDAP server was lost

This commit is contained in:
ralf 2024-08-09 14:10:23 +02:00
parent 89d4155f23
commit bc582dedfb
2 changed files with 38 additions and 29 deletions

View File

@ -91,7 +91,7 @@ class Import
]; ];
} }
catch (\Exception $e) { catch (\Exception $e) {
$this->logger('Error: '.$e->getMessage(), 'fatal'); $this->logger('Error: '.$e->getMessage().' ('.$e->getCode().')', 'fatal');
throw $e; throw $e;
} }
} }
@ -273,7 +273,6 @@ class Import
$start = ['', 500, &$cookie]; // cookie must be a reference! $start = ['', 500, &$cookie]; // cookie must be a reference!
do do
{ {
$contact = $reconnected = null;
foreach ($this->contacts->search('', false, '', ['account_lid', 'jpegphoto'], '', '', 'AND', $start, $filter) as $contact) foreach ($this->contacts->search('', false, '', ['account_lid', 'jpegphoto'], '', '', 'AND', $start, $filter) as $contact)
{ {
// if we have a regexp to filter the DN, continue on non-match // if we have a regexp to filter the DN, continue on non-match
@ -580,15 +579,8 @@ class Import
// remember the users we imported, to be able to delete the ones we dont // remember the users we imported, to be able to delete the ones we dont
unset($sql_users[$account_id]); unset($sql_users[$account_id]);
} }
/* check if connection was somehow lost / timed out and reconnect
if ($initial_import && !isset($contact) && ldap_errno($this->contacts->ds) === -1)
{
$this->contacts->ds = $this->accounts->ldap_connection(true);
$reconnected = true;
$this->logger("Reconnected to LDAP server", 'info');
}*/
} }
while ($reconnected || $start[2] !== ''); while ($start[2] !== '');
if ($set_members) if ($set_members)
{ {
@ -668,7 +660,8 @@ class Import
} }
} }
catch(\Exception $e) { catch(\Exception $e) {
$this->logger($e->getMessage(), 'fatal'); _egw_log_exception($e);
$this->logger($e->getMessage().' ('.$e->getCode().')', 'fatal');
$GLOBALS['egw']->accounts = $frontend; $GLOBALS['egw']->accounts = $frontend;
throw $e; throw $e;
} }
@ -898,7 +891,7 @@ class Import
} }
} }
catch (\Exception $e) { catch (\Exception $e) {
$this->logger("Error deleting no longer existing $type '$account_lid' (#$account_id): ".$e->getMessage(), 'error'); $this->logger("Error deleting no longer existing $type '$account_lid' (#$account_id): ".$e->getMessage().' ('.$e->getCode().')', 'error');
} }
$GLOBALS['egw']->accounts = $backup_accounts; $GLOBALS['egw']->accounts = $backup_accounts;
@ -1001,11 +994,11 @@ class Import
_egw_log_exception($e); _egw_log_exception($e);
// disable async job, something is not configured correct // disable async job, something is not configured correct
self::installAsyncJob(); self::installAsyncJob();
$import->logger('Async job for periodic import canceled', 'fatal'); $import->logger('Async job for periodic import canceled: '.$e->getMessage().' ('.$e->getCode().')', 'fatal');
} }
catch (\Exception $e) { catch (\Exception $e) {
_egw_log_exception($e); _egw_log_exception($e);
$import->logger('Error: '.$e->getMessage(), 'fatal'); $import->logger('Error: '.$e->getMessage().' ('.$e->getCode().')', 'fatal');
} }
} }

View File

@ -391,30 +391,36 @@ class Ldap
$this->connect(); $this->connect();
} }
/**
* @var bool $admin parameter of last call to connect, to be able to reconnect
*/
protected bool $admin_connection;
/** /**
* connect to LDAP server * connect to LDAP server
* *
* @param boolean $admin =false true (re-)connect with admin not user credentials, eg. to modify accounts * @param boolean $admin =false true (re-)connect with admin not user credentials, eg. to modify accounts
*/ */
function connect($admin = false) function connect($admin = false, $reconnect=false)
{ {
if ($admin) if (($this->admin_connection = $admin))
{ {
$this->ds = Api\Ldap::factory(); $this->ds = Api\Ldap::factory(true, '', '', '', $reconnect);
} }
// if ldap is NOT the contact repository, we only do accounts and need to use the account-data // if ldap is NOT the contact repository, we only do accounts and need to use the account-data
elseif (substr($GLOBALS['egw_info']['server']['contact_repository'],-4) != 'ldap') // not (ldap or sql-ldap) elseif (substr($GLOBALS['egw_info']['server']['contact_repository'],-4) != 'ldap') // not (ldap or sql-ldap)
{ {
$this->ldap_config['ldap_contact_host'] = $this->ldap_config['ldap_host']; $this->ldap_config['ldap_contact_host'] = $this->ldap_config['ldap_host'];
$this->allContactsDN = $this->ldap_config['ldap_context']; $this->allContactsDN = $this->ldap_config['ldap_context'];
$this->ds = Api\Ldap::factory(); $this->ds = Api\Ldap::factory(true, '', '', '', $reconnect);
} }
else else
{ {
$this->ds = Api\Ldap::factory(true, $this->ds = Api\Ldap::factory(true,
$this->ldap_config['ldap_contact_host'], $this->ldap_config['ldap_contact_host'],
$GLOBALS['egw_info']['user']['account_dn'], $GLOBALS['egw_info']['user']['account_dn'],
$GLOBALS['egw_info']['user']['passwd'] $GLOBALS['egw_info']['user']['passwd'],
$reconnect
); );
} }
} }
@ -1273,17 +1279,27 @@ class Ldap
$this->total = 0; $this->total = 0;
} }
if($_addressbooktype == self::ALL || $_ldapContext == $this->allContactsDN) // retry, if connection to LDAP is lost
for($retry=1; $retry >= 0; --$retry)
{ {
$result = ldap_search($this->ds, $_ldapContext, $_filter, $_attributes, null, null, null, null, $control); if ($_addressbooktype == self::ALL || $_ldapContext == $this->allContactsDN)
} {
else $result = ldap_search($this->ds, $_ldapContext, $_filter, $_attributes, null, null, null, null, $control);
{ }
$result = ldap_list($this->ds, $_ldapContext, $_filter, $_attributes, null, null, null, null, $control); else
} {
if(!$result || ($entries = ldap_get_entries($this->ds, $result)) === false) $result = ldap_list($this->ds, $_ldapContext, $_filter, $_attributes, null, null, null, null, $control);
{ }
throw new \Exception(ldap_error($this->ds) ?: 'Unable to retrieve LDAP result', ldap_errno($this->ds)); if (!$result || ($entries = ldap_get_entries($this->ds, $result)) === false)
{
// retry after reconnect, if connection to LDAP server is lost
if ($retry >= 0 && in_array(ldap_errno($this->ds), [91, -1], true))
{
$this->connect($this->admin_connection, true);
continue;
}
throw new \Exception(ldap_error($this->ds) ?: 'Unable to retrieve LDAP result', ldap_errno($this->ds));
}
} }
$this->total += $entries['count']; $this->total += $entries['count'];
//error_log(__METHOD__."('$_ldapContext', '$_filter', ".array2string($_attributes).", $_addressbooktype) result of $entries[count]"); //error_log(__METHOD__."('$_ldapContext', '$_filter', ".array2string($_attributes).", $_addressbooktype) result of $entries[count]");