ILIAS  release_5-1 Revision 5.0.0-5477-g43f3e3fab5f
class.ilLDAPQuery.php
Go to the documentation of this file.
1 <?php
2 /*
3  +-----------------------------------------------------------------------------+
4  | ILIAS open source |
5  +-----------------------------------------------------------------------------+
6  | Copyright (c) 1998-2006 ILIAS open source, University of Cologne |
7  | |
8  | This program is free software; you can redistribute it and/or |
9  | modify it under the terms of the GNU General Public License |
10  | as published by the Free Software Foundation; either version 2 |
11  | of the License, or (at your option) any later version. |
12  | |
13  | This program is distributed in the hope that it will be useful, |
14  | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16  | GNU General Public License for more details. |
17  | |
18  | You should have received a copy of the GNU General Public License |
19  | along with this program; if not, write to the Free Software |
20  | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
21  +-----------------------------------------------------------------------------+
22 */
23 
24 define('IL_LDAP_BIND_DEFAULT',0);
25 define('IL_LDAP_BIND_ADMIN',1);
26 define('IL_LDAP_BIND_TEST',2);
27 
28 include_once('Services/LDAP/classes/class.ilLDAPAttributeMapping.php');
29 include_once('Services/LDAP/classes/class.ilLDAPResult.php');
30 include_once('Services/LDAP/classes/class.ilLDAPQueryException.php');
31 
42 {
43  private $ldap_server_url = null;
44  private $settings = null;
45  private $log = null;
46 
47  private $user_fields = array();
48 
57  public function __construct(ilLDAPServer $a_server,$a_url = '')
58  {
59  global $ilLog;
60 
61  $this->settings = $a_server;
62 
63  if(strlen($a_url))
64  {
65  $this->ldap_server_url = $a_url;
66  }
67  else
68  {
69  $this->ldap_server_url = $this->settings->getUrl();
70  }
71 
72  $this->mapping = ilLDAPAttributeMapping::_getInstanceByServerId($this->settings->getServerId());
73  $this->log = ilLoggerFactory::getLogger('auth');
74 
75  $this->fetchUserProfileFields();
76  $this->connect();
77  }
78 
79  // begin-patch ldap_multiple
84  public function getServer()
85  {
86  return $this->settings;
87  }
88 
96  public function fetchUser($a_name)
97  {
98  $this->user_fields = array_merge(array($this->settings->getUserAttribute()),$this->mapping->getFields());
99 
100  if(!$this->readUserData($a_name))
101  {
102  return array();
103  }
104  else
105  {
106  return $this->users;
107  }
108  }
109 
110 
117  public function fetchUsers()
118  {
119  // First of all check if a group restriction is enabled
120  // YES: => fetch all group members
121  // No: => fetch all users
122  if(strlen($this->settings->getGroupName()))
123  {
124  $this->log->debug('Searching for group members.');
125 
126  $groups = $this->settings->getGroupNames();
127  if(count($groups) <= 1)
128  {
129  $this->fetchGroupMembers();
130  }
131  else
132  {
133  foreach($groups as $group)
134  {
135  $this->fetchGroupMembers($group);
136  }
137  }
138 
139  }
140  if(!strlen($this->settings->getGroupName()) or $this->settings->isMembershipOptional())
141  {
142  $this->log->info('Start reading all users...');
143  $this->readAllUsers();
144  #throw new ilLDAPQueryException('LDAP: Called import of users without specifying group restrictions. NOT IMPLEMENTED YET!');
145  }
146  return $this->users ? $this->users : array();
147  }
148 
160  public function query($a_search_base,$a_filter,$a_scope,$a_attributes)
161  {
162  $res = $this->queryByScope($a_scope,$a_search_base,$a_filter,$a_attributes);
163  if($res === false)
164  {
165  throw new ilLDAPQueryException(__METHOD__.' '.ldap_error($this->lh).' '.
166  sprintf('DN: %s, Filter: %s, Scope: %s',
167  $a_search_base,
168  $a_filter,
169  $a_scope));
170  }
171  return new ilLDAPResult($this->lh,$res);
172  }
173 
180  public function modAdd($a_dn,$a_attribute)
181  {
182  if(@ldap_mod_add($this->lh,$a_dn,$a_attribute))
183  {
184  return true;
185  }
186  throw new ilLDAPQueryException(__METHOD__.' '.ldap_error($this->lh));
187  }
188 
195  public function modDelete($a_dn,$a_attribute)
196  {
197  if(@ldap_mod_del($this->lh,$a_dn,$a_attribute))
198  {
199  return true;
200  }
201  throw new ilLDAPQueryException(__METHOD__.' '.ldap_error($this->lh));
202  }
203 
212  private function readAllUsers()
213  {
214  // Build search base
215  if(($dn = $this->settings->getSearchBase()) && substr($dn,-1) != ',')
216  {
217  $dn .= ',';
218  }
219  $dn .= $this->settings->getBaseDN();
220 
221  // page results
222  $filter = $this->settings->getFilter();
223  $page_filter = array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','-');
224  $chars = array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z');
225 
226  foreach($page_filter as $letter)
227  {
228  $new_filter = '(&';
229  $new_filter .= $filter;
230 
231  switch($letter)
232  {
233  case '-':
234  $new_filter .= ('(!(|');
235  foreach($chars as $char)
236  {
237  $new_filter .= ('('.$this->settings->getUserAttribute().'='.$char.'*)');
238  }
239  $new_filter .= ')))';
240  break;
241 
242  default:
243  $new_filter .= ('('.$this->settings->getUserAttribute().'='.$letter.'*))');
244  break;
245  }
246 
247  $this->log->info('Searching with ldap search and filter '.$new_filter.' in '.$dn);
248  $res = $this->queryByScope($this->settings->getUserScope(),
249  $dn,
250  $new_filter,
251  array($this->settings->getUserAttribute()));
252 
253  $tmp_result = new ilLDAPResult($this->lh,$res);
254  if(!$tmp_result->numRows())
255  {
256  $this->log->notice('No users found. Aborting.');
257  continue;
258  }
259  $this->log->info('Found '.$tmp_result->numRows().' users.');
260  $attribute = strtolower($this->settings->getUserAttribute());
261  foreach($tmp_result->getRows() as $data)
262  {
263  if(isset($data[$attribute]))
264  {
265  $this->readUserData($data[$attribute],false,false);
266  }
267  else
268  {
269  $this->log->warning('Unknown error. No user attribute found.');
270  }
271  }
272  unset($tmp_result);
273  }
274  return true;
275  }
276 
277 
284  private function fetchGroupMembers($a_name = '')
285  {
286  $group_name = strlen($a_name) ? $a_name : $this->settings->getGroupName();
287 
288  // Build filter
289  $filter = sprintf('(&(%s=%s)%s)',
290  $this->settings->getGroupAttribute(),
291  $group_name,
292  $this->settings->getGroupFilter());
293 
294 
295  // Build search base
296  if(($gdn = $this->settings->getGroupDN()) && substr($gdn,-1) != ',')
297  {
298  $gdn .= ',';
299  }
300  $gdn .= $this->settings->getBaseDN();
301 
302  $this->log->debug('Using filter '.$filter);
303  $this->log->debug('Using DN '.$gdn);
304  $res = $this->queryByScope($this->settings->getGroupScope(),
305  $gdn,
306  $filter,
307  array($this->settings->getGroupMember()));
308 
309  $tmp_result = new ilLDAPResult($this->lh,$res);
310  $group_data = $tmp_result->getRows();
311 
312 
313  if(!$tmp_result->numRows())
314  {
315  $this->log->info('No group found.');
316  return false;
317  }
318 
319  $attribute_name = strtolower($this->settings->getGroupMember());
320 
321  // All groups
322  foreach($group_data as $data)
323  {
324  $this->log->debug('Found '.count($data[$attribute_name]).' group members for group '.$data['dn']);
325  if(is_array($data[$attribute_name]))
326  {
327  foreach($data[$attribute_name] as $name)
328  {
329  $this->readUserData($name,true,true);
330  }
331  }
332  else
333  {
334  $this->readUserData($data[$attribute_name],true,true);
335  }
336  }
337  unset($tmp_result);
338  return;
339  }
340 
347  private function readUserData($a_name,$a_check_dn = true,$a_try_group_user_filter = false)
348  {
349  $filter = $this->settings->getFilter();
350  if($a_try_group_user_filter)
351  {
352  if($this->settings->isMembershipOptional())
353  {
354  $filter = $this->settings->getGroupUserFilter();
355  }
356  }
357 
358  // Build filter
359  if($this->settings->enabledGroupMemberIsDN() and $a_check_dn)
360  {
361  $dn = $a_name;
362  #$res = $this->queryByScope(IL_LDAP_SCOPE_BASE,$dn,$filter,$this->user_fields);
363 
364  $fields = array_merge($this->user_fields,array('useraccountcontrol'));
365  $res = $this->queryByScope(IL_LDAP_SCOPE_BASE,strtolower($dn),$filter,$fields);
366  }
367  else
368  {
369  $filter = sprintf('(&(%s=%s)%s)',
370  $this->settings->getUserAttribute(),
371  $a_name,
372  $filter);
373 
374  // Build search base
375  if(($dn = $this->settings->getSearchBase()) && substr($dn,-1) != ',')
376  {
377  $dn .= ',';
378  }
379  $dn .= $this->settings->getBaseDN();
380  $fields = array_merge($this->user_fields,array('useraccountcontrol'));
381  $res = $this->queryByScope($this->settings->getUserScope(),strtolower($dn),$filter,$fields);
382  }
383 
384 
385  $tmp_result = new ilLDAPResult($this->lh,$res);
386  if(!$tmp_result->numRows())
387  {
388  $this->log->info('LDAP: No user data found for: '.$a_name);
389  unset($tmp_result);
390  return false;
391  }
392 
393  if($user_data = $tmp_result->get())
394  {
395  if(isset($user_data['useraccountcontrol']))
396  {
397  if(($user_data['useraccountcontrol'] & 0x02))
398  {
399  $this->log->notice('LDAP: '.$a_name.' account disabled.');
400  return;
401  }
402  }
403 
404  $user_ext = $user_data[strtolower($this->settings->getUserAttribute())];
405 
406  // auth mode depends on ldap server settings
407  $auth_mode = $this->settings->getAuthenticationMappingKey();
408  $user_data['ilInternalAccount'] = ilObjUser::_checkExternalAuthAccount($auth_mode,$user_ext);
409  $this->users[$user_ext] = $user_data;
410  }
411  return true;
412  }
413 
418  private function parseAuthMode()
419  {
420  return $this->settings->getAuthenticationMappingKey();
421  }
422 
432  private function queryByScope($a_scope,$a_base_dn,$a_filter,$a_attributes)
433  {
434  $a_filter = $a_filter ? $a_filter : "(objectclass=*)";
435 
436  switch($a_scope)
437  {
438  case IL_LDAP_SCOPE_SUB:
439  $res = @ldap_search($this->lh,$a_base_dn,$a_filter,$a_attributes);
440  break;
441 
442  case IL_LDAP_SCOPE_ONE:
443  $res = @ldap_list($this->lh,$a_base_dn,$a_filter,$a_attributes);
444  break;
445 
446  case IL_LDAP_SCOPE_BASE:
447 
448  $res = @ldap_read($this->lh,$a_base_dn,$a_filter,$a_attributes);
449  break;
450 
451  default:
452  $this->log->warning("LDAP: LDAPQuery: Unknown search scope");
453  }
454 
455  return $res;
456 
457  }
458 
466  private function connect()
467  {
468  $this->lh = @ldap_connect($this->ldap_server_url);
469 
470  // LDAP Connect
471  if(!$this->lh)
472  {
473  throw new ilLDAPQueryException("LDAP: Cannot connect to LDAP Server: ".$this->settings->getUrl());
474  }
475  // LDAP Version
476  if(!ldap_set_option($this->lh,LDAP_OPT_PROTOCOL_VERSION,$this->settings->getVersion()))
477  {
478  throw new ilLDAPQueryException("LDAP: Cannot set version to: ".$this->settings->getVersion());
479  }
480  // Switch on referrals
481  if($this->settings->isActiveReferrer())
482  {
483  if(!ldap_set_option($this->lh,LDAP_OPT_REFERRALS,true))
484  {
485  throw new ilLDAPQueryException("LDAP: Cannot switch on LDAP referrals");
486  }
487  #@ldap_set_rebind_proc($this->lh,'referralRebind');
488  }
489  else
490  {
491  ldap_set_option($this->lh,LDAP_OPT_REFERRALS,false);
492  $this->log->debug('Switching referrals to false.');
493  }
494  // Start TLS
495  if($this->settings->isActiveTLS())
496  {
497  if(!ldap_start_tls($this->lh))
498  {
499  throw new ilLDAPQueryException("LDAP: Cannot start LDAP TLS");
500  }
501  }
502  }
503 
512  public function bind($a_binding_type = IL_LDAP_BIND_DEFAULT,$a_user_dn = '',$a_password = '')
513  {
514  switch($a_binding_type)
515  {
516  case IL_LDAP_BIND_TEST:
517  ldap_set_option($this->lh, LDAP_OPT_NETWORK_TIMEOUT, ilLDAPServer::DEFAULT_NETWORK_TIMEOUT);
518  // fall through
520  // Now bind anonymously or as user
521  if(
522  IL_LDAP_BIND_USER == $this->settings->getBindingType() &&
523  strlen($this->settings->getBindUser())
524  )
525  {
526  $user = $this->settings->getBindUser();
527  $pass = $this->settings->getBindPassword();
528 
529  define('IL_LDAP_REBIND_USER',$user);
530  define('IL_LDAP_REBIND_PASS',$pass);
531  $this->log->debug('Bind as '.$user);
532  }
533  else
534  {
535  $user = $pass = '';
536  $this->log->debug('Bind anonymous');
537  }
538  break;
539 
540  case IL_LDAP_BIND_ADMIN:
541  $user = $this->settings->getRoleBindDN();
542  $pass = $this->settings->getRoleBindPassword();
543 
544  if(!strlen($user) or !strlen($pass))
545  {
546  $user = $this->settings->getBindUser();
547  $pass = $this->settings->getBindPassword();
548  }
549 
550  define('IL_LDAP_REBIND_USER',$user);
551  define('IL_LDAP_REBIND_PASS',$pass);
552  break;
553 
554  default:
555  throw new ilLDAPQueryException('LDAP: unknown binding type in: '.__METHOD__);
556  }
557 
558  if(!@ldap_bind($this->lh,$user,$pass))
559  {
560  throw new ilLDAPQueryException('LDAP: Cannot bind as '.$user.' with message: '. ldap_err2str(ldap_errno($this->lh)).' Trying fallback...', ldap_errno($this->lh));
561  }
562  else
563  {
564  $this->log->debug('Bind successful.');
565  }
566  }
567 
575  private function fetchUserProfileFields()
576  {
577  include_once('Services/LDAP/classes/class.ilLDAPRoleAssignmentRules.php');
578 
579  $this->user_fields = array_merge(
580  array($this->settings->getUserAttribute()),
581  array('dn'),
582  $this->mapping->getFields(),
584  );
585  }
586 
587 
595  private function unbind()
596  {
597  if($this->lh)
598  {
599  @ldap_unbind($this->lh);
600  }
601  }
602 
603 
611  public function __destruct()
612  {
613  if($this->lh)
614  {
615  @ldap_unbind($this->lh);
616  }
617  }
618 }
619 
620 function referralRebind($a_ds,$a_url)
621 {
622  global $ilLog;
623 
624  $ilLog->write('LDAP: Called referralRebind.');
625 
626  ldap_set_option($a_ds, LDAP_OPT_PROTOCOL_VERSION, 3);
627 
628  if (!ldap_bind($a_ds,IL_LDAP_REBIND_USER,IL_LDAP_REBIND_PASS))
629  {
630  $ilLog->write('LDAP: Rebind failed');
631  }
632 }
633 
634 ?>
const IL_LDAP_BIND_USER
fetchUsers()
Fetch all users.
modAdd($a_dn, $a_attribute)
Add value to an existing attribute.
static _getInstanceByServerId($a_server_id)
Get instance of class.
readUserData($a_name, $a_check_dn=true, $a_try_group_user_filter=false)
Read user data.
const IL_LDAP_BIND_DEFAULT
const IL_LDAP_SCOPE_SUB
__construct(ilLDAPServer $a_server, $a_url='')
Constructur.
connect()
Connect to LDAP server.
static getAttributeNames($a_server_id)
get all possible attribute names
const IL_LDAP_BIND_TEST
readAllUsers()
Fetch all users This function splits the query to filters like e.g (uid=a*) (uid=b*)...
fetchGroupMembers($a_name='')
Fetch group member ids.
const DEFAULT_NETWORK_TIMEOUT
parseAuthMode()
Parse authentication mode.
$data
query($a_search_base, $a_filter, $a_scope, $a_attributes)
Perform a query.
fetchUserProfileFields()
fetch required fields of user profile data
referralRebind($a_ds, $a_url)
getServer()
Get server.
fetchUser($a_name)
Get one user by login name.
const IL_LDAP_SCOPE_ONE
modDelete($a_dn, $a_attribute)
Delete value from an existing attribute.
const IL_LDAP_BIND_ADMIN
__destruct()
Destructor unbind from ldap server.
static _checkExternalAuthAccount($a_auth, $a_account)
check whether external account and authentication method matches with a user
static getLogger($a_component_id)
Get component logger.
bind($a_binding_type=IL_LDAP_BIND_DEFAULT, $a_user_dn='', $a_password='')
Bind to LDAP server.
const IL_LDAP_SCOPE_BASE
queryByScope($a_scope, $a_base_dn, $a_filter, $a_attributes)
Query by scope IL_SCOPE_SUB => ldap_search IL_SCOPE_ONE => ldap_list.