xref: /plugin/pureldap/classes/GroupHierarchyCache.php (revision e7339d5a8ae85d8bb79a5552d9633163199d0038)
1<?php
2
3namespace dokuwiki\plugin\pureldap\classes;
4
5use FreeDSx\Ldap\Entry\Entry;
6use FreeDSx\Ldap\Exception\ProtocolException;
7use FreeDSx\Ldap\LdapClient;
8use FreeDSx\Ldap\Operations;
9use FreeDSx\Ldap\Search\Filters;
10
11/**
12 * Keeps a copy of all AD groups and provides recursive operations
13 *
14 * All groups are cached as full DN here
15 */
16class GroupHierarchyCache
17{
18    /** @var LdapClient */
19    protected $ldap;
20
21    /** @var array List of group DNs and their parent and children */
22    protected $groupHierarchy;
23
24    /**
25     * GroupHierarchyCache constructor.
26     *
27     * @param LdapClient $ldap
28     */
29    public function __construct(LdapClient $ldap)
30    {
31        $this->ldap = $ldap;
32
33        $this->groupHierarchy = $this->getCachedGroupList();
34    }
35
36    /**
37     * Use a file system cached version of the group hierarchy
38     *
39     * The cache expires after $conf['auth_security_timeout']
40     *
41     * @return array
42     */
43    protected function getCachedGroupList()
44    {
45        global $conf;
46
47        $cachename = getcachename('grouphierarchy', '.pureldap-gch');
48        $cachetime = @filemtime($cachename);
49
50        // valid file system cache? use it
51        if ($cachetime && (time() - $cachetime) < $conf['auth_security_timeout']) {
52            return json_decode(file_get_contents($cachename), true);
53        }
54
55        // get fresh data and store in cache
56        $groups = $this->getGroupList();
57        file_put_contents($cachename, json_encode($groups));
58        return $groups;
59    }
60
61    /**
62     * Load all group information from AD
63     *
64     * @return array
65     */
66    protected function getGroupList()
67    {
68        $filter = Filters::equal('objectCategory', 'group');
69        $search = Operations::search($filter, 'memberOf', 'cn');
70        $paging = $this->ldap->paging($search);
71
72        $groups = [];
73
74        while ($paging->hasEntries()) {
75            try {
76                $entries = $paging->getEntries();
77            } catch (ProtocolException $e) {
78                return $groups; // return what we have
79            }
80            /** @var Entry $entry */
81            foreach ($entries as $entry) {
82                $dn = (string)$entry->getDn();
83                $groups[$dn] = [];
84                if ($entry->has('memberOf')) {
85                    $parents = $entry->get('memberOf')->getValues();
86                    $groups[$dn]['parents'] = $parents;
87                    foreach ($parents as $parent) {
88                        $groups[$parent]['children'][] = $dn;
89                    }
90                }
91            }
92        }
93        return $groups;
94    }
95
96    /**
97     * Recursive method to get all children or parents
98     *
99     * @param string $group
100     * @param string $type
101     * @param array $data list to fill
102     */
103    protected function getHierarchy($group, $type, &$data)
104    {
105        if (empty($this->groupHierarchy[$group][$type])) return;
106
107        $parents = $this->groupHierarchy[$group][$type];
108        foreach ($parents as $parent) {
109            if (in_array($parent, $data)) continue; // we did this one already
110            $data[] = $parent;
111            $this->getHierarchy($parent, $type, $data);
112        }
113    }
114
115    /**
116     * Get all parents of a group
117     *
118     * @param string $group
119     * @return string[]
120     */
121    public function getParents($group)
122    {
123        $parents = [];
124        $this->getHierarchy($group, 'parents', $parents);
125        return $parents;
126    }
127
128    /**
129     * Get all children of a group
130     *
131     * @param string $group
132     * @return string[]
133     */
134    public function getChildren($group)
135    {
136        $children = [];
137        $this->getHierarchy($group, 'children', $children);
138        return $children;
139    }
140}
141
142