egroupware/addressbook/inc/class.addressbook_ads.inc.php

219 lines
6.7 KiB
PHP

<?php
/**
* Addressbook - ADS Backend
*
* @link http://www.egroupware.org
* @author Ralf Becker <rb@stylite.de>
* @package addressbook
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/
/**
* Active directory backend for accounts (not yet AD contacts)
*
* We use ADS string representation of objectGUID as contact ID and UID.
*
* Unfortunatly Samba4 and active directory of win2008r2 differn on how to search for an objectGUID:
* - Samba4 can only search for string representation eg. (objectGUID=2336A3FC-EDBD-42A2-9EEB-BD7A5DD2804E)
* - win2008r2 can only search for hex representation eg. (objectGUID=\FC\A3\36\23\BD\ED\A2\42\9E\EB\BD\7A\5D\D2\80\4E)
* We could use both filters or-ed together, for now we detect Samba4 and use string GUID for it.
*
* All values used to construct filters need to run through ldap::quote(),
* to be save against LDAP query injection!!!
*/
class addressbook_ads extends addressbook_ldap
{
/**
* LDAP searches only a limited set of attributes for performance reasons,
* you NEED an index for that columns, ToDo: make it configurable
* minimum: $this->columns_to_search = array('n_family','n_given','org_name','email');
*/
var $search_attributes = array(
'n_family','n_middle','n_given','org_name','org_unit',
'adr_one_location','note','email','samaccountname',
);
/**
* Filter used for accounts addressbook
* @var string
*/
var $accountsFilter = '(objectCategory=person)';
/**
* Attribute used for DN
*
* @var string
*/
var $dn_attribute='cn';
/**
* Do NOT attempt to change DN (dn-attribute can NOT be part of schemas used in addressbook!)
*
* Set here to true, as accounts can be stored in different containers and CN is not used as n_fn (displayName is)
*
* @var boolean
*/
var $never_change_dn = true;
/**
* Accounts ADS object
*
* @var accounts_ads
*/
protected $accounts_ads;
/**
* ADS is Samba4 (true), otherwise false
*
* @var boolean
*/
public $is_samba4 = false;
/**
* constructor of the class
*
* @param array $ldap_config=null default use from $GLOBALS['egw_info']['server']
* @param resource $ds=null ldap connection to use
*/
function __construct(array $ldap_config=null, $ds=null)
{
$this->accountName = $GLOBALS['egw_info']['user']['account_lid'];
if ($ldap_config)
{
$this->ldap_config = $ldap_config;
}
else
{
$this->ldap_config =& $GLOBALS['egw_info']['server'];
}
$this->accounts_ads = $GLOBALS['egw']->accounts->backend;
//$this->personalContactsDN = 'ou=personal,ou=contacts,'. $this->ldap_config['ldap_contact_context'];
//$this->sharedContactsDN = 'ou=shared,ou=contacts,'. $this->ldap_config['ldap_contact_context'];
$this->allContactsDN = $this->accountContactsDN = $this->accounts_ads->ads_context();
if ($ds)
{
$this->ds = $ds;
}
else
{
$this->connect();
}
$this->ldapServerInfo = ldapserverinfo::get($this->ds, $this->ldap_config['ads_host']);
$this->is_samba4 = $this->ldapServerInfo->serverType == SAMBA4_LDAPSERVER;
// AD seems to use user, instead of inetOrgPerson
unset($this->schema2egw['posixaccount']);
$this->schema2egw['user'] = array_merge($this->schema2egw['inetorgperson'], array(
'account_id' => 'objectsid',
'id' => 'objectguid',
'uid' => 'objectguid',
'n_fn' => 'displayname', // leave CN used in DN untouched
'accountexpires', 'useraccountcontrol', // needed to exclude deactivated or expired accounts
));
unset($this->schema2egw['user']['n_fileas']);
unset($this->schema2egw['inetorgperson']);
foreach($this->schema2egw as $schema => $attributes)
{
$this->all_attributes = array_merge($this->all_attributes,array_values($attributes));
}
$this->all_attributes = array_values(array_unique($this->all_attributes));
$this->charset = translation::charset();
}
/**
* connect to LDAP server
*
* @param boolean $admin=false true (re-)connect with admin not user credentials, eg. to modify accounts
*/
function connect($admin=false)
{
$this->ds = $this->accounts_ads->ldap_connection();
}
/**
* Return LDAP filter for contact id
*
* @param string $contact_id
* @return string
*/
protected function id_filter($contact_id)
{
// check that GUID eg. from URL contains only valid hex characters and dash
// we cant use ldap::quote() for win2008r2 hex GUID, as it contains backslashes
if (!preg_match('/^[0-9A-Fa-f-]+/', $contact_id))
{
throw new egw_exception_assertion_failed("'$contact_id' is NOT a valid GUID!");
}
// samba4 can only search by string representation of objectGUID, while win2008r2 requires hex representation
return '(objectguid='.($this->is_samba4 ? $contact_id : $this->accounts_ads->objectguid2hex($contact_id)).')';
}
/**
* reads contact data
*
* @param string/array $contact_id contact_id or array with values for id or account_id
* @return array/boolean data if row could be retrived else False
*/
function read($contact_id)
{
if (is_array($contact_id) && isset($contact_id['account_id']) ||
!is_array($contact_id) && substr($contact_id,0,8) == 'account:')
{
$account_id = (int)(is_array($contact_id) ? $contact_id['account_id'] : substr($contact_id,8));
$contact_id = $GLOBALS['egw']->accounts->id2name($account_id, 'person_id');
}
$contact_id = !is_array($contact_id) ? $contact_id :
(isset ($contact_id['id']) ? $contact_id['id'] : $contact_id['uid']);
$rows = $this->_searchLDAP($this->allContactsDN, $filter=$this->id_filter($contact_id), $this->all_attributes, ADDRESSBOOK_ALL);
//error_log(__METHOD__."('$contact_id') _searchLDAP($this->allContactsDN, '$filter',...)=".array2string($rows));
return $rows ? $rows[0] : false;
}
/**
* Special handling for mapping data of ADA user objectclass to eGW contact
*
* Please note: all regular fields are already copied!
*
* @internal
* @param array &$contact already copied fields according to the mapping
* @param array $data eGW contact data
*/
function _user2egw(&$contact, $data)
{
$contact['account_id'] = $this->accounts_ads->objectsid2account_id($data['objectsid']);
$contact['id'] = $contact['uid'] = $this->accounts_ads->objectguid2str($data['objectguid']);
// ignore system accounts
if ($contact['account_id'] < accounts_ads::MIN_ACCOUNT_ID) return false;
// ignore deactivated or expired accounts
if (!$this->accounts_ads->user_active($data)) return false;
$this->_inetorgperson2egw($contact, $data, 'displayname');
}
/**
* Remove attributes we are not allowed to update
*
* @param array $attributes
*/
function sanitize_update(array &$ldapContact)
{
// not allowed and not need to update these in AD
unset($ldapContact['objectguid']);
unset($ldapContact['objectsid']);
parent::sanitize_update($ldapContact);
}
}