ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
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 $this->ldap_server_url = $a_url;
68 } else {
69 $this->ldap_server_url = $this->settings->getUrl();
70 }
71
72 $this->mapping = ilLDAPAttributeMapping::_getInstanceByServerId($this->settings->getServerId());
73 $this->log = $GLOBALS['DIC']->logger()->auth();
74
76 $this->connect();
77 }
78
79 // begin-patch ldap_multiple
84 public function getServer()
85 {
86 return $this->settings;
87 }
88
93 public function getLogger()
94 {
95 return $this->log;
96 }
97
105 public function fetchUser($a_name)
106 {
107 if (!$this->readUserData($a_name)) {
108 return array();
109 } else {
110 return $this->users;
111 }
112 }
113
114
121 public function fetchUsers()
122 {
123 // First of all check if a group restriction is enabled
124 // YES: => fetch all group members
125 // No: => fetch all users
126 if (strlen($this->settings->getGroupName())) {
127 $this->log->debug('Searching for group members.');
128
129 $groups = $this->settings->getGroupNames();
130 if (count($groups) <= 1) {
131 $this->fetchGroupMembers();
132 } else {
133 foreach ($groups as $group) {
134 $this->fetchGroupMembers($group);
135 }
136 }
137 }
138 if (!strlen($this->settings->getGroupName()) or $this->settings->isMembershipOptional()) {
139 $this->log->info('Start reading all users...');
140 $this->readAllUsers();
141 #throw new ilLDAPQueryException('LDAP: Called import of users without specifying group restrictions. NOT IMPLEMENTED YET!');
142 }
143 return $this->users ? $this->users : array();
144 }
145
157 public function query($a_search_base, $a_filter, $a_scope, $a_attributes)
158 {
159 $res = $this->queryByScope($a_scope, $a_search_base, $a_filter, $a_attributes);
160 if ($res === false) {
161 throw new ilLDAPQueryException(__METHOD__ . ' ' . ldap_error($this->lh) . ' ' .
162 sprintf(
163 'DN: %s, Filter: %s, Scope: %s',
164 $a_search_base,
165 $a_filter,
166 $a_scope
167 ));
168 }
169 return new ilLDAPResult($this->lh, $res);
170 }
171
178 public function modAdd($a_dn, $a_attribute)
179 {
180 if (@ldap_mod_add($this->lh, $a_dn, $a_attribute)) {
181 return true;
182 }
183 throw new ilLDAPQueryException(__METHOD__ . ' ' . ldap_error($this->lh));
184 }
185
192 public function modDelete($a_dn, $a_attribute)
193 {
194 if (@ldap_mod_del($this->lh, $a_dn, $a_attribute)) {
195 return true;
196 }
197 throw new ilLDAPQueryException(__METHOD__ . ' ' . ldap_error($this->lh));
198 }
199
208 private function readAllUsers()
209 {
210 // Build search base
211 if (($dn = $this->settings->getSearchBase()) && substr($dn, -1) != ',') {
212 $dn .= ',';
213 }
214 $dn .= $this->settings->getBaseDN();
215
216 // page results
217 $filter = $this->settings->getFilter();
218 $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','-');
219 $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');
220
221 foreach ($page_filter as $letter) {
222 $new_filter = '(&';
223 $new_filter .= $filter;
224
225 switch ($letter) {
226 case '-':
227 $new_filter .= ('(!(|');
228 foreach ($chars as $char) {
229 $new_filter .= ('(' . $this->settings->getUserAttribute() . '=' . $char . '*)');
230 }
231 $new_filter .= ')))';
232 break;
233
234 default:
235 $new_filter .= ('(' . $this->settings->getUserAttribute() . '=' . $letter . '*))');
236 break;
237 }
238
239 $this->log->info('Searching with ldap search and filter ' . $new_filter . ' in ' . $dn);
240 $res = $this->queryByScope(
241 $this->settings->getUserScope(),
242 $dn,
243 $new_filter,
244 array($this->settings->getUserAttribute())
245 );
246
247 $tmp_result = new ilLDAPResult($this->lh, $res);
248 if (!$tmp_result->numRows()) {
249 $this->log->notice('No users found. Aborting.');
250 continue;
251 }
252 $this->log->info('Found ' . $tmp_result->numRows() . ' users.');
253 $attribute = strtolower($this->settings->getUserAttribute());
254 foreach ($tmp_result->getRows() as $data) {
255 if (isset($data[$attribute])) {
256 $this->readUserData($data[$attribute], false, false);
257 } else {
258 $this->log->warning('Unknown error. No user attribute found.');
259 }
260 }
261 unset($tmp_result);
262 }
263 return true;
264 }
265
272 public function checkGroupMembership($a_ldap_user_name, $ldap_user_data)
273 {
274 $group_names = $this->getServer()->getGroupNames();
275
276 if (!count($group_names)) {
277 $this->getLogger()->debug('No LDAP group restrictions found');
278 return true;
279 }
280
281 $group_dn = $this->getServer()->getGroupDN();
282 if (
283 $group_dn &&
284 (substr($group_dn, -1) != ',')
285 ) {
286 $group_dn .= ',';
287 }
288 $group_dn .= $this->getServer()->getBaseDN();
289
290 foreach ($group_names as $group) {
291 $user = $a_ldap_user_name;
292 if ($this->getServer()->enabledGroupMemberIsDN()) {
293 if ($this->getServer()->enabledEscapeDN()) {
294 $user = ldap_escape($ldap_user_data['dn'], "", LDAP_ESCAPE_FILTER);
295 } else {
296 $user = $ldap_user_data['dn'];
297 }
298 }
299
300 $filter = sprintf(
301 '(&(%s=%s)(%s=%s)%s)',
302 $this->getServer()->getGroupAttribute(),
303 $group,
304 $this->getServer()->getGroupMember(),
305 $user,
306 $this->getServer()->getGroupFilter()
307 );
308 $this->getLogger()->debug('Current group search base: ' . $group_dn);
309 $this->getLogger()->debug('Current group filter: ' . $filter);
310
311 $res = $this->queryByScope(
312 $this->getServer()->getGroupScope(),
313 $group_dn,
314 $filter,
315 [$this->getServer()->getGroupMember()]
316 );
317
318 $this->getLogger()->dump($res);
319
320 $tmp_result = new ilLDAPResult($this->lh, $res);
321 $group_result = $tmp_result->getRows();
322
323 $this->getLogger()->debug('Group query returned: ');
324 $this->getLogger()->dump($group_result, ilLogLevel::DEBUG);
325
326 if (count($group_result)) {
327 return true;
328 }
329 }
330
331 // group restrictions failed check optional membership
332 if ($this->getServer()->isMembershipOptional()) {
333 $this->getLogger()->debug('Group restrictions failed, checking user filter.');
334 if ($this->readUserData($a_ldap_user_name, true, true)) {
335 $this->getLogger()->debug('User filter matches.');
336 return true;
337 }
338 }
339 $this->getLogger()->debug('Group restrictions failed.');
340 return false;
341 }
342
343
350 private function fetchGroupMembers($a_name = '')
351 {
352 $group_name = strlen($a_name) ? $a_name : $this->settings->getGroupName();
353
354 // Build filter
355 $filter = sprintf(
356 '(&(%s=%s)%s)',
357 $this->settings->getGroupAttribute(),
358 $group_name,
359 $this->settings->getGroupFilter()
360 );
361
362
363 // Build search base
364 if (($gdn = $this->settings->getGroupDN()) && substr($gdn, -1) != ',') {
365 $gdn .= ',';
366 }
367 $gdn .= $this->settings->getBaseDN();
368
369 $this->log->debug('Using filter ' . $filter);
370 $this->log->debug('Using DN ' . $gdn);
371 $res = $this->queryByScope(
372 $this->settings->getGroupScope(),
373 $gdn,
374 $filter,
375 array($this->settings->getGroupMember())
376 );
377
378 $tmp_result = new ilLDAPResult($this->lh, $res);
379 $group_data = $tmp_result->getRows();
380
381
382 if (!$tmp_result->numRows()) {
383 $this->log->info('No group found.');
384 return false;
385 }
386
387 $attribute_name = strtolower($this->settings->getGroupMember());
388
389 // All groups
390 foreach ($group_data as $data) {
391 if (is_array($data[$attribute_name])) {
392 $this->log->debug('Found ' . count($data[$attribute_name]) . ' group members for group ' . $data['dn']);
393 foreach ($data[$attribute_name] as $name) {
394 $this->readUserData($name, true, true);
395 }
396 } else {
397 $this->readUserData($data[$attribute_name], true, true);
398 }
399 }
400 unset($tmp_result);
401 return;
402 }
403
410 private function readUserData($a_name, $a_check_dn = false, $a_try_group_user_filter = false)
411 {
412 $filter = $this->settings->getFilter();
413 if ($a_try_group_user_filter) {
414 if ($this->settings->isMembershipOptional()) {
415 $filter = $this->settings->getGroupUserFilter();
416 }
417 }
418
419 // Build filter
420 if ($this->settings->enabledGroupMemberIsDN() and $a_check_dn) {
421 $dn = $a_name;
422 #$res = $this->queryByScope(IL_LDAP_SCOPE_BASE,$dn,$filter,$this->user_fields);
423
424 $fields = array_merge($this->user_fields, array('useraccountcontrol'));
425 $res = $this->queryByScope(IL_LDAP_SCOPE_BASE, strtolower($dn), $filter, $fields);
426 } else {
427 $filter = sprintf(
428 '(&(%s=%s)%s)',
429 $this->settings->getUserAttribute(),
430 $a_name,
431 $filter
432 );
433
434 // Build search base
435 if (($dn = $this->settings->getSearchBase()) && substr($dn, -1) != ',') {
436 $dn .= ',';
437 }
438 $dn .= $this->settings->getBaseDN();
439 $fields = array_merge($this->user_fields, array('useraccountcontrol'));
440 $res = $this->queryByScope($this->settings->getUserScope(), strtolower($dn), $filter, $fields);
441 }
442
443
444 $tmp_result = new ilLDAPResult($this->lh, $res);
445 if (!$tmp_result->numRows()) {
446 $this->log->info('LDAP: No user data found for: ' . $a_name);
447 unset($tmp_result);
448 return false;
449 }
450
451 if ($user_data = $tmp_result->get()) {
452 if (isset($user_data['useraccountcontrol'])) {
453 if (($user_data['useraccountcontrol'] & 0x02)) {
454 $this->log->notice('LDAP: ' . $a_name . ' account disabled.');
455 return;
456 }
457 }
458
459 $account = $user_data[strtolower($this->settings->getUserAttribute())];
460 if (is_array($account)) {
461 $user_ext = strtolower(array_shift($account));
462 } else {
463 $user_ext = strtolower($account);
464 }
465
466 // auth mode depends on ldap server settings
467 $auth_mode = $this->settings->getAuthenticationMappingKey();
468 $user_data['ilInternalAccount'] = ilObjUser::_checkExternalAuthAccount($auth_mode, $user_ext);
469 $this->users[$user_ext] = $user_data;
470 }
471 return true;
472 }
473
478 private function parseAuthMode()
479 {
480 return $this->settings->getAuthenticationMappingKey();
481 }
482
492 private function queryByScope($a_scope, $a_base_dn, $a_filter, $a_attributes)
493 {
494 $a_filter = $a_filter ? $a_filter : "(objectclass=*)";
495
496 switch ($a_scope) {
498 $res = @ldap_search($this->lh, $a_base_dn, $a_filter, $a_attributes);
499 break;
500
502 $res = @ldap_list($this->lh, $a_base_dn, $a_filter, $a_attributes);
503 break;
504
506
507 $res = @ldap_read($this->lh, $a_base_dn, $a_filter, $a_attributes);
508 break;
509
510 default:
511 $this->log->warning("LDAP: LDAPQuery: Unknown search scope");
512 }
513
514 $error = ldap_error($this->lh);
515 if (strcmp('Success', $error) !== 0) {
516 $this->getLogger()->warning($error);
517 $this->getLogger()->warning('Base DN:' . $a_base_dn);
518 $this->getLogger()->warning('Filter: ' . $a_filter);
519 }
520
521 return $res;
522 }
523
531 private function connect()
532 {
533 $this->lh = @ldap_connect($this->ldap_server_url);
534
535 // LDAP Connect
536 if (!$this->lh) {
537 throw new ilLDAPQueryException("LDAP: Cannot connect to LDAP Server: " . $this->settings->getUrl());
538 }
539 // LDAP Version
540 if (!ldap_set_option($this->lh, LDAP_OPT_PROTOCOL_VERSION, $this->settings->getVersion())) {
541 throw new ilLDAPQueryException("LDAP: Cannot set version to: " . $this->settings->getVersion());
542 }
543 // Switch on referrals
544 if ($this->settings->isActiveReferrer()) {
545 if (!ldap_set_option($this->lh, LDAP_OPT_REFERRALS, true)) {
546 throw new ilLDAPQueryException("LDAP: Cannot switch on LDAP referrals");
547 }
548 #@ldap_set_rebind_proc($this->lh,'referralRebind');
549 } else {
550 ldap_set_option($this->lh, LDAP_OPT_REFERRALS, false);
551 $this->log->debug('Switching referrals to false.');
552 }
553 // Start TLS
554 if ($this->settings->isActiveTLS()) {
555 if (!ldap_start_tls($this->lh)) {
556 throw new ilLDAPQueryException("LDAP: Cannot start LDAP TLS");
557 }
558 }
559 }
560
569 public function bind($a_binding_type = IL_LDAP_BIND_DEFAULT, $a_user_dn = '', $a_password = '')
570 {
571 switch ($a_binding_type) {
573 ldap_set_option($this->lh, LDAP_OPT_NETWORK_TIMEOUT, ilLDAPServer::DEFAULT_NETWORK_TIMEOUT);
574 // fall through
575 // no break
577 // Now bind anonymously or as user
578 if (
579 IL_LDAP_BIND_USER == $this->settings->getBindingType() &&
580 strlen($this->settings->getBindUser())
581 ) {
582 $user = $this->settings->getBindUser();
583 $pass = $this->settings->getBindPassword();
584
585 define('IL_LDAP_REBIND_USER', $user);
586 define('IL_LDAP_REBIND_PASS', $pass);
587 $this->log->debug('Bind as ' . $user);
588 } else {
589 $user = $pass = '';
590 $this->log->debug('Bind anonymous');
591 }
592 break;
593
595 $user = $this->settings->getRoleBindDN();
596 $pass = $this->settings->getRoleBindPassword();
597
598 if (!strlen($user) or !strlen($pass)) {
599 $user = $this->settings->getBindUser();
600 $pass = $this->settings->getBindPassword();
601 }
602
603 define('IL_LDAP_REBIND_USER', $user);
604 define('IL_LDAP_REBIND_PASS', $pass);
605 break;
606
608 $this->log->debug('Trying to bind as: ' . $a_user_dn);
609 $user = $a_user_dn;
610 $pass = $a_password;
611 break;
612
613
614 default:
615 throw new ilLDAPQueryException('LDAP: unknown binding type in: ' . __METHOD__);
616 }
617
618 if (!@ldap_bind($this->lh, $user, $pass)) {
619 throw new ilLDAPQueryException('LDAP: Cannot bind as ' . $user . ' with message: ' . ldap_err2str(ldap_errno($this->lh)) . ' Trying fallback...', ldap_errno($this->lh));
620 } else {
621 $this->log->debug('Bind successful.');
622 }
623 }
624
632 private function fetchUserProfileFields()
633 {
634 include_once('Services/LDAP/classes/class.ilLDAPRoleAssignmentRules.php');
635
636 $this->user_fields = array_merge(
637 array($this->settings->getUserAttribute()),
638 array('dn'),
639 $this->mapping->getFields(),
640 ilLDAPRoleAssignmentRules::getAttributeNames($this->getServer()->getServerId())
641 );
642 }
643
644
652 private function unbind()
653 {
654 if ($this->lh) {
655 @ldap_unbind($this->lh);
656 }
657 }
658
659
667 public function __destruct()
668 {
669 if ($this->lh) {
670 @ldap_unbind($this->lh);
671 }
672 }
673}
674
675function referralRebind($a_ds, $a_url)
676{
677 global $DIC;
678
679 $ilLog = $DIC['ilLog'];
680
681 $ilLog->write('LDAP: Called referralRebind.');
682
683 ldap_set_option($a_ds, LDAP_OPT_PROTOCOL_VERSION, 3);
684
685 if (!ldap_bind($a_ds, IL_LDAP_REBIND_USER, IL_LDAP_REBIND_PASS)) {
686 $ilLog->write('LDAP: Rebind failed');
687 }
688}
$users
Definition: authpage.php:44
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, $tryFallback=true)
check whether external account and authentication method matches with a user
$user
Definition: migrateto20.php:57
$GLOBALS['JPEG_Segment_Names']
Global Variable: XMP_tag_captions.
global $DIC
Definition: saml.php:7
foreach($_POST as $key=> $value) $res
settings()
Definition: settings.php:2
$data
Definition: bench.php:6