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