19 declare(strict_types=1);
    56         $this->
logger = $DIC->logger()->auth();
    61             $this->ldap_server_url = $a_url;
    63             $this->ldap_server_url = $this->
settings->getUrl();
   106         if ($this->
settings->getGroupName() !== 
'') {
   107             $this->
logger->debug(
'Searching for group members.');
   109             $groups = $this->
settings->getGroupNames();
   110             if (count($groups) <= 1) {
   113                 foreach ($groups as $group) {
   118         if ($this->
settings->getGroupName() === 
'' || $this->
settings->isMembershipOptional()) {
   119             $this->
logger->info(
'Start reading all users...');
   121             #throw new ilLDAPQueryException('LDAP: Called import of users without specifying group restrictions. NOT IMPLEMENTED YET!');   130     public function query(
string $a_search_base, 
string $a_filter, 
int $a_scope, array $a_attributes): 
ilLDAPResult   132         $res = $this->
queryByScope($a_scope, $a_search_base, $a_filter, $a_attributes);
   133         if (
$res === 
false) {
   136                     'DN: %s, Filter: %s, Scope: %s',
   151     public function modAdd(
string $a_dn, array $a_attribute): bool
   153         if (ldap_mod_add($this->lh, $a_dn, $a_attribute)) {
   165     public function modDelete(
string $a_dn, array $a_attribute): bool
   167         if (ldap_mod_del($this->lh, $a_dn, $a_attribute)) {
   183         if (($dn = $this->
settings->getSearchBase()) && substr($dn, -1) !== 
',') {
   186         $dn .= $this->
settings->getBaseDN();
   191                 $this->
logger->warning(
'Using LDAP with paging failed. Trying to use fallback.');
   198         if (!$tmp_result->numRows()) {
   199             $this->
logger->notice(
'No users found. Aborting.');
   201         $this->
logger->info(
'Found ' . $tmp_result->numRows() . 
' users.');
   202         $attribute = strtolower($this->
settings->getUserAttribute());
   203         foreach ($tmp_result->getRows() as 
$data) {
   204             if (isset(
$data[$attribute]) && is_scalar(
$data[$attribute]) && (string) 
$data[$attribute] !== 
'') {
   209             $this->
logger->warning(sprintf(
   210                 'Unknown error. No or invalid value found for attribute %s: %s',
   211                 $this->
settings->getUserAttribute(),
   212                 var_export(
$data[$attribute] ?? null, 
true)
   225         $filter = 
'(&' . $this->
settings->getFilter();
   226         $filter .= (
'(' . $this->
settings->getUserAttribute() . 
'=*))');
   227         $this->
logger->info(
'Searching with ldap search and filter ' . $filter . 
' in ' . $dn);
   231         $estimated_results = 0;
   235                 LDAP_CONTROL_PAGEDRESULTS => [
   236                     'oid' => LDAP_CONTROL_PAGEDRESULTS,
   237                     'isCritical' => 
true,
   239                         'size' => self::PAGINATION_SIZE,
   248                 array($this->
settings->getUserAttribute()),
   252             $tmp_result->setResult(
$res);
   259                 ldap_parse_result($this->lh, 
$res, $errcode, $matcheddn, $errmsg, $referrals, $controls);
   260                 $cookie = $controls[LDAP_CONTROL_PAGEDRESULTS][
'value'][
'cookie'] ?? 
'';
   261                 $this->
logger->debug(
'Estimated number of results: ' . $estimated_results);
   263                 $this->
logger->warning(
'Result pagination failed with message: ' . $e->getMessage());
   266         } 
while (!empty($cookie));
   279         $filter = $this->
settings->getFilter();
   280         $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', 
'-');
   281         $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');
   284         foreach ($page_filter as $letter) {
   286             $new_filter .= $filter;
   288             if ($letter === 
'-') {
   289                 $new_filter .= (
'(!(|');
   290                 foreach ($chars as $char) {
   291                     $new_filter .= (
'(' . $this->
settings->getUserAttribute() . 
'=' . $char . 
'*)');
   293                 $new_filter .= 
')))';
   295                 $new_filter .= (
'(' . $this->
settings->getUserAttribute() . 
'=' . $letter . 
'*))');
   298             $this->
logger->info(
'Searching with ldap search and filter ' . $new_filter . 
' in ' . $dn);
   303                 array($this->
settings->getUserAttribute())
   305             $tmp_result->setResult(
$res);
   320         $group_names = $this->
getServer()->getGroupNames();
   322         if (!count($group_names)) {
   323             $this->
logger->debug(
'No LDAP group restrictions found');
   327         $group_dn = $this->
getServer()->getGroupDN();
   330             (substr($group_dn, -1) !== 
',')
   334         $group_dn .= $this->
getServer()->getBaseDN();
   336         foreach ($group_names as $group) {
   337             $user = $a_ldap_user_name;
   338             if ($this->
getServer()->enabledGroupMemberIsDN()) {
   339                 if ($this->
getServer()->enabledEscapeDN()) {
   340                     $user = ldap_escape($ldap_user_data[
'dn'], 
"", LDAP_ESCAPE_FILTER);
   342                     $user = $ldap_user_data[
'dn'];
   347                 '(&(%s=%s)(%s=%s)%s)',
   354             $this->
logger->debug(
'Current group search base: ' . $group_dn);
   355             $this->
logger->debug(
'Current group filter: ' . $filter);
   368             $group_result = $tmp_result->getRows();
   370             $this->
logger->debug(
'Group query returned: ');
   373             if (count($group_result)) {
   379         if ($this->
getServer()->isMembershipOptional()) {
   380             $this->
logger->debug(
'Group restrictions failed, checking user filter.');
   381             if ($this->
readUserData($a_ldap_user_name, 
true, 
true)) {
   382                 $this->
logger->debug(
'User filter matches.');
   386         $this->
logger->debug(
'Group restrictions failed.');
   396         $group_name = $a_name !== 
'' ? $a_name : $this->
settings->getGroupName();
   401             $this->
settings->getGroupAttribute(),
   408         if (($gdn = $this->
settings->getGroupDN()) && substr($gdn, -1) !== 
',') {
   411         $gdn .= $this->
settings->getBaseDN();
   413         $this->
logger->debug(
'Using filter ' . $filter);
   414         $this->
logger->debug(
'Using DN ' . $gdn);
   419             array($this->
settings->getGroupMember())
   424         $group_data = $tmp_result->getRows();
   427         if (!$tmp_result->numRows()) {
   428             $this->
logger->info(
'No group found.');
   435         $readUserData = 
function (array $members): 
void {
   436             if ($members === []) {
   437                 $this->
logger->warning(sprintf(
   438                     'No valid member values found for group member attribute: %s',
   444             foreach ($members as $member) {
   450         $attribute_name = strtolower($this->
settings->getGroupMember());
   451         foreach ($group_data as 
$data) {
   453             if (isset($data[$attribute_name])) {
   454                 if (is_array($data[$attribute_name])) {
   455                     $members = 
array_map(
'strval', array_filter($data[$attribute_name]));
   456                     $this->
logger->debug(
'Found ' . count($members) . 
' group members for group ' . $data[
'dn']);
   457                 } elseif (is_scalar($data[$attribute_name]) && (
string) $data[$attribute_name] !== 
'') {
   459                         (string) $data[$attribute_name]
   464             $readUserData($members);
   474     private function readUserData(
string $a_name, 
bool $a_check_dn = 
false, 
bool $a_try_group_user_filter = 
false): bool
   476         $filter = $this->
settings->getFilter();
   477         if ($a_try_group_user_filter && $this->
settings->isMembershipOptional()) {
   478             $filter = $this->
settings->getGroupUserFilter();
   482         if ($a_check_dn && $this->
settings->enabledGroupMemberIsDN()) {
   485             $fields = array_merge($this->user_fields, array(
'useraccountcontrol'));
   490                 $this->
settings->getUserAttribute(),
   496             if (($dn = $this->
settings->getSearchBase()) && substr($dn, -1) !== 
',') {
   499             $dn .= $this->
settings->getBaseDN();
   500             $fields = array_merge($this->user_fields, array(
'useraccountcontrol'));
   507         if (!$tmp_result->numRows()) {
   508             $this->
logger->info(
'LDAP: No user data found for: ' . $a_name);
   513         if ($user_data = $tmp_result->get()) {
   514             if (isset($user_data[
'useraccountcontrol']) && ($user_data[
'useraccountcontrol'] & 0x02)) {
   515                 $this->
logger->notice(
'LDAP: ' . $a_name . 
' account disabled.');
   519             $account = $user_data[strtolower($this->
settings->getUserAttribute())] ?? 
'';
   520             if (is_array($account)) {
   521                 $account = array_shift($account) ?? 
'';
   524             $user_ext = strtolower((
string) $account);
   525             if ($user_ext === 
'') {
   526                 $this->
logger->notice(
'LDAP: Could not find user attribute ' . $this->
settings->getUserAttribute() . 
'.');
   531             $auth_mode = $this->
settings->getAuthenticationMappingKey();
   533             $this->users[$user_ext] = $user_data;
   550         array $controls = null
   552         $a_filter = $a_filter ?: 
"(objectclass=*)";
   554         set_error_handler(
static function (
int $severity, 
string $message, 
string $file, 
int $line): 
void {
   555             throw new ErrorException($message, $severity, $severity, $file, $line);
   563                     $result = ldap_search(
   606                         "Undefined LDAP Search Scope: " . $a_scope
   610             $this->
logger->warning($e->getMessage());
   611             $this->
logger->warning($e->getTraceAsString());
   613             restore_error_handler();
   616         $error = ldap_errno($this->lh);
   618             $this->
logger->warning(
"LDAP Error Code: " . $error . 
"(" . ldap_err2str($error) . 
")");
   619             $this->
logger->warning(
'Base DN:' . $a_base_dn);
   620             $this->
logger->warning(
'Filter: ' . $a_filter);
   634         $this->lh = ldap_connect($this->ldap_server_url);
   641         if (!ldap_set_option($this->lh, LDAP_OPT_PROTOCOL_VERSION, $this->
settings->getVersion())) {
   645         if ($this->
settings->isActiveReferrer()) {
   646             if (!ldap_set_option($this->lh, LDAP_OPT_REFERRALS, 
true)) {
   650             ldap_set_option($this->lh, LDAP_OPT_REFERRALS, 
false);
   651             $this->
logger->debug(
'Switching referrals to false.');
   654         if ($this->
settings->isActiveTLS() && !ldap_start_tls($this->lh)) {
   669         switch ($a_binding_type) {
   671             case self::LDAP_BIND_TEST:
   675             case self::LDAP_BIND_DEFAULT:
   679                     $this->
settings->getBindUser() !== 
''   681                     $user = $this->
settings->getBindUser();
   682                     $pass = $this->
settings->getBindPassword();
   684                     $this->
logger->debug(
'Bind as ' . $user);
   687                     $this->
logger->debug(
'Bind anonymous');
   691             case self::LDAP_BIND_ADMIN:
   692                 $user = $this->
settings->getRoleBindDN();
   693                 $pass = $this->
settings->getRoleBindPassword();
   695                 if ($user === 
'' || $pass === 
'') {
   696                     $user = $this->
settings->getBindUser();
   697                     $pass = $this->
settings->getBindPassword();
   701             case self::LDAP_BIND_AUTH:
   702                 $this->
logger->debug(
'Trying to bind as: ' . $a_user_dn);
   713             set_error_handler(
static function (
int $severity, 
string $message, 
string $file, 
int $line): 
void {
   714                 throw new ErrorException($message, $severity, $severity, $file, $line);
   717             if (!ldap_bind($this->lh, $user, $pass)) {
   718                 throw new ilLDAPQueryException(
'LDAP: Cannot bind as ' . $user . 
' with message: ' . ldap_err2str(ldap_errno($this->lh)) . 
' Trying fallback...', ldap_errno($this->lh));
   721             throw new ilLDAPQueryException(
'LDAP: Cannot bind as ' . $user . 
' with message: ' . $e->getMessage());
   723             restore_error_handler();
   726         $this->
logger->debug(
'Bind successful.');
   734         $this->user_fields = array_merge(
   735             array($this->
settings->getUserAttribute()),
   737             $this->mapping->getFields(),
   748             ldap_unbind($this->lh);
   757         if ($this->
getServer()->getVersion() !== 3) {
   758             $this->
logger->info(
'Pagination control unavailable for ldap v' . $this->
getServer()->getVersion());
   762         $result = ldap_read($this->lh, 
'', 
'(objectClass=*)', [self::IL_LDAP_SUPPORTED_CONTROL]);
   763         if ($result === 
false) {
   764             $this->
logger->warning(
'Failed to query for pagination control');
   767         $entries = (array) (ldap_get_entries($this->lh, $result)[0] ?? []);
   769             array_key_exists(strtolower(self::IL_LDAP_SUPPORTED_CONTROL), $entries) &&
   770             is_array($entries[strtolower(self::IL_LDAP_SUPPORTED_CONTROL)]) &&
   771             in_array(LDAP_CONTROL_PAGEDRESULTS, $entries[strtolower(self::IL_LDAP_SUPPORTED_CONTROL)], 
true)
   773             $this->
logger->info(
'Using paged control');
   776         $this->
logger->info(
'Paged control disabled');
 
fetchUsers()
Fetch all users. 
 
query(string $a_search_base, string $a_filter, int $a_scope, array $a_attributes)
Perform a query. 
 
runReadAllUsersPaged(string $dn)
read all users with ldap paging 
 
const IL_LDAP_SUPPORTED_CONTROL
 
modAdd(string $a_dn, array $a_attribute)
Add value to an existing attribute. 
 
static _checkExternalAuthAccount(string $a_auth, string $a_account, bool $tryFallback=true)
check whether external account and authentication method matches with a user 
 
connect()
Connect to LDAP server. 
 
static getAttributeNames($a_server_id)
get all possible attribute names 
 
ilLDAPAttributeMapping $mapping
 
readAllUsers()
Fetch all users This function splits the query to filters like e.g (uid=a*) (uid=b*)... 
 
modDelete(string $a_dn, array $a_attribute)
Delete value from an existing attribute. 
 
const DEFAULT_NETWORK_TIMEOUT
 
runReadAllUsersPartial(string $dn)
Read all users partial by alphabet. 
 
fetchUserProfileFields()
fetch required fields of user profile data 
 
checkPaginationEnabled()
Check if pagination is enabled (rfc: 2696) 
 
readUserData(string $a_name, bool $a_check_dn=false, bool $a_try_group_user_filter=false)
Read user data. 
 
fetchGroupMembers(string $a_name='')
Fetch group member ids. 
 
This class stores the settings that define the mapping between LDAP attribute and user profile fields...
 
__construct(ilLDAPServer $a_server, string $a_url='')
 
__destruct()
Destructor unbind from ldap server. 
 
checkGroupMembership(string $a_ldap_user_name, array $ldap_user_data)
check group membership 
 
queryByScope(int $a_scope, string $a_base_dn, string $a_filter, array $a_attributes, array $controls=null)
Query by scope IL_SCOPE_SUB => ldap_search IL_SCOPE_ONE => ldap_list. 
 
bind(int $a_binding_type=ilLDAPQuery::LDAP_BIND_DEFAULT, string $a_user_dn='', string $a_password='')
Bind to LDAP server. 
 
static _getInstanceByServerId(int $a_server_id)
 
fetchUser(string $a_name)
Get one user by login name.