xref: /plugin/pureldap/classes/ADClient.php (revision 5a3b912293b77009ff72b70b480eb77929df5103)
11078ec26SAndreas Gohr<?php
21078ec26SAndreas Gohr
31078ec26SAndreas Gohrnamespace dokuwiki\plugin\pureldap\classes;
41078ec26SAndreas Gohr
51078ec26SAndreas Gohruse FreeDSx\Ldap\Entry\Entries;
61078ec26SAndreas Gohruse FreeDSx\Ldap\Entry\Entry;
71078ec26SAndreas Gohruse FreeDSx\Ldap\Exception\OperationException;
8*5a3b9122SAndreas Gohruse FreeDSx\Ldap\Exception\ProtocolException;
91078ec26SAndreas Gohruse FreeDSx\Ldap\Operations;
101078ec26SAndreas Gohruse FreeDSx\Ldap\Search\Filters;
111078ec26SAndreas Gohr
121078ec26SAndreas Gohrclass ADClient extends Client
131078ec26SAndreas Gohr{
141078ec26SAndreas Gohr
151078ec26SAndreas Gohr    /** @inheritDoc */
161078ec26SAndreas Gohr    public function getUser($username, $fetchgroups = true)
171078ec26SAndreas Gohr    {
181078ec26SAndreas Gohr        if (!$this->autoAuth()) return null;
191078ec26SAndreas Gohr
201078ec26SAndreas Gohr        $filter = Filters::and(
211078ec26SAndreas Gohr            Filters::equal('objectClass', 'user'),
221078ec26SAndreas Gohr            Filters::equal('userPrincipalName', $username)
231078ec26SAndreas Gohr        );
241078ec26SAndreas Gohr
251078ec26SAndreas Gohr        try {
261078ec26SAndreas Gohr            /** @var Entries $entries */
271078ec26SAndreas Gohr            $entries = $this->ldap->search(Operations::search($filter));
281078ec26SAndreas Gohr        } catch (OperationException $e) {
291078ec26SAndreas Gohr            $this->debug($e);
301078ec26SAndreas Gohr            return null;
311078ec26SAndreas Gohr        }
321078ec26SAndreas Gohr        if ($entries->count() !== 1) return null;
331078ec26SAndreas Gohr        $entry = $entries->first();
341078ec26SAndreas Gohr
351078ec26SAndreas Gohr        return [
361078ec26SAndreas Gohr            'user' => $username,
371078ec26SAndreas Gohr            'name' => $this->attr2str($entry->get('DisplayName')) ?: $this->attr2str($entry->get('Name')),
381078ec26SAndreas Gohr            'mail' => $this->attr2str($entry->get('mail')),
391078ec26SAndreas Gohr            'dn' => $entry->getDn()->toString(),
401078ec26SAndreas Gohr            'grps' => $this->getUserGroups($entry), // we always return groups because its currently inexpensive
411078ec26SAndreas Gohr        ];
421078ec26SAndreas Gohr    }
431078ec26SAndreas Gohr
44*5a3b9122SAndreas Gohr    /** @inheritDoc */
45*5a3b9122SAndreas Gohr    public function getGroups()
46*5a3b9122SAndreas Gohr    {
47*5a3b9122SAndreas Gohr        if (!$this->autoAuth()) return [];
48*5a3b9122SAndreas Gohr
49*5a3b9122SAndreas Gohr        $filter = Filters::equal('objectClass', 'group');
50*5a3b9122SAndreas Gohr        $search = Operations::search($filter, 'cn');
51*5a3b9122SAndreas Gohr        $paging = $this->ldap->paging($search);
52*5a3b9122SAndreas Gohr
53*5a3b9122SAndreas Gohr        $groups = [];
54*5a3b9122SAndreas Gohr
55*5a3b9122SAndreas Gohr        while ($paging->hasEntries()) {
56*5a3b9122SAndreas Gohr            try {
57*5a3b9122SAndreas Gohr                $entries = $paging->getEntries();
58*5a3b9122SAndreas Gohr            } catch (ProtocolException $e) {
59*5a3b9122SAndreas Gohr                $this->debug($e);
60*5a3b9122SAndreas Gohr                return $groups; // we return what we got so far
61*5a3b9122SAndreas Gohr            }
62*5a3b9122SAndreas Gohr
63*5a3b9122SAndreas Gohr            foreach ($entries as $entry) {
64*5a3b9122SAndreas Gohr                $groups[] = $this->attr2str($entry->get('cn'));
65*5a3b9122SAndreas Gohr            }
66*5a3b9122SAndreas Gohr        }
67*5a3b9122SAndreas Gohr
68*5a3b9122SAndreas Gohr        return $groups;
69*5a3b9122SAndreas Gohr    }
70*5a3b9122SAndreas Gohr
711078ec26SAndreas Gohr    /**
721078ec26SAndreas Gohr     * Get the list of groups the given user is member of
731078ec26SAndreas Gohr     *
741078ec26SAndreas Gohr     * This method currently does no LDAP queries and thus is inexpensive.
751078ec26SAndreas Gohr     *
761078ec26SAndreas Gohr     * @param Entry $userentry
771078ec26SAndreas Gohr     * @return array
781078ec26SAndreas Gohr     * @todo implement nested group memberships
791078ec26SAndreas Gohr     */
801078ec26SAndreas Gohr    protected function getUserGroups(Entry $userentry)
811078ec26SAndreas Gohr    {
821078ec26SAndreas Gohr        $groups = [$this->config['defaultgroup']]; // always add default
831078ec26SAndreas Gohr
841078ec26SAndreas Gohr        // we simply take the first CN= part of the group DN and return it as the group name
851078ec26SAndreas Gohr        // this should be correct for ActiveDirectory and saves us additional LDAP queries
861078ec26SAndreas Gohr        if ($userentry->has('memberOf')) {
871078ec26SAndreas Gohr            foreach ($userentry->get('memberOf')->getValues() as $line) {
881078ec26SAndreas Gohr                list($cn) = explode(',', $line, 2);
891078ec26SAndreas Gohr                $groups[] = substr($cn, 3);
901078ec26SAndreas Gohr            }
911078ec26SAndreas Gohr        }
921078ec26SAndreas Gohr
931078ec26SAndreas Gohr        // resolving the primary group in AD is complicated but basically never needed
941078ec26SAndreas Gohr        // http://support.microsoft.com/?kbid=321360
951078ec26SAndreas Gohr        $gid = $userentry->get('primaryGroupID')->firstValue();
961078ec26SAndreas Gohr        if ($gid == 513) {
971078ec26SAndreas Gohr            $groups[] = 'Domain Users';
981078ec26SAndreas Gohr        }
991078ec26SAndreas Gohr
1001078ec26SAndreas Gohr        return $groups;
1011078ec26SAndreas Gohr    }
1021078ec26SAndreas Gohr}
103