ldap->domainFromBaseDn(); $userInfo = $this->lookupUser($sam); if ($userInfo === null) { return null; } $identities = array_unique(array_filter([ $userInfo['dn'], $sam . '@' . $domain, $username, ])); foreach ($identities as $identity) { if ($this->tryBind($identity, $password)) { return [ 'username' => $sam, 'display_name' => $userInfo['display_name'], 'email' => $userInfo['email'], 'is_admin' => $this->isAdministrator($userInfo['groups']), ]; } } return null; } public function isAdministrator(array $groups): bool { $adminGroups = array_map( 'mb_strtolower', config('ldap.admin_groups', ['Domain Admins', 'Administrators']) ); foreach ($groups as $group) { if (in_array(mb_strtolower($group), $adminGroups, true)) { return true; } } return false; } /** * @return array{dn: string, display_name: string, email: string, groups: list}|null */ public function lookupUser(string $username): ?array { $connection = null; try { $connection = $this->ldap->bind(); $filter = '(sAMAccountName=' . ldap_escape($username, '', LDAP_ESCAPE_FILTER) . ')'; $result = @ldap_search( $connection, config('ldap.base_dn'), $filter, ['dn', 'displayname', 'mail', 'memberof', 'useraccountcontrol', 'lastlogontimestamp', 'samaccountname'] ); if ($result === false) { return null; } $entries = ldap_get_entries($connection, $result); if (($entries['count'] ?? 0) < 1) { return null; } $entry = $entries[0]; $uac = (int) ($this->ldap->attributeValue($entry, 'useraccountcontrol') ?? 0); if ($uac & 2) { return null; } $groups = []; if (isset($entry['memberof']) && is_array($entry['memberof'])) { for ($i = 0; $i < ($entry['memberof']['count'] ?? 0); $i++) { $dn = $entry['memberof'][$i] ?? ''; if (preg_match('/^CN=([^,]+)/i', $dn, $matches)) { $groups[] = $matches[1]; } } } sort($groups); return [ 'username' => $this->ldap->attributeValue($entry, 'samaccountname') ?? $username, 'dn' => $entry['dn'], 'display_name' => $this->ldap->attributeValue($entry, 'displayname') ?? $username, 'email' => $this->ldap->attributeValue($entry, 'mail') ?? '', 'enabled' => ! ($uac & 2), 'last_logon' => $this->filetimeToDate($this->ldap->attributeValue($entry, 'lastlogontimestamp')), 'groups' => $groups, 'is_admin' => $this->isAdministrator($groups), 'domain' => $this->ldap->domainFromBaseDn(), ]; } catch (RuntimeException) { return null; } finally { if ($connection !== null) { @ldap_unbind($connection); } } } public function getProfile(string $username): ?array { return $this->lookupUser($username); } private function filetimeToDate(?string $filetime): ?string { if ($filetime === null || $filetime === '' || $filetime === '0') { return null; } $unix = ((int) $filetime / 10000000) - 11644473600; if ($unix <= 0) { return null; } return gmdate('Y-m-d H:i:s', $unix); } private function tryBind(string $identity, string $password): bool { $connection = null; try { $connection = $this->ldap->connect(ssl: false); ldap_set_option($connection, LDAP_OPT_PROTOCOL_VERSION, 3); ldap_set_option($connection, LDAP_OPT_REFERRALS, 0); return @ldap_bind($connection, $identity, $password); } catch (RuntimeException) { return false; } finally { if ($connection !== null) { @ldap_unbind($connection); } } } }