ILIAS  Release_4_1_x_branch Revision 61804
 All Data Structures Namespaces Files Functions Variables Groups Pages
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 = $ilLog;
74 
75  $this->fetchUserProfileFields();
76  $this->connect();
77  }
78 
86  public function fetchUser($a_name)
87  {
88  $this->user_fields = array_merge(array($this->settings->getUserAttribute()),$this->mapping->getFields());
89 
90  if(!$this->readUserData($a_name))
91  {
92  return array();
93  }
94  else
95  {
96  return $this->users;
97  }
98  }
99 
100 
107  public function fetchUsers()
108  {
109  // First of all check if a group restriction is enabled
110  // YES: => fetch all group members
111  // No: => fetch all users
112  if(strlen($this->settings->getGroupName()))
113  {
114  $this->log->write(__METHOD__.': Searching for group members.');
115 
116  $groups = $this->settings->getGroupNames();
117  if(count($groups) <= 1)
118  {
119  $this->fetchGroupMembers();
120  }
121  else
122  {
123  foreach($groups as $group)
124  {
125  $this->fetchGroupMembers($group);
126  }
127  }
128 
129  }
130  if(!strlen($this->settings->getGroupName()) or $this->settings->isMembershipOptional())
131  {
132  $this->log->write(__METHOD__.': Start reading all users...');
133  $this->readAllUsers();
134  #throw new ilLDAPQueryException('LDAP: Called import of users without specifying group restrictions. NOT IMPLEMENTED YET!');
135  }
136  return $this->users ? $this->users : array();
137  }
138 
150  public function query($a_search_base,$a_filter,$a_scope,$a_attributes)
151  {
152  $res = $this->queryByScope($a_scope,$a_search_base,$a_filter,$a_attributes);
153  if($res === false)
154  {
155  throw new ilLDAPQueryException(__METHOD__.' '.ldap_error($this->lh).' '.
156  sprintf('DN: %s, Filter: %s, Scope: %s',
157  $a_search_base,
158  $a_filter,
159  $a_scope));
160  }
161  return new ilLDAPResult($this->lh,$res);
162  }
163 
170  public function modAdd($a_dn,$a_attribute)
171  {
172  if(@ldap_mod_add($this->lh,$a_dn,$a_attribute))
173  {
174  return true;
175  }
176  throw new ilLDAPQueryException(__METHOD__.' '.ldap_error($this->lh));
177  }
178 
185  public function modDelete($a_dn,$a_attribute)
186  {
187  if(@ldap_mod_del($this->lh,$a_dn,$a_attribute))
188  {
189  return true;
190  }
191  throw new ilLDAPQueryException(__METHOD__.' '.ldap_error($this->lh));
192  }
193 
202  private function readAllUsers()
203  {
204  // Build search base
205  if(($dn = $this->settings->getSearchBase()) && substr($dn,-1) != ',')
206  {
207  $dn .= ',';
208  }
209  $dn .= $this->settings->getBaseDN();
210 
211  // page results
212  $filter = $this->settings->getFilter();
213  $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','-');
214  $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');
215 
216  foreach($page_filter as $letter)
217  {
218  $new_filter = '(&';
219  $new_filter .= $filter;
220 
221  switch($letter)
222  {
223  case '-':
224  $new_filter .= ('(!(|');
225  foreach($chars as $char)
226  {
227  $new_filter .= ('('.$this->settings->getUserAttribute().'='.$char.'*)');
228  }
229  $new_filter .= ')))';
230  break;
231 
232  default:
233  $new_filter .= ('('.$this->settings->getUserAttribute().'='.$letter.'*))');
234  break;
235  }
236 
237  $this->log->write(__METHOD__.': Searching with ldap search and filter '.$new_filter.' in '.$dn);
238  $res = $this->queryByScope($this->settings->getUserScope(),
239  $dn,
240  $new_filter,
241  array($this->settings->getUserAttribute()));
242 
243  $tmp_result = new ilLDAPResult($this->lh,$res);
244  if(!$tmp_result->numRows())
245  {
246  $this->log->write(__METHOD__.': No users found. Aborting.');
247  continue;
248  }
249  $this->log->write(__METHOD__.': Found '.$tmp_result->numRows().' users.');
250  foreach($tmp_result->getRows() as $data)
251  {
252  if(isset($data[$this->settings->getUserAttribute()]))
253  {
254  $this->readUserData($data[$this->settings->getUserAttribute()],false,false);
255  }
256  else
257  {
258  $this->log->write(__METHOD__.': Unknown error. No user attribute found.');
259  }
260  }
261  unset($tmp_result);
262  }
263  return true;
264  }
265 
266 
273  private function fetchGroupMembers($a_name = '')
274  {
275  $group_name = strlen($a_name) ? $a_name : $this->settings->getGroupName();
276 
277  // Build filter
278  $filter = sprintf('(&(%s=%s)%s)',
279  $this->settings->getGroupAttribute(),
280  $group_name,
281  $this->settings->getGroupFilter());
282 
283 
284  // Build search base
285  if(($gdn = $this->settings->getGroupDN()) && substr($gdn,-1) != ',')
286  {
287  $gdn .= ',';
288  }
289  $gdn .= $this->settings->getBaseDN();
290 
291  $this->log->write('LDAP: Using filter '.$filter);
292  $this->log->write('LDAP: Using DN '.$gdn);
293  $res = $this->queryByScope($this->settings->getGroupScope(),
294  $gdn,
295  $filter,
296  array($this->settings->getGroupMember()));
297 
298  $tmp_result = new ilLDAPResult($this->lh,$res);
299  $group_data = $tmp_result->getRows();
300 
301 
302  if(!$tmp_result->numRows())
303  {
304  $this->log->write(__METHOD__.': No group found.');
305  return false;
306  }
307 
308  $attribute_name = strtolower($this->settings->getGroupMember());
309 
310  // All groups
311  foreach($group_data as $data)
312  {
313  $this->log->write(__METHOD__.': found '.count($data[$attribute_name]).' group members for group '.$data['dn']);
314  if(is_array($data[$attribute_name]))
315  {
316  foreach($data[$attribute_name] as $name)
317  {
318  $this->readUserData($name,true,true);
319  }
320  }
321  else
322  {
323  $this->readUserData($data[$attribute_name],true,true);
324  }
325  }
326  unset($tmp_result);
327  return;
328  }
329 
336  private function readUserData($a_name,$a_check_dn = true,$a_try_group_user_filter = false)
337  {
338  $filter = $this->settings->getFilter();
339  if($a_try_group_user_filter)
340  {
341  if($this->settings->isMembershipOptional())
342  {
343  $filter = $this->settings->getGroupUserFilter();
344  }
345  }
346 
347  // Build filter
348  if($this->settings->enabledGroupMemberIsDN() and $a_check_dn)
349  {
350  $dn = $a_name;
351  #$res = $this->queryByScope(IL_LDAP_SCOPE_BASE,$dn,$filter,$this->user_fields);
352 
353  $fields = array_merge($this->user_fields,array('useraccountcontrol'));
354  $res = $this->queryByScope(IL_LDAP_SCOPE_BASE,strtolower($dn),$filter,$fields);
355  }
356  else
357  {
358  $filter = sprintf('(&(%s=%s)%s)',
359  $this->settings->getUserAttribute(),
360  $a_name,
361  $filter);
362 
363  // Build search base
364  if(($dn = $this->settings->getSearchBase()) && substr($dn,-1) != ',')
365  {
366  $dn .= ',';
367  }
368  $dn .= $this->settings->getBaseDN();
369  $fields = array_merge($this->user_fields,array('useraccountcontrol'));
370  $res = $this->queryByScope($this->settings->getUserScope(),strtolower($dn),$filter,$fields);
371  }
372 
373 
374  $tmp_result = new ilLDAPResult($this->lh,$res);
375  if(!$tmp_result->numRows())
376  {
377  $this->log->write('LDAP: No user data found for: '.$a_name);
378  unset($tmp_result);
379  return false;
380  }
381 
382  if($user_data = $tmp_result->get())
383  {
384  if(isset($user_data['useraccountcontrol']))
385  {
386  if(($user_data['useraccountcontrol'] & 0x02))
387  {
388  $this->log->write(__METHOD__.': '.$a_name.' account disabled.');
389  return;
390  }
391  }
392 
393  $user_ext = $user_data[strtolower($this->settings->getUserAttribute())];
394  $user_data['ilInternalAccount'] = ilObjUser::_checkExternalAuthAccount('ldap',$user_ext);
395  $this->users[$user_ext] = $user_data;
396  }
397  return true;
398  }
399 
409  private function queryByScope($a_scope,$a_base_dn,$a_filter,$a_attributes)
410  {
411  $a_filter = $a_filter ? $a_filter : "(objectclass=*)";
412 
413  switch($a_scope)
414  {
415  case IL_LDAP_SCOPE_SUB:
416  $res = @ldap_search($this->lh,$a_base_dn,$a_filter,$a_attributes);
417  break;
418 
419  case IL_LDAP_SCOPE_ONE:
420  $res = @ldap_list($this->lh,$a_base_dn,$a_filter,$a_attributes);
421  break;
422 
423  case IL_LDAP_SCOPE_BASE:
424 
425  $res = ldap_read($this->lh,$a_base_dn,$a_filter,$a_attributes);
426  break;
427 
428  default:
429  $this->log->write("LDAP: LDAPQuery: Unknown search scope");
430  }
431 
432  return $res;
433 
434  }
435 
443  private function connect()
444  {
445  $this->lh = @ldap_connect($this->ldap_server_url);
446 
447  // LDAP Connect
448  if(!$this->lh)
449  {
450  throw new ilLDAPQueryException("LDAP: Cannot connect to LDAP Server: ".$this->settings->getUrl());
451  }
452  // LDAP Version
453  if(!ldap_set_option($this->lh,LDAP_OPT_PROTOCOL_VERSION,$this->settings->getVersion()))
454  {
455  throw new ilLDAPQueryException("LDAP: Cannot set version to: ".$this->settings->getVersion());
456  }
457  // Switch on referrals
458  if($this->settings->isActiveReferrer())
459  {
460  if(!ldap_set_option($this->lh,LDAP_OPT_REFERRALS,true))
461  {
462  throw new ilLDAPQueryException("LDAP: Cannot switch on LDAP referrals");
463  }
464  #@ldap_set_rebind_proc($this->lh,'referralRebind');
465  }
466  else
467  {
468  ldap_set_option($this->lh,LDAP_OPT_REFERRALS,false);
469  $this->log->write(__METHOD__.': Switching referrals to false.');
470  }
471  // Start TLS
472  if($this->settings->isActiveTLS())
473  {
474  if(!ldap_start_tls($this->lh))
475  {
476  throw new ilLDAPQueryException("LDAP: Cannot start LDAP TLS");
477  }
478  }
479  }
480 
489  public function bind($a_binding_type = IL_LDAP_BIND_DEFAULT,$a_user_dn = '',$a_password = '')
490  {
491  switch($a_binding_type)
492  {
494  // Now bind anonymously or as user
495  if(strlen($this->settings->getBindUser()))
496  {
497  $user = $this->settings->getBindUser();
498  $pass = $this->settings->getBindPassword();
499 
500  define('IL_LDAP_REBIND_USER',$user);
501  define('IL_LDAP_REBIND_PASS',$pass);
502  $this->log->write(__METHOD__.': Bind as '.$user);
503  }
504  else
505  {
506  $user = $pass = '';
507  $this->log->write(__METHOD__.': Bind anonymous');
508  }
509  break;
510 
511  case IL_LDAP_BIND_ADMIN:
512  $user = $this->settings->getRoleBindDN();
513  $pass = $this->settings->getRoleBindPassword();
514 
515  if(!strlen($user) or !strlen($pass))
516  {
517  $user = $this->settings->getBindUser();
518  $pass = $this->settings->getBindPassword();
519  }
520 
521  define('IL_LDAP_REBIND_USER',$user);
522  define('IL_LDAP_REBIND_PASS',$pass);
523  break;
524 
525  case IL_LDAP_BIND_TEST:
526  if(!@ldap_bind($this->lh,$a_user_dn,$a_password))
527  {
528  return false;
529  }
530  return true;
531 
532  default:
533  throw new ilLDAPQueryException('LDAP: unknown binding type in: '.__METHOD__);
534  }
535 
536  if(!@ldap_bind($this->lh,$user,$pass))
537  {
538  throw new ilLDAPQueryException('LDAP: Cannot bind as '.$user);
539  }
540  else
541  {
542  $this->log->write(__METHOD__.': Bind successful.');
543  }
544  }
545 
553  private function fetchUserProfileFields()
554  {
555  include_once('Services/LDAP/classes/class.ilLDAPRoleAssignmentRules.php');
556 
557  $this->user_fields = array_merge(
558  array($this->settings->getUserAttribute()),
559  array('dn'),
560  $this->mapping->getFields(),
562  );
563  }
564 
565 
573  private function unbind()
574  {
575  if($this->lh)
576  {
577  @ldap_unbind($this->lh);
578  }
579  }
580 
581 
589  public function __destruct()
590  {
591  if($this->lh)
592  {
593  @ldap_unbind($this->lh);
594  }
595  }
596 }
597 
598 function referralRebind($a_ds,$a_url)
599 {
600  global $ilLog;
601 
602  $ilLog->write('LDAP: Called referralRebind.');
603 
604  ldap_set_option($a_ds, LDAP_OPT_PROTOCOL_VERSION, 3);
605 
606  if (!ldap_bind($a_ds,IL_LDAP_REBIND_USER,IL_LDAP_REBIND_PASS))
607  {
608  $ilLog->write('LDAP: Rebind failed');
609  }
610 }
611 
612 ?>