ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
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
24define('IL_LDAP_BIND_DEFAULT',0);
25define('IL_LDAP_BIND_ADMIN',1);
26define('IL_LDAP_BIND_TEST',2);
27define('IL_LDAP_BIND_AUTH', 10);
28
29include_once('Services/LDAP/classes/class.ilLDAPAttributeMapping.php');
30include_once('Services/LDAP/classes/class.ilLDAPResult.php');
31include_once('Services/LDAP/classes/class.ilLDAPQueryException.php');
32
43{
44 private $ldap_server_url = null;
45 private $settings = null;
46
50 private $log = null;
51
52 private $user_fields = array();
53
62 public function __construct(ilLDAPServer $a_server,$a_url = '')
63 {
64 $this->settings = $a_server;
65
66 if(strlen($a_url))
67 {
68 $this->ldap_server_url = $a_url;
69 }
70 else
71 {
72 $this->ldap_server_url = $this->settings->getUrl();
73 }
74
75 $this->mapping = ilLDAPAttributeMapping::_getInstanceByServerId($this->settings->getServerId());
76 $this->log = $GLOBALS['DIC']->logger()->auth();
77
79 $this->connect();
80 }
81
82 // begin-patch ldap_multiple
87 public function getServer()
88 {
89 return $this->settings;
90 }
91
96 public function getLogger()
97 {
98 return $this->log;
99 }
100
108 public function fetchUser($a_name)
109 {
110 if(!$this->readUserData($a_name))
111 {
112 return array();
113 }
114 else
115 {
116 return $this->users;
117 }
118 }
119
120
127 public function fetchUsers()
128 {
129 // First of all check if a group restriction is enabled
130 // YES: => fetch all group members
131 // No: => fetch all users
132 if(strlen($this->settings->getGroupName()))
133 {
134 $this->log->debug('Searching for group members.');
135
136 $groups = $this->settings->getGroupNames();
137 if(count($groups) <= 1)
138 {
139 $this->fetchGroupMembers();
140 }
141 else
142 {
143 foreach($groups as $group)
144 {
145 $this->fetchGroupMembers($group);
146 }
147 }
148
149 }
150 if(!strlen($this->settings->getGroupName()) or $this->settings->isMembershipOptional())
151 {
152 $this->log->info('Start reading all users...');
153 $this->readAllUsers();
154 #throw new ilLDAPQueryException('LDAP: Called import of users without specifying group restrictions. NOT IMPLEMENTED YET!');
155 }
156 return $this->users ? $this->users : array();
157 }
158
170 public function query($a_search_base,$a_filter,$a_scope,$a_attributes)
171 {
172 $res = $this->queryByScope($a_scope,$a_search_base,$a_filter,$a_attributes);
173 if($res === false)
174 {
175 throw new ilLDAPQueryException(__METHOD__.' '.ldap_error($this->lh).' '.
176 sprintf('DN: %s, Filter: %s, Scope: %s',
177 $a_search_base,
178 $a_filter,
179 $a_scope));
180 }
181 return new ilLDAPResult($this->lh,$res);
182 }
183
190 public function modAdd($a_dn,$a_attribute)
191 {
192 if(@ldap_mod_add($this->lh,$a_dn,$a_attribute))
193 {
194 return true;
195 }
196 throw new ilLDAPQueryException(__METHOD__.' '.ldap_error($this->lh));
197 }
198
205 public function modDelete($a_dn,$a_attribute)
206 {
207 if(@ldap_mod_del($this->lh,$a_dn,$a_attribute))
208 {
209 return true;
210 }
211 throw new ilLDAPQueryException(__METHOD__.' '.ldap_error($this->lh));
212 }
213
222 private function readAllUsers()
223 {
224 // Build search base
225 if(($dn = $this->settings->getSearchBase()) && substr($dn,-1) != ',')
226 {
227 $dn .= ',';
228 }
229 $dn .= $this->settings->getBaseDN();
230
231 // page results
232 $filter = $this->settings->getFilter();
233 $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','-');
234 $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');
235
236 foreach($page_filter as $letter)
237 {
238 $new_filter = '(&';
239 $new_filter .= $filter;
240
241 switch($letter)
242 {
243 case '-':
244 $new_filter .= ('(!(|');
245 foreach($chars as $char)
246 {
247 $new_filter .= ('('.$this->settings->getUserAttribute().'='.$char.'*)');
248 }
249 $new_filter .= ')))';
250 break;
251
252 default:
253 $new_filter .= ('('.$this->settings->getUserAttribute().'='.$letter.'*))');
254 break;
255 }
256
257 $this->log->info('Searching with ldap search and filter '.$new_filter.' in '.$dn);
258 $res = $this->queryByScope($this->settings->getUserScope(),
259 $dn,
260 $new_filter,
261 array($this->settings->getUserAttribute()));
262
263 $tmp_result = new ilLDAPResult($this->lh,$res);
264 if(!$tmp_result->numRows())
265 {
266 $this->log->notice('No users found. Aborting.');
267 continue;
268 }
269 $this->log->info('Found '.$tmp_result->numRows().' users.');
270 $attribute = strtolower($this->settings->getUserAttribute());
271 foreach($tmp_result->getRows() as $data)
272 {
273 if(isset($data[$attribute]))
274 {
275 $this->readUserData($data[$attribute],false,false);
276 }
277 else
278 {
279 $this->log->warning('Unknown error. No user attribute found.');
280 }
281 }
282 unset($tmp_result);
283 }
284 return true;
285 }
286
293 public function checkGroupMembership($a_ldap_user_name, $ldap_user_data)
294 {
295 $group_names = $this->getServer()->getGroupNames();
296
297 if(!count($group_names))
298 {
299 $this->getLogger()->debug('No LDAP group restrictions found');
300 return true;
301 }
302
303 $group_dn = $this->getServer()->getGroupDN();
304 if(
305 $group_dn &&
306 (substr($group_dn, -1) != ',')
307 )
308 {
309 $group_dn .= ',';
310 }
311 $group_dn .= $this->getServer()->getBaseDN();
312
313 foreach($group_names as $group)
314 {
315 $user = $a_ldap_user_name;
316 if($this->getServer()->enabledGroupMemberIsDN())
317 {
318 $user = $ldap_user_data['dn'];
319 }
320
321 $filter = sprintf('(&(%s=%s)(%s=%s)%s)',
322 $this->getServer()->getGroupAttribute(),
323 $group,
324 $this->getServer()->getGroupMember(),
325 $user,
326 $this->getServer()->getGroupFilter()
327 );
328 $this->getLogger()->debug('Current group search base: ' . $group_dn);
329 $this->getLogger()->debug('Current group filter: ' . $filter);
330
331 $res = $this->queryByScope(
332 $this->getServer()->getGroupScope(),
333 $group_dn,
334 $filter,
335 [$this->getServer()->getGroupMember()]
336 );
337
338 $this->getLogger()->dump($res);
339
340 $tmp_result = new ilLDAPResult($this->lh,$res);
341 $group_result = $tmp_result->getRows();
342
343 $this->getLogger()->debug('Group query returned: ');
344 $this->getLogger()->dump($group_result, ilLogLevel::DEBUG);
345
346 if(count($group_result))
347 {
348 return true;
349 }
350 }
351
352 // group restrictions failed check optional membership
353 if($this->getServer()->isMembershipOptional())
354 {
355 $this->getLogger()->debug('Group restrictions failed, checking user filter.');
356 if($this->readUserData($a_ldap_user_name, true, true))
357 {
358 $this->getLogger()->debug('User filter matches.');
359 return true;
360 }
361 }
362 $this->getLogger()->debug('Group restrictions failed.');
363 return false;
364 }
365
366
373 private function fetchGroupMembers($a_name = '')
374 {
375 $group_name = strlen($a_name) ? $a_name : $this->settings->getGroupName();
376
377 // Build filter
378 $filter = sprintf('(&(%s=%s)%s)',
379 $this->settings->getGroupAttribute(),
380 $group_name,
381 $this->settings->getGroupFilter());
382
383
384 // Build search base
385 if(($gdn = $this->settings->getGroupDN()) && substr($gdn,-1) != ',')
386 {
387 $gdn .= ',';
388 }
389 $gdn .= $this->settings->getBaseDN();
390
391 $this->log->debug('Using filter '.$filter);
392 $this->log->debug('Using DN '.$gdn);
393 $res = $this->queryByScope($this->settings->getGroupScope(),
394 $gdn,
395 $filter,
396 array($this->settings->getGroupMember()));
397
398 $tmp_result = new ilLDAPResult($this->lh,$res);
399 $group_data = $tmp_result->getRows();
400
401
402 if(!$tmp_result->numRows())
403 {
404 $this->log->info('No group found.');
405 return false;
406 }
407
408 $attribute_name = strtolower($this->settings->getGroupMember());
409
410 // All groups
411 foreach($group_data as $data)
412 {
413 $this->log->debug('Found '.count($data[$attribute_name]).' group members for group '.$data['dn']);
414 if(is_array($data[$attribute_name]))
415 {
416 foreach($data[$attribute_name] as $name)
417 {
418 $this->readUserData($name,true,true);
419 }
420 }
421 else
422 {
423 $this->readUserData($data[$attribute_name],true,true);
424 }
425 }
426 unset($tmp_result);
427 return;
428 }
429
436 private function readUserData($a_name,$a_check_dn = false,$a_try_group_user_filter = false)
437 {
438 $filter = $this->settings->getFilter();
439 if($a_try_group_user_filter)
440 {
441 if($this->settings->isMembershipOptional())
442 {
443 $filter = $this->settings->getGroupUserFilter();
444 }
445 }
446
447 // Build filter
448 if($this->settings->enabledGroupMemberIsDN() and $a_check_dn)
449 {
450 $dn = $a_name;
451 #$res = $this->queryByScope(IL_LDAP_SCOPE_BASE,$dn,$filter,$this->user_fields);
452
453 $fields = array_merge($this->user_fields,array('useraccountcontrol'));
454 $res = $this->queryByScope(IL_LDAP_SCOPE_BASE,strtolower($dn),$filter,$fields);
455 }
456 else
457 {
458 $filter = sprintf('(&(%s=%s)%s)',
459 $this->settings->getUserAttribute(),
460 $a_name,
461 $filter);
462
463 // Build search base
464 if(($dn = $this->settings->getSearchBase()) && substr($dn,-1) != ',')
465 {
466 $dn .= ',';
467 }
468 $dn .= $this->settings->getBaseDN();
469 $fields = array_merge($this->user_fields,array('useraccountcontrol'));
470 $res = $this->queryByScope($this->settings->getUserScope(),strtolower($dn),$filter,$fields);
471 }
472
473
474 $tmp_result = new ilLDAPResult($this->lh,$res);
475 if(!$tmp_result->numRows())
476 {
477 $this->log->info('LDAP: No user data found for: '.$a_name);
478 unset($tmp_result);
479 return false;
480 }
481
482 if($user_data = $tmp_result->get())
483 {
484 if(isset($user_data['useraccountcontrol']))
485 {
486 if(($user_data['useraccountcontrol'] & 0x02))
487 {
488 $this->log->notice('LDAP: '.$a_name.' account disabled.');
489 return;
490 }
491 }
492
493 $account = $user_data[strtolower($this->settings->getUserAttribute())];
494 if(is_array($account))
495 {
496 $user_ext = strtolower(array_shift($account));
497 }
498 else
499 {
500 $user_ext = strtolower($account);
501 }
502
503 // auth mode depends on ldap server settings
504 $auth_mode = $this->settings->getAuthenticationMappingKey();
505 $user_data['ilInternalAccount'] = ilObjUser::_checkExternalAuthAccount($auth_mode,$user_ext);
506 $this->users[$user_ext] = $user_data;
507 }
508 return true;
509 }
510
515 private function parseAuthMode()
516 {
517 return $this->settings->getAuthenticationMappingKey();
518 }
519
529 private function queryByScope($a_scope,$a_base_dn,$a_filter,$a_attributes)
530 {
531 $a_filter = $a_filter ? $a_filter : "(objectclass=*)";
532
533 switch($a_scope)
534 {
536 $res = @ldap_search($this->lh,$a_base_dn,$a_filter,$a_attributes);
537 break;
538
540 $res = @ldap_list($this->lh,$a_base_dn,$a_filter,$a_attributes);
541 break;
542
544
545 $res = @ldap_read($this->lh,$a_base_dn,$a_filter,$a_attributes);
546 break;
547
548 default:
549 $this->log->warning("LDAP: LDAPQuery: Unknown search scope");
550 }
551
552 $error = ldap_error($this->lh);
553 if(strcmp('Success', $error) !== 0)
554 {
555 $this->getLogger()->warning($error);
556 $this->getLogger()->warning('Base DN:' . $a_base_dn);
557 $this->getLogger()->warning('Filter: ' . $a_filter);
558 }
559
560 return $res;
561
562 }
563
571 private function connect()
572 {
573 $this->lh = @ldap_connect($this->ldap_server_url);
574
575 // LDAP Connect
576 if(!$this->lh)
577 {
578 throw new ilLDAPQueryException("LDAP: Cannot connect to LDAP Server: ".$this->settings->getUrl());
579 }
580 // LDAP Version
581 if(!ldap_set_option($this->lh,LDAP_OPT_PROTOCOL_VERSION,$this->settings->getVersion()))
582 {
583 throw new ilLDAPQueryException("LDAP: Cannot set version to: ".$this->settings->getVersion());
584 }
585 // Switch on referrals
586 if($this->settings->isActiveReferrer())
587 {
588 if(!ldap_set_option($this->lh,LDAP_OPT_REFERRALS,true))
589 {
590 throw new ilLDAPQueryException("LDAP: Cannot switch on LDAP referrals");
591 }
592 #@ldap_set_rebind_proc($this->lh,'referralRebind');
593 }
594 else
595 {
596 ldap_set_option($this->lh,LDAP_OPT_REFERRALS,false);
597 $this->log->debug('Switching referrals to false.');
598 }
599 // Start TLS
600 if($this->settings->isActiveTLS())
601 {
602 if(!ldap_start_tls($this->lh))
603 {
604 throw new ilLDAPQueryException("LDAP: Cannot start LDAP TLS");
605 }
606 }
607 }
608
617 public function bind($a_binding_type = IL_LDAP_BIND_DEFAULT,$a_user_dn = '',$a_password = '')
618 {
619 switch($a_binding_type)
620 {
622 ldap_set_option($this->lh, LDAP_OPT_NETWORK_TIMEOUT, ilLDAPServer::DEFAULT_NETWORK_TIMEOUT);
623 // fall through
625 // Now bind anonymously or as user
626 if(
627 IL_LDAP_BIND_USER == $this->settings->getBindingType() &&
628 strlen($this->settings->getBindUser())
629 )
630 {
631 $user = $this->settings->getBindUser();
632 $pass = $this->settings->getBindPassword();
633
634 define('IL_LDAP_REBIND_USER',$user);
635 define('IL_LDAP_REBIND_PASS',$pass);
636 $this->log->debug('Bind as '.$user);
637 }
638 else
639 {
640 $user = $pass = '';
641 $this->log->debug('Bind anonymous');
642 }
643 break;
644
646 $user = $this->settings->getRoleBindDN();
647 $pass = $this->settings->getRoleBindPassword();
648
649 if(!strlen($user) or !strlen($pass))
650 {
651 $user = $this->settings->getBindUser();
652 $pass = $this->settings->getBindPassword();
653 }
654
655 define('IL_LDAP_REBIND_USER',$user);
656 define('IL_LDAP_REBIND_PASS',$pass);
657 break;
658
660 $this->log->debug('Trying to bind as: ' . $a_user_dn);
661 $user = $a_user_dn;
662 $pass = $a_password;
663 break;
664
665
666 default:
667 throw new ilLDAPQueryException('LDAP: unknown binding type in: '.__METHOD__);
668 }
669
670 if(!@ldap_bind($this->lh,$user,$pass))
671 {
672 throw new ilLDAPQueryException('LDAP: Cannot bind as '.$user.' with message: '. ldap_err2str(ldap_errno($this->lh)).' Trying fallback...', ldap_errno($this->lh));
673 }
674 else
675 {
676 $this->log->debug('Bind successful.');
677 }
678 }
679
687 private function fetchUserProfileFields()
688 {
689 include_once('Services/LDAP/classes/class.ilLDAPRoleAssignmentRules.php');
690
691 $this->user_fields = array_merge(
692 array($this->settings->getUserAttribute()),
693 array('dn'),
694 $this->mapping->getFields(),
695 ilLDAPRoleAssignmentRules::getAttributeNames($this->getServer()->getServerId())
696 );
697 }
698
699
707 private function unbind()
708 {
709 if($this->lh)
710 {
711 @ldap_unbind($this->lh);
712 }
713 }
714
715
723 public function __destruct()
724 {
725 if($this->lh)
726 {
727 @ldap_unbind($this->lh);
728 }
729 }
730}
731
732function referralRebind($a_ds,$a_url)
733{
734 global $ilLog;
735
736 $ilLog->write('LDAP: Called referralRebind.');
737
738 ldap_set_option($a_ds, LDAP_OPT_PROTOCOL_VERSION, 3);
739
740 if (!ldap_bind($a_ds,IL_LDAP_REBIND_USER,IL_LDAP_REBIND_PASS))
741 {
742 $ilLog->write('LDAP: Rebind failed');
743 }
744}
745
746?>
sprintf('%.4f', $callTime)
$error
Definition: Error.php:17
An exception for terminatinating execution or to throw for unit testing.
const IL_LDAP_BIND_AUTH
const IL_LDAP_BIND_DEFAULT
referralRebind($a_ds, $a_url)
const IL_LDAP_BIND_ADMIN
const IL_LDAP_BIND_TEST
const IL_LDAP_BIND_USER
const IL_LDAP_SCOPE_BASE
const IL_LDAP_SCOPE_SUB
const IL_LDAP_SCOPE_ONE
static _getInstanceByServerId($a_server_id)
Get instance of class.
modAdd($a_dn, $a_attribute)
Add value to an existing attribute.
fetchUsers()
Fetch all users.
queryByScope($a_scope, $a_base_dn, $a_filter, $a_attributes)
Query by scope IL_SCOPE_SUB => ldap_search IL_SCOPE_ONE => ldap_list.
fetchGroupMembers($a_name='')
Fetch group member ids.
fetchUserProfileFields()
fetch required fields of user profile data
getServer()
Get server.
bind($a_binding_type=IL_LDAP_BIND_DEFAULT, $a_user_dn='', $a_password='')
Bind to LDAP server.
connect()
Connect to LDAP server.
parseAuthMode()
Parse authentication mode.
readUserData($a_name, $a_check_dn=false, $a_try_group_user_filter=false)
Read user data.
__destruct()
Destructor unbind from ldap server.
getLogger()
Get logger.
readAllUsers()
Fetch all users This function splits the query to filters like e.g (uid=a*) (uid=b*)....
__construct(ilLDAPServer $a_server, $a_url='')
Constructur.
fetchUser($a_name)
Get one user by login name.
checkGroupMembership($a_ldap_user_name, $ldap_user_data)
check group membership
query($a_search_base, $a_filter, $a_scope, $a_attributes)
Perform a query.
modDelete($a_dn, $a_attribute)
Delete value from an existing attribute.
static getAttributeNames($a_server_id)
get all possible attribute names
const DEFAULT_NETWORK_TIMEOUT
static _checkExternalAuthAccount($a_auth, $a_account)
check whether external account and authentication method matches with a user
$GLOBALS['loaded']
Global hash that tracks already loaded includes.
settings()
Definition: settings.php:2