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