Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
ldap_bridge.inc
1 <?php
18 require_once SQ_INCLUDE_PATH.'/asset.inc';
19 require_once SQ_CORE_PACKAGE_PATH.'/interfaces/bridge/bridge.inc';
20 require_once SQ_FUDGE_PATH.'/ldap/ldap.inc';
21 
33 class LDAP_Bridge extends Asset implements Bridge
34 {
35 
42  var $_group_types = Array(
43  'organizationalunit' => 'ou',
44  'posixgroup' => 'cn',
45  'group' => 'cn',
46  'groupofnames' => 'cn',
47  'groupofuniquenames' => 'cn',
48  'domain' => 'dc',
49  'container' => 'cn',
50  'organization' => 'o',
51  'country' => 'c',
52  );
53 
60  var $_user_types = Array(
61  'organizationalperson' => 'cn',
62  'inetorgperson' => 'cn',
63  'userproxy' => 'cn',
64  );
65 
71  var $ldap_shdw_link_type = SQ_LINK_TYPE_1;
72 
73 
80  function LDAP_Bridge($assetid=0)
81  {
82  $this->_ser_attrs = TRUE;
83  $this->Asset($assetid);
84 
85  }//end constructor
86 
87 
98  protected function _getName($short_name=FALSE, $contextid=NULL)
99  {
100  // No context specified, using the current context
101  if ($contextid === NULL) {
102  $contextid = $GLOBALS['SQ_SYSTEM']->getContextId();
103  }//end if
104 
105  // Obtain the attribute value for Name from the specified Context
106  $values = $GLOBALS['SQ_SYSTEM']->am->getAttributeValuesByName('name', $this->type(), Array($this->id), $contextid);
107  if (empty($values) === TRUE) {
108  return parent::_getName($short_name, $contextid);
109  } else {
110  return $values[$this->id];
111  }
112 
113  }//end _getName()
114 
115 
122  function connectToLdap()
123  {
124  // If the bridge is archived, make no attempt to connect
125  if ($this->status == SQ_STATUS_ARCHIVED) {
126  return NULL;
127  }
128 
129  // A bit silly to connect to LDAP without a hostname, otherwise continue...
130  $hostname = $this->attr('host');
131  if (empty($hostname)) return NULL;
132 
133  $ldap = new Ldap();
134  if (!$ldap->connect($this->attr('host'), $this->attr('port'))) {
135  return NULL;
136  }
137 
138  // any non-default ldap connection settings set here
139  foreach ($this->attr('ldap_options') as $option => $value) {
140  ldap_set_option($ldap->ptr, constant($option), $value);
141  }
142 
143  // alias dereferencing setting here
144  ldap_set_option($ldap->ptr, LDAP_OPT_DEREF, constant($this->attr('aliases')));
145 
146  $bind_dn = $this->attr('bind_dn');
147 
148  // If the bind DN is empty, anonymous access is assumed, and the
149  // password supplied will be ignored
150  if (empty($bind_dn)) {
151  $password = '';
152  } else {
153  $password = $this->attr('password');
154  }
155 
156  if (!$ldap->bind($bind_dn, $password)) {
157  return NULL;
158  }
159  return $ldap;
160 
161  }//end connectToLdap()
162 
163 
175  {
176  // an array of customisable ldap connection options to their customised value
177  // defaults:
178  // LDAP_OPT_PROTOCOL_VERSION default = 2
179  // LDAP_OPT_REFERRALS = 1
180  return Array(
181  'LDAP_OPT_PROTOCOL_VERSION' => 3,
182  'LDAP_OPT_REFERRALS' => 0,
183  );
184 
185  }//end getConnectionOptions()
186 
187 
205  function getAsset($assetid, $type_code='', $mute_errors=FALSE, $return_null=FALSE, $get_all_attr = FALSE)
206  {
207  $asset = NULL;
208  $id_parts = explode(':', $assetid);
209 
210  if (isset($id_parts[1])) {
211  $shadowid = $id_parts[1];
212  } else {
213  return $asset;
214  }
215 
216  // Setup user's inbox
217  if (isset($id_parts[2]) && $id_parts[2] == 'inbox') {
218  $GLOBALS['SQ_SYSTEM']->am->includeAsset('inbox');
219  $inbox_asset = new Inbox();
220  $inbox_asset->id = $this->id.':'.$shadowid.':inbox';
221  $inbox_asset->name = 'Inbox';
222  $inbox_asset->status = $this->status;
223  return $inbox_asset;
224  }
225 
226  $ldap = @$this->connectToLdap();
227  if (is_null($ldap) || is_null($ldap->ptr)) return $return_null ? NULL : $this->_getDummyAsset($shadowid);
228  $required_attrs = $this->attr('attributes');
229 
230  $shadowid = $this->decodeString($shadowid);
231 
232  if (!$get_all_attr) {
233  $user_attrs = $this->attr('user_attributes');
234  $sort_attr = (!empty($user_attrs['sort_by'])) ? Array($user_attrs['sort_by']) : Array();
235  $attr_req = array_merge(
236  array_keys(array_get_index($this->attr('user_attributes'), 'show', Array())),
237  array_values($required_attrs),
238  $sort_attr,
239  Array('objectclass')
240  );
241 
242  $result = $ldap->search($shadowid,'(objectClass=*)', NULL, FALSE, FALSE, array_values(array_unique($attr_req)));
243  } else {
244  $result = $ldap->search($shadowid,'(objectClass=*)', NULL, FALSE, FALSE);
245  }
246 
247  if (!$result) return $return_null ? NULL : $this->_getDummyAsset($shadowid);
248  $data = $ldap->getEntries($result);
249  if (!$data['count']) return $return_null ? NULL : $this->_getDummyAsset($shadowid);
250 
251  $data = $data[0];
252  $ldap->disconnect();
253 
254  if (!isset($data['dn']) && isset($data['distinguishedname'])) {
255  $data['dn'] = $data['distinguishedname'];
256  }
257 
258  unset($data['objectclass']['count']);
259 
260  foreach ($data['objectclass'] as $class) {
261  $class = strtolower($class);
262  if (isset($this->_group_types[$class])) {
263  // an LDAP user group
264  $GLOBALS['SQ_SYSTEM']->am->includeAsset('ldap_user_group');
265  $asset = new Ldap_User_Group($this->id, $data);
266  return $asset;
267 
268  } else if (isset($this->_user_types[$class])) {
269  // include all three LDAP user assets, in case the type changes
270  $GLOBALS['SQ_SYSTEM']->am->includeAsset('ldap_backend_user');
271  $GLOBALS['SQ_SYSTEM']->am->includeAsset('ldap_simple_edit_user');
272  $GLOBALS['SQ_SYSTEM']->am->includeAsset('ldap_user');
273  // LDAP user or LDAP Simple Edit User or LDAP backend user,
274  // depending on the bridge setting
275  $user_type = $this->attr('user_type');
276  $asset = new $user_type($this->id, $data);
277  return $asset;
278  }
279  }
280 
281  return $return_null ? NULL : $this->_getDummyAsset($shadowid);
282 
283  }//end getAsset()
284 
285 
294  protected function _getDummyAsset($shadowid)
295  {
296  // return 'unknown ldap user' when we cannot find a match
297  $data['objectclass'] = Array();
298  $data['dn'] = $shadowid;
299  $user_type = $this->attr('user_type');
300  $GLOBALS['SQ_SYSTEM']->am->includeAsset($user_type);
301  $asset = new $user_type($this->id, $data);
302  return $asset; // this should return a dummy
303 
304  }//end _getDummyAsset()
305 
306 
317  function getAssetTypeInfo($assetids, $type_code=Array(), $strict_type_code=TRUE)
318  {
319  if (!is_array($assetids)) {
320  $assetids = Array($assetids);
321  }
322  assert_type($type_code, 'array');
323  if (empty($assetids)) return Array();
324 
325  $results = Array();
326  $type_codes = Array();
327 
328  // filter assets and get their type info
329  $type_infos = $GLOBALS['SQ_SYSTEM']->am->getAssetInfo($assetids, $type_code, $strict_type_code, 'type_code');
330 
331  foreach ($type_infos as $assetid => $type_code) {
332  if (!isset($type_codes[$type_code])) {
333  $sql = 'SELECT inhd_type_code FROM sq_ast_typ_inhd WHERE type_code = :type_code ORDER BY inhd_type_code_lvl DESC';
334  $query = MatrixDAL::preparePdoQuery($sql);
335  MatrixDAL::bindValueToPdo($query, 'type_code', $type_code);
336  $result = MatrixDAL::executePdoAssoc($query, 0);
337  $type_codes[$type_code] = $result;
338  }
339 
340  $results[$assetid] = $type_codes[$type_code];
341  }
342 
343  ksort($results);
344 
345  return $results;
346 
347  }//end getAssetTypeInfo()
348 
349 
373  function getLinks($assetid, $link_types, $type_code='', $strict_type_code=TRUE, $side_of_link='major', $sort_by=NULL, $dependant=NULL, $exclusive=NULL)
374  {
375  // if the wanted link type is not the type of links
376  // that this bridge allows, lets return now
377  if (!($this->ldap_shdw_link_type & $link_types)) {
378  return Array();
379  }
380 
381  if ($dependant || $exclusive) {
382  return Array();
383  }
384 
385  $id_parts = explode(':', $assetid);
386  if (isset($id_parts[1])) $assetid = $id_parts[1];
387 
388  if (!is_array($type_code)) {
389  if (empty($type_code)) {
390  $type_code = Array();
391  } else {
392  $type_code = Array($type_code);
393  }
394  }
395  $type_code_key = implode('-', $type_code);
396 
397  // the attribute mappings to the LDAP schemas
398  $attrs = $this->attr('attributes');
399 
400  if (!isset($this->_tmp['getLinks'][$assetid][$side_of_link][$type_code_key])) {
401 
402  if ($side_of_link == 'minor') {
403 
404  // we'll get the direct parent above us using our DN
405  $minorid = substr($assetid, strpos($assetid, ',') +1);
406  if ($minorid == $this->attr('root_dn')) {
407  // the parent is the bridge
408  $links[] = Array(
409  'linkid' => 0,
410  'majorid' => $this->id,
411  'major_type_code' => $this->type(),
412  'minorid' => $this->id.':'.$assetid,
413  'value' => '',
414  'link_type' => $this->ldap_shdw_link_type,
415  'is_dependant' => FALSE,
416  'is_exclusive' => FALSE,
417  'sort_order' => 0,
418  'locked' => 0,
419  );
420 
421  } else {
422  $asset = $this->getAsset($this->id.':'.$minorid);
423 
424  if (!empty($type_code)) {
425  if ($asset->type() == 'ldap_user_group') {
426  if (!((in_array('ldap_user_group', $type_code)) || (!$strict_type_code && in_array('user_group', $type_code)))) {
427  return Array();
428  }
429  } else if ($asset->type() == 'ldap_backend_user') {
430  if (!((in_array('ldap_backend_user', $type_code)) || (!$strict_type_code && in_array('user', $type_code)) || (!$strict_type_code && in_array('ldap_user', $type_code)))) {
431  return Array();
432  }
433  } else if ($asset->type() == 'ldap_backend_user') {
434  if (!((in_array('ldap_simple_edit_user', $type_code)) || (!$strict_type_code && in_array('user', $type_code)) || (!$strict_type_code && in_array('ldap_user', $type_code)))) {
435  return Array();
436  }
437  } else if ($asset->type() == 'ldap_user') {
438  if (!((in_array('ldap_user', $type_code)) || (!$strict_type_code && in_array('user', $type_code)))) {
439  return Array();
440  }
441  }
442  }
443 
444  $links[] = Array(
445  'linkid' => 0,
446  'majorid' => $asset->id,
447  'major_type_code' => $asset->type(),
448  'minorid' => $this->id.':'.$assetid,
449  'value' => '',
450  'link_type' => $this->ldap_shdw_link_type,
451  'is_dependant' => FALSE,
452  'is_exclusive' => FALSE,
453  'sort_order' => 0,
454  'locked' => 0,
455  );
456  }
457 
458  } else {
459 
460  $entries = NULL;
461 
462  $attr = $this->attr('attributes');
463  $user_attrs = $this->attr('user_attributes');
464  $sort_by = (!empty($user_attrs['sort_by'])) ? $user_attrs['sort_by'] : NULL;
465 
466  // If the group defines its own members, use the "Group Members" attribute to
467  // provide links to its members. Note that this is mandatory in Active Directory
468  // so if nothing is provided, the default "member" will be used.
469  if (($this->attr('system_type') == 'activedirectory') && empty($attr['gm'])) {
470  $attr['gm'] = 'member';
471  }
472  if ($assetid != $this->id) {
473  $asset = $this->getAsset($this->id.':'.$assetid);
474  if ($asset->type() == 'ldap_user_group' && !empty($attr['gm']) && isset($asset->vars[$attr['gm']])) {
475  $members = $asset->vars[$attr['gm']];
476  $entries = Array();
477  foreach ($members as $dn) {
478  $user = $this->getAsset($this->id.':'.$dn, '', FALSE, TRUE);
479  // dn of user group was stripped out in construction, but we need it this time
480  if (!is_null($user)){
481  $user->vars['dn'] = $dn;
482  $entries[$dn] = $user->vars;
483  }
484  }
485  if (!empty($sort_by)){
486  uasort($entries, create_function('$a,$b',
487  '$a = (isset($a[\''.$sort_by.'\'][\'value\'])) ? $a[\''.$sort_by.'\'][\'value\'] : "";
488  $b = (isset($b[\''.$sort_by.'\'][\'value\'])) ? $b[\''.$sort_by.'\'][\'value\'] : "";
489  if ($a == $b) {
490  return 0;
491  }
492  return ($a < $b) ? -1 : 1;'
493  )
494  );
495  }
496  }
497  }
498 
499  if (is_null($entries)) {
500  $ldap = @$this->connectToLdap();
501  if (is_null($ldap) || is_null($ldap->ptr)) return Array();
502 
503  if ($assetid == $this->id) {
504  $base_dn = $this->attr('root_dn');
505  } else {
506  $base_dn = $assetid;
507  }
508 
509  $filter = '';
510  foreach ($this->_group_types as $key => $value) {
511  if (empty($filter)) {
512  $filter = '(objectClass='.$key.')';
513  } else {
514  $filter = '(|'.$filter.'(objectClass='.$key.'))';
515  }
516  }
517  foreach ($this->_user_types as $key => $value) {
518  if (empty($filter)) {
519  $filter = '(objectClass='.$key.')';
520  } else {
521  $filter = '(|'.$filter.'(objectClass='.$key.'))';
522  }
523  }
524 
525  $base_dn = $this->decodeString($base_dn);
526 
527  // Attributes representing the objectclass values are always required + attribute used for sorting
528  $sort_attr = (!empty($sort_by)) ? Array($sort_by) : Array();
529  $required_attrs = array_values(array_unique(array_merge($attr, $sort_attr, Array('c', 'o', 'ou', 'cn', 'dc', 'objectclass'))));
530  $result = $ldap->search($base_dn, $filter, $sort_by, FALSE, TRUE, $required_attrs);
531 
532  if (!$result) {
533  $ldap->disconnect();
534  return Array();
535  }
536 
537  $entries = $ldap->getEntries($result);
538  if (!$entries['count']) {
539  $ldap->disconnect();
540  return Array();
541  }
542  unset($entries['count']);
543 
544  $ldap->disconnect();
545  }//end if is_null
546 
547  $links = Array();
548 
549  $i = 0;
550  foreach ($entries as $data) {
551 
552  $type = '';
553  if (isset($data['objectclass']['count'])) {
554  unset($data['objectclass']['count']);
555  }
556 
557  if (isset($data['objectclass']['value'])) {
558  $data['objectclass'] = $data['objectclass']['value'];
559  }
560 
561  foreach ($data['objectclass'] as $class) {
562  $class = strtolower($class);
563  foreach ($this->_group_types as $key => $value) {
564  if ($class == $key) {
565  if (!isset($attrs[$value])) {
566  $attrs[$value] = $value;
567  }
568 
569  if (!isset($data[$attrs[$value]][0])) {
570  continue(3);
571  }
572 
573  $name = $data[$attrs[$value]][0];
574  $type = 'ldap_user_group';
575  }
576  }
577 
578  // if this container is not a group, check the $result to see if it is a user
579  if (empty($type)) {
580  foreach ($this->_user_types as $key => $value) {
581  if ($class == $key) {
582  if (!isset($attrs[$value])) {
583  $attrs[$value] = $value;
584  }
585 
586  if ((!isset($data[$attrs[$value]][0]) && !isset($data[$attrs[$value]]['value']))) {
587  continue(2);
588  }
589 
590  if (isset($data[$attrs[$value]]['value']) && isset($data[$attrs[$value]]['value'][0])) {
591  $name = $data[$attrs[$value]]['value'][0];
592  } else {
593  $name = $data[$attrs[$value]][0];
594  }
595  $type = $this->attr('user_type');
596  }
597  }
598  }
599  if (!empty($type)) break;
600  }//end foreach
601 
602  if (empty($type)) continue;
603  if (!empty($type_code)) {
604 
605  if ($type == 'ldap_user_group') {
606  if (!in_array('user_group', $type_code) && !in_array('ldap_user_group', $type_code)) {
607  continue;
608  }
609  } else {
610  // work out the type code we want to list
611  if ($this->attr('user_type') == 'ldap_backend_user') {
612  $all_types = Array(
613  'user',
614  'ldap_user',
615  'ldap_simple_edit_user',
616  'ldap_backend_user',
617  );
618  } else if ($this->attr('user_type') == 'ldap_simple_edit_user') {
619  $all_types = Array(
620  'user',
621  'ldap_user',
622  'ldap_simple_edit_user',
623  );
624  } else {
625  // ldap_user
626  $all_types = Array(
627  'user',
628  'ldap_user',
629  );
630  }
631  $found = array_intersect($all_types, $type_code);
632  if (empty($found)) continue;
633  }
634 
635  }
636 
637  // find the DN for the asset
638  // make sure we have dn
639  if (!isset($data['dn']) && isset($data['distinguishedname'])) {
640  $data['dn'] = $data['distinguishedname'];
641  }
642 
643  if (is_array($data['dn'])) {
644  $dn = array_shift($data['dn']);
645  } else {
646  $dn = $data['dn'];
647  }
648 
649  $links[] = Array(
650  'linkid' => 0,
651  'majorid' => $this->id,
652  'minorid' => $this->id.':'.$this->encodeString($dn),
653  'minor_type_code' => $type,
654  'value' => '',
655  'link_type' => $this->ldap_shdw_link_type,
656  'is_dependant' => FALSE,
657  'is_exclusive' => FALSE,
658  'sort_order' => $i,
659  'locked' => 0,
660  );
661  $i++;
662 
663  }//end foreach entries
664 
665  }//end else side_of_link
666 
667  $this->_tmp['getLinks'][$assetid][$side_of_link][$type_code_key] = $links;
668  }//end if isset
669 
670  return $this->_tmp['getLinks'][$assetid][$side_of_link][$type_code_key];
671 
672  }//end getLinks()
673 
674 
690  function getParents($assetid, $type_code='', $strict_type_code=TRUE)
691  {
692  $id_parts = explode(':', $assetid);
693  if (isset($id_parts[1])) $assetid = $id_parts[1];
694 
695  $parents = Array();
696  if (!is_array($type_code)) {
697  $type_code = Array($type_code);
698  }
699 
700  // Bug Fix #4487 - allowing 'ldap_user_group' as a valid type code to return data
701  $valid_types = Array('user_group', 'ldap_user_group');
702  $found_type = array_intersect($valid_types, $type_code);
703 
704  if (empty($found_type)) {
705  return Array();
706  }
707 
708  if (!isset($this->_tmp['getParents'][$assetid])) {
709  $ldap = @$this->connectToLdap();
710  if (is_null($ldap) || is_null($ldap->ptr)) return Array();
711 
712  // the attribute mappings to the LDAP schemas
713  $attrs = $this->attr('attributes');
714  $assetid = $this->decodeString($assetid);
715 
716  $result = $ldap->search($assetid,'(objectClass=*)', NULL, FALSE, FALSE, array_merge(array_values($attrs), Array('objectclass')));
717  if (!$result) return Array();
718 
719  $data = $ldap->getEntries($result);
720  if (!$data['count']) {
721  $ldap->disconnect();
722  return Array();
723  }
724  $data = $data[0];
725 
726  $mo_groups = Array();
727 
728  if (isset($attrs['mo']) && isset($data[$attrs['mo']])) {
729  // User defines the groups it is a part of
730  $mo_groups = $data[$attrs['mo']];
731  if (!$mo_groups['count']) $mo_groups = Array();
732  unset($mo_groups['count']);
733  } else if (isset($attrs['gm'])) {
734  // Group defines its members
735  $base_dn = $this->attr('root_dn');
736  $base_dn = $this->decodeString($base_dn);
737  $result = $ldap->search($base_dn, '('.$attrs['gm'].'='.$ldap->escape_filter_value($assetid).')', NULL, TRUE, TRUE, array_merge(array_values($attrs), Array('objectclass')));
738  if ($result) {
739  $groups = $ldap->getEntries($result);
740  if (!$groups['count']) $mo_groups = Array();
741  unset($groups['count']);
742  foreach ($groups as $group_data) {
743  $mo_groups[] = $group_data['dn'];
744  }
745  }
746  }
747 
748  // also add in groups based on our DN
749  $ou_groups = Array();
750  $matches = Array();
751  $reg_expression = '|ou=([^,]+),(.*)|i';
752  $reg_string = substr($assetid, strpos($assetid, ',') + 1);
753 
754  $matching = TRUE;
755  while ($matching){
756  $matches = Array();
757  preg_match_all($reg_expression, $reg_string, $matches);
758  if (!empty($matches[1])) {
759  $reg_string = array_shift($matches[2]);
760  $ou_groups[array_shift($matches[1])] = $reg_string;
761  } else {
762  $matching = FALSE;
763  }
764  }
765 
766  foreach ($mo_groups as $group_name) {
767  $group_name = $this->decodeString($group_name);
768  $result = $ldap->search($group_name, '(objectClass=*)', NULL, FALSE, FALSE, array_merge(array_values($attrs), Array('objectclass')));
769  if (!$result) continue;
770  $group_data = $ldap->getEntries($result);
771  if ($group_data['count'] > 0) {
772  $parents[$this->id.':'.$group_data[0]['dn']] = 'ldap_user_group';
773  }
774  }
775 
776  foreach ($ou_groups as $group_name => $group_dn) {
777  $group_name = $this->decodeString($group_name);
778  $ou_value = (isset($attrs['ou']) && $attrs['ou'] != '') ? $attrs['ou'] : 'ou';
779  $result = $ldap->search($ou_value.'='.$group_name.','.$group_dn, '(objectClass=organizationalUnit)', NULL, FALSE, FALSE, array_merge(array_values($attrs), Array('objectclass')));
780  if (!$result) continue;
781  $group_data = $ldap->getEntries($result);
782 
783  if ($group_data['count'] > 0) {
784  $parents[$this->id.':'.$group_data[0]['dn']] = 'ldap_user_group';
785  }
786  }
787 
788  $ldap->disconnect();
789 
790  if (!empty($parents)) {
791  // Initialise the list of all parents to prevent infinite recursive loop.
792  // As we use the _tmp attribute of this object to store the list, we need
793  // a flag to unset it when we finish. Otherwise, the list will be used for
794  // the next clean getParents() method call and can cause incorrect results.
795  $bridge_getParents_first_level = FALSE;
796  if (!isset($this->_tmp['all_parents'])) {
797  // Include the asset ID so that it will not be the parent of itself
798  $this->_tmp['all_parents'] = Array($this->id.':'.$assetid => '');
799  $bridge_getParents_first_level = TRUE;
800  }
801 
802  // Filter the parents against the list of all parents so that we will not need
803  // to process a parent asset twice. That will also prevent infinite recursive loop.
804  $valid_parents = Array();
805  foreach ($parents as $parent_id => $parent_type_code) {
806  if (!isset($this->_tmp['all_parents'][$parent_id])) {
807  $valid_parents[$parent_id] = $parent_type_code;
808  }
809  }
810 
811  // Assign valid parents to the parent list.
812  $parents = $valid_parents;
813 
814  if (!empty($valid_parents)) {
815  // Add the valid parents to the list of all parents now to make them
816  // available in the recursive getParents() invocation below.
817  $this->_tmp['all_parents'] += $valid_parents;
818 
819  // Get the grandparents of the valid parents recursively.
820  $grandparents = Array();
821  foreach ($valid_parents as $parent_id => $parent_type_code) {
822  $grandparents += $GLOBALS['SQ_SYSTEM']->am->getParents($parent_id, $type_code, $strict_type_code);
823  }
824 
825  // Add the grandparents to the parent list
826  $parents += $grandparents;
827 
828  }
829 
830  if ($bridge_getParents_first_level) {
831  // Unset the list of all parents to prevent it from being used by
832  // the next first level call to this bridge's getParents() method.
833  unset($this->_tmp['all_parents']);
834  } else {
835  // We do not want to cache the parents in the array $this->_tmp['getParents']
836  // if they have been filtered against the list of all parents as they might be
837  // different from the original ones returned from the first level getParents() call.
838  return $parents;
839  }
840  }
841 
842  $this->_tmp['getParents'][$assetid] = $parents;
843 
844  }//end if not cached
845 
846  return $this->_tmp['getParents'][$assetid];
847 
848  }//end getParents()
849 
850 
871  function getChildren($assetid, $type_code='', $strict_type_code=TRUE, $dependant=NULL, $sort_by=NULL)
872  {
873  $id_parts = explode(':', $assetid);
874  if (isset($id_parts[1])) $assetid = $id_parts[1];
875 
876  if ($assetid != $this->id) {
877  // if we are using Active Directory, the tree structure does not quite work the same
878  // as openLDAP, so we can only do one level for now
879  if ($this->attr('system_type') == 'activedirectory') {
880  $links = $this->getLinks($assetid, SQ_LINK_TYPE_1 | SQ_LINK_TYPE_2, $type_code, $strict_type_code, 'major', $sort_by);
881 
882  $children = Array();
883  foreach ($links as $link_data) {
884  $children[$link_data['minorid']][0]['type_code'] = $link_data['minor_type_code'];
885  }
886  return $children;
887  }
888  }
889 
890  if (!is_array($type_code)) {
891  if (empty($type_code)) {
892  $type_code = Array();
893  } else {
894  $type_code = Array($type_code);
895  }
896  }
897 
898  $ldap = @$this->connectToLdap();
899  if (is_null($ldap) || is_null($ldap->ptr)) return Array();
900 
901  if ($assetid == $this->id) {
902  $base_dn = $this->attr('root_dn');
903  } else {
904  $base_dn = $assetid;
905  }
906 
907  // the attribute mappings to the LDAP schemas
908  $attrs = $this->attr('attributes');
909 
910  $base_dn = $this->decodeString($base_dn);
911  $result = $ldap->search($base_dn,'(objectClass=*)', NULL, TRUE, TRUE, array_merge(array_values($attrs), Array('objectclass')));
912  if (!$result) {
913  $ldap->disconnect();
914  return Array();
915  }
916  $entries = $ldap->getEntries($result);
917  if (!$entries['count']) {
918  $ldap->disconnect();
919  return Array();
920  }
921  unset($entries['count']);
922 
923  if ($sort_by == 'name') {
924  // we need to sort the entries by name
925  $sorted_array = Array();
926  foreach ($entries as $data) {
927 
928  $attr = '';
929 
930  unset($data['objectclass']['count']);
931  foreach ($data['objectclass'] as $class) {
932  $class = strtolower($class);
933  foreach ($this->_group_types as $key => $value) {
934  if ($class == $key) $attr = $value;
935  }
936  foreach ($this->_user_types as $key => $value) {
937  if ($class == $key) $attr = $value;
938  }
939  }
940  if (empty($attr)) continue;
941 
942  $sorted_array[strtolower($data[$attrs[$attr]][0])] = Array(
943  'dn' => $data['dn'],
944  'objectclass' => $data['objectclass'],
945  );
946  }//end foreach
947 
948  ksort($sorted_array, SORT_STRING);
949  $entries = $sorted_array;
950  }
951 
952 
953  // now that we have an array in the format we wanted (sorted or not)
954  // we can go through and construct our children array
955  $children = Array();
956 
957  // work out the type code we want to list
958  if ($this->attr('user_type') == 'ldap_backend_user') {
959  $all_types = Array(
960  'user',
961  'ldap_user',
962  'ldap_simple_edit_user',
963  'ldap_backend_user',
964  );
965  } else if ($this->attr('user_type') == 'ldap_simple_edit_user') {
966  $all_types = Array(
967  'user',
968  'ldap_user',
969  'ldap_simple_edit_user',
970  );
971  } else {
972  // ldap_user
973  $all_types = Array(
974  'user',
975  'ldap_user',
976  );
977  }
978  $user_groups = Array('user_group', 'ldap_user_group');
979  $found = array_intersect($all_types, $type_code);
980  $found_ug = array_intersect($user_groups, $type_code);
981 
982  foreach ($entries as $data) {
983  if ($data['dn'] == $assetid) continue;
984  unset($data['objectclass']['count']);
985  foreach ($data['objectclass'] as $class) {
986  $class = strtolower($class);
987  if (isset($this->_group_types[$class])) {
988  if (!empty($type_code) && empty($found_ug)) {
989  continue(2);
990  }
991  $children[$this->id.':'.$data['dn']][0]['type_code'] = 'ldap_user_group';
992  } else if (isset($this->_user_types[$class])) {
993  if (!empty($type_code) && empty($found)) {
994  continue(2);
995  }
996  $children[$this->id.':'.$data['dn']][0]['type_code'] = $this->attr('user_type');
997  }
998  }
999  }
1000 
1001  $ldap->disconnect();
1002 
1003  return $children;
1004 
1005  }//end getChildren()
1006 
1007 
1018  function getLineageFromURL($assetid, $protocol, $url)
1019  {
1020  $lineage = Array();
1021 
1022  $groups = explode(',', $assetid);
1023  for (reset($groups); NULL !== ($k = key($groups));) {
1024  $dn = implode(',', $groups);
1025  if ($dn == $this->attr('root_dn')) break;
1026 
1027  $asset = $this->getAsset($this->id.':'.$dn);
1028  $url = substr($asset->getURL(), strlen(current_protocol()) +3);
1029 
1030  $lineage[] = Array (
1031  'url' => $url,
1032  'assetid' => $this->id.':'.$dn,
1033  'name' => $asset->name,
1034  'short_name' => $asset->short_name,
1035  'type_code' => $asset->type(),
1036  'link_type' => SQ_LINK_TYPE_1,
1037  'protocol' => current_protocol(),
1038  );
1039 
1040  unset($groups[$k]);
1041  }
1042  return array_reverse($lineage);
1043 
1044  }//end getLineageFromURL()
1045 
1046 
1067  function getPermission($assetid, $permission, $granted=NULL, $and_greater=TRUE, $expand_groups=FALSE, $all_info=FALSE)
1068  {
1069  // All users underneath this bridge inherit the permissions of the bridge
1070  return $GLOBALS['SQ_SYSTEM']->am->getPermission($this->id, $permission, $granted, $and_greater, $expand_groups, $all_info);
1071 
1072  }//end getPermission()
1073 
1074 
1086  function setPermission($assetid, $userid, $permission, $granted)
1087  {
1088  return FALSE;
1089 
1090  }//end setPermission()
1091 
1092 
1103  function deletePermission($assetid, $userid, $permission)
1104  {
1105  return FALSE;
1106 
1107  }//end deletePermission()
1108 
1109 
1124  function getAssetInfo($assetids, $type_code=Array(), $strict_type_code=TRUE, $field='')
1125  {
1126  $info = Array();
1127  foreach ($assetids as $assetid) {
1128  if (!empty($field)) {
1129  if ($field == 'assetid') {
1130  $info[$assetid] = $assetid;
1131  } else if ($field == 'type_code') {
1132  $asset =& $this->getAsset($assetid);
1133  if (is_null($asset) === FALSE) {
1134  $info[$assetid] = $asset->type();
1135  } else {
1136  $info[$assetid] = '';
1137  }
1138  } else if (in_array($field , Array('version', 'name', 'short_name', 'status'))) {
1139  $asset =& $this->getAsset($assetid);
1140  if (is_null($asset) === FALSE) {
1141  $info[$assetid] = $asset->$field;
1142  } else {
1143  $info[$assetid] = '';
1144  }
1145  } else {
1146  $info[$assetid] = $this->$field;
1147  }
1148  } else {
1149  $asset =& $this->getAsset($assetid);
1150  if (is_null($asset) === FALSE) {
1151  $info[$assetid] = Array(
1152  'assetid' => $assetid,
1153  'type_code' => $asset->type(),
1154  'version' => $asset->version,
1155  'name' => $asset->name,
1156  'short_name' => $asset->short_name,
1157  'status' => $asset->status,
1158  'languages' => $this->languages,
1159  'charset' => $this->charset,
1160  'force_secure' => $this->force_secure,
1161  'created' => $this->created,
1162  'created_userid' => $this->created_userid,
1163  'updated' => $this->updated,
1164  'updated_userid' => $this->updated_userid,
1165  'published' => $this->published,
1166  'published_userid' => $this->published_userid,
1167  'status_changed' => $this->status_changed,
1168  'status_changed_userid' => $this->status_changed_userid,
1169  );
1170  } else {
1171  $info[$assetid] = Array();
1172  }
1173  }//end else
1174  }//end foreach assetids
1175 
1176  return $info;
1177 
1178  }//end getAssetInfo()
1179 
1180 
1192  function assetExists($assetids)
1193  {
1194  return FALSE;
1195 
1196  }//end assetExists()
1197 
1198 
1220  function getLink($assetid, $link_type=NULL, $type_code='', $strict_type_code=TRUE, $value=NULL, $side_of_link='major', $exclusive=NULL)
1221  {
1222  if ($type_code=='inbox') {
1223  return $links = Array(
1224  'linkid' => 0,
1225  'majorid' => $assetid,
1226  'minor_type_code' => 'inbox',
1227  'minorid' => $assetid.':inbox',
1228  'value' => '',
1229  'link_type' => $this->ldap_shdw_link_type,
1230  'is_dependant' => FALSE,
1231  'is_exclusive' => FALSE,
1232  'sort_order' => 0,
1233  'locked' => 0,
1234  );
1235  } else if ($type_code == 'user' && $side_of_link == 'minor') {
1236  $id_parts = explode(':', $assetid);
1237  if (isset($id_parts[2]) && $id_parts[2] == 'inbox') {
1238  return $links = Array(
1239  'linkid' => 0,
1240  'majorid' => $id_parts[0].':'.$id_parts[1],
1241  'major_type_code' => $this->attr('user_type'),
1242  'minorid' => $assetid,
1243  'value' => '',
1244  'link_type' => $this->ldap_shdw_link_type,
1245  'is_dependant' => FALSE,
1246  'is_exclusive' => FALSE,
1247  'sort_order' => 0,
1248  'locked' => 0,
1249  );
1250  }
1251  }
1252 
1253  return Array();
1254 
1255  }//end getLink()
1256 
1257 
1269  function getLinkById($linkid, $assetid=0, $side_of_link='major')
1270  {
1271  return Array();
1272 
1273  }//end getLinkById()
1274 
1275 
1297  function countLinks($assetid, $side_of_link='major', $link_types=0, $type_code='', $strict_type_code=TRUE, $ignore_linkid=0)
1298  {
1299  return 0;
1300 
1301  }//end countLinks()
1302 
1303 
1324  function getLinkByAsset($assetid, $other_assetid, $link_types=NULL, $value=NULL, $side_of_link='major', $force_array=FALSE, $dependant=NULL, $exclusive=NULL)
1325  {
1326  return Array();
1327 
1328  }//end getLinkByAsset()
1329 
1330 
1340  function getAllChildLinks($assetid, $link_type=0)
1341  {
1342  return Array();
1343 
1344  }//end getAllChildLinks()
1345 
1346 
1361  function updateLink($linkid, $link_type=NULL, $value=NULL, $sort_order=NULL)
1362  {
1363  return FALSE;
1364 
1365  }//end updateLink()
1366 
1367 
1377  function deleteAssetLink($linkid, $moving=FALSE)
1378  {
1379 
1380  return FALSE;
1381 
1382  }//end deleteAssetLink()
1383 
1384 
1397  function canCreateLink(&$major, &$minor, $link_type, $exclusive)
1398  {
1399  return FALSE;
1400 
1401  }//end canCreateLink()
1402 
1403 
1420  function createAssetLink(&$major, &$minor, $link_type, $value='', $sort_order=NULL, $dependant='0', $exclusive='0', $moving=FALSE)
1421  {
1422  return 0;
1423 
1424  }//end createAssetLink()
1425 
1426 
1435  function delete($release_lock)
1436  {
1437  if (parent::delete($release_lock)) {
1438  $this->_deleteStoredContents();
1439  return TRUE;
1440  }
1441 
1442  return FALSE;
1443 
1444  }//end delete()
1445 
1446 
1454  {
1455 
1456  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('db2');
1457  $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
1458 
1459  $sql = 'DELETE FROM sq_shdw_ast_lnk WHERE minorid LIKE :minorid';
1460 
1461  $query = MatrixDAL::preparePdoQuery($sql);
1462  MatrixDAL::bindValueToPdo($query, 'minorid', $this->id.':%');
1463  $result = MatrixDAL::execPdoQuery($query);
1464 
1465  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
1466  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
1467 
1468  return TRUE;
1469 
1470  }//end _deleteStoredContents()
1471 
1472 
1483  function paintUserDetails($info, &$o)
1484  {
1485  $show = $this->attr('user_attributes');
1486  if (!isset($show['show'])) {
1487  $show = Array();
1488  } else {
1489  $show = $show['show'];
1490  }
1491 
1492  if (is_null($o)) {
1493  ?><table border="0" cellspacing="2" cellpadding="2"><?php
1494  }
1495 
1496  // loop through each field to be shown
1497  foreach ($show as $field_name => $friendly_name) {
1498  if (!isset($info[$field_name])) {
1499  // field not defined
1500  continue;
1501  } else {
1502  $value = $info[$field_name]['value'];
1503  $count = 0;
1504  $multi = '';
1505  if (is_array($value)) {
1506  $count = count($value);
1507  $value = implode('<br />', $value);
1508  }
1509  if ($count > 1) $multi = ' ('.$count.' values)';
1510 
1511  if (!is_null($o)) {
1512  $o->openField($friendly_name.$multi);
1513  } else {
1514  ?><tr><td valign="top"><b><?php echo $friendly_name.$multi; ?></b></td><td valign="top"><?php
1515  }
1516  echo $value;
1517  if (!is_null($o)) {
1518  echo '<br />';
1519  // only print extra info if we are on the backend
1520  // TODO: Leaving this in by request, until we are sure all implementations work
1521  if (isset($info[$field_name]['attrid'])) {
1522  echo '<span style="color:#666">(attrid = '.$info[$field_name]['attrid'].')</span> ';
1523  }
1524  echo '<span style="color:#666">(type = '.$info[$field_name]['type'].')</span>';
1525  $o->closeField();
1526  } else {
1527  ?></td></tr><?php
1528  }
1529  }
1530  }//end foreach
1531 
1532  if (is_null($o)) {
1533  ?></table><?php
1534  }
1535 
1536  }//end paintUserDetails()
1537 
1538 
1548  function initUser(&$user, $data)
1549  {
1550 
1551  // the attribute mappings to the LDAP schemas
1552  $attrs = $this->attr('attributes');
1553  $user->_ldapid = $this->id;
1554 
1555  // set general object properties
1556  $user->id = $this->id.':'.$this->encodeString($data['dn']);
1557  foreach ($data['objectclass'] as $class) {
1558  $class = strtolower($class);
1559  foreach ($this->_user_types as $key => $value) {
1560  if (($class == $key) && isset($attrs[$value])) {
1561  $user->name = $data[$attrs[$value]][0];
1562  }
1563  }
1564  }
1565  if (empty($user->name)) {
1566  $user->name = translate('ldap_unknown_user');
1567  }
1568 
1569  $user->name = $this->decodeString($user->name);
1570 
1571  $user->short_name = $user->name;
1572  $user->status = $this->status;
1573  $user->version = '0.1';
1574 
1575  // error_log('initUser: '.$user->name."($this->id, ".$this->attr('user_type').")");
1576 
1577  foreach ($data as $key => $value) {
1578  if (is_array($value)) {
1579  if (isset($value['count'])) unset($value['count']);
1580  if (count($value) > 1) {
1581  $user->vars[$key] = Array(
1582  'value' => $value,
1583  'type' => 'serialise',
1584  'attrid' => 0,
1585  );
1586  } else {
1587  $user->vars[$key] = Array(
1588  'value' => array_shift($value),
1589  'type' => 'text',
1590  'attrid' => 0,
1591  );
1592  }
1593  }
1594  }
1595 
1596  // set the data paths
1597  $user->_loadDataPaths();
1598 
1599  // set variable values
1600  $user->vars['dn']['value'] = $data['dn'];
1601  $user->vars['dn']['type'] = 'text';
1602 
1603  if (isset($attrs['uid']) && isset($data[$attrs['uid']])) {
1604  $user->vars['username']['value'] = $data[$attrs['uid']][0];
1605  } else {
1606  $user->vars['username']['value'] = $data['dn'];
1607  }
1608 
1609  $user->vars['username']['type'] = 'text';
1610 
1611  if (isset($attrs['email']) && isset($data[$attrs['email']])) {
1612  $user->vars['email']['value'] = $data[$attrs['email']][0];
1613  } else {
1614  $user->vars['email']['value'] = '';
1615  }
1616 
1617  $user->vars['email']['type'] = 'email';
1618 
1619  if (isset($attrs['fn']) && isset($data[$attrs['fn']])) {
1620  $user->vars['first_name']['value'] = $data[$attrs['fn']][0];
1621  } else {
1622  $user->vars['first_name']['value'] = '';
1623  }
1624 
1625  $user->vars['first_name']['type'] = 'text';
1626 
1627  if (isset($attrs['sn']) && isset($data[$attrs['sn']])) {
1628  $user->vars['last_name']['value'] = $data[$attrs['sn']][0];
1629  } else {
1630  $user->vars['last_name']['value'] = '';
1631  }
1632 
1633  $user->vars['last_name']['type'] = 'text';
1634 
1635  }//end initUser()
1636 
1637 
1648  function encodeString($string)
1649  {
1650 
1651  if (is_array($string)) {
1652  foreach ($string as $key => $value) {
1653  $string[$key] = $this->encodeString($value);
1654  }
1655  } else {
1656  $string = str_replace('&', '%26', $string);
1657  }
1658 
1659  return $string;
1660 
1661  }//end encodeString()
1662 
1663 
1674  function decodeString($string)
1675  {
1676 
1677  if (is_array($string)) {
1678  foreach ($string as $key => $value) {
1679  $string[$key] = $this->decodeString($value);
1680  }
1681  } else {
1682  $string = str_replace('%26', '&', $string);
1683  }
1684 
1685  return $string;
1686 
1687  }//end decodeString()
1688 
1689 
1698  public function getAssetMapAssetInfo($assetid)
1699  {
1700  return Array();
1701 
1702  }//end getAssetMapAssetInfo()
1703 
1704 
1705 }//end class
1706 
1707 ?>