CWIS Developer Documentation
PrivilegeSet.php
Go to the documentation of this file.
1 <?PHP
2 #
3 # FILE: PrivilegeSet.php
4 #
5 # Part of the Collection Workflow Integration System (CWIS)
6 # Copyright 2013 Edward Almasy and Internet Scout Research Group
7 # http://scout.wisc.edu/cwis/
8 #
9 
16 class PrivilegeSet {
17 
18  # used as a field ID in conditions to test whether a resources is
19  # available as part of the privilege check
20  const HAVE_RESOURCE = -1;
21 
29  function __construct($Data = NULL)
30  {
31  # if privilege data supplied
32  if ($Data !== NULL)
33  {
34  # if data is in legacy form (an array of privileges)
35  if (is_array($Data))
36  {
37  # set internal privilege set from array
38  $this->Privileges = $Data;
39  }
40  else
41  {
42  # set internal values from data
43  $this->LoadFromData($Data);
44  }
45  }
46  }
47 
57  function Data($NewValue = NULL)
58  {
59  # if new data supplied
60  if ($NewValue !== NULL)
61  {
62  # unpack privilege data and load
63  $this->LoadFromData($NewValue);
64  }
65 
66  # serialize current data and return to caller
67  $Data = array();
68  if (count($this->Privileges))
69  {
70  foreach ($this->Privileges as $Priv)
71  {
72  $Data["Privileges"][] = is_object($Priv)
73  ? array("SUBSET" => $Priv->Data())
74  : $Priv;
75  }
76  }
77  $Data["Logic"] = $this->Logic;
78  return serialize($Data);
79  }
80 
91  function MeetsRequirements(CWUser $User, $Resource = self::NO_RESOURCE)
92  {
93  # when there are no requirements, then every user meets them
94  $Satisfied = TRUE;
95 
96  # for each privilege requirement
97  foreach ($this->Privileges as $Priv)
98  {
99  # if privilege is actually a privilege subgroup
100  if (is_object($Priv))
101  {
102  # check if the subgroup is satisfied
103  $Satisfied = $Priv->MeetsRequirements($User, $Resource);
104  }
105  # else if privilege is actually a condition
106  elseif (is_array($Priv))
107  {
108  # check if condition is satisfied for the given resource
109  $Satisfied = $this->MeetsCondition($Priv, $Resource, $User);
110  }
111  # else privilege is actually a privilege
112  else
113  {
114  # check if user has the spcified privilege
115  $Satisfied = $User->HasPriv( $Priv );
116  }
117 
118  # for AND logic, we can bail as soon as the first
119  # condition is not met
120  if ($this->Logic == "AND")
121  {
122  if (!$Satisfied)
123  {
124  break;
125  }
126  }
127  # conversely, for OR logic, we can bail as soon as any
128  # condition is met
129  else
130  {
131  if ($Satisfied)
132  {
133  break;
134  }
135  }
136  }
137 
138  # report result of the test back to caller
139  return $Satisfied;
140  }
141 
148  function AddPrivilege($Privilege)
149  {
150  # add privilege if not currently in set
151  if (!$this->IncludesPrivilege($Privilege))
152  {
153  if (is_object($Privilege)) { $Privilege = $Privilege->Id(); }
154  $this->Privileges[] = $Privilege;
155  }
156  }
157 
164  function RemovePrivilege($Privilege)
165  {
166  # remove privilege if currently in set
167  if ($this->IncludesPrivilege($Privilege))
168  {
169  if (is_object($Privilege)) { $Privilege = $Privilege->Id(); }
170  $Index = array_search($Privilege, $this->Privileges);
171  unset($this->Privileges[$Index]);
172  }
173  }
174 
180  function IncludesPrivilege($Privilege)
181  {
182  # check whether privilege is in our list and report to caller
183  if (is_object($Privilege)) { $Privilege = $Privilege->Id(); }
184  return $this->IsInPrivilegeData($Privilege) ? TRUE : FALSE;
185  }
186 
195  function GetPrivilegeInfo()
196  {
197  # grab privilege information and add logic
198  $Info = $this->Privileges;
199  $Info["Logic"] = $this->Logic;
200 
201  # return privilege info array to caller
202  return $Info;
203  }
204 
211  function GetPrivilegeList()
212  {
213  # create list of privileges with conditions stripped out
214  $List = array();
215  foreach ($this->Privileges as $Priv)
216  {
217  if (!is_array($Priv)) { $List[] = $Priv; }
218  }
219 
220  # return list of privileges to caller
221  return $List;
222  }
223 
238  function AddCondition($Field, $Value = NULL, $Operator = "==")
239  {
240  # get field ID
241  $FieldId = is_object($Field) ? $Field->Id() : $Field;
242 
243  # set up condition array
244  $Condition = array(
245  "FieldId" => intval($FieldId),
246  "Operator" => trim($Operator),
247  "Value" => $Value);
248 
249  # if condition is not already in set
250  if (!$this->IsInPrivilegeData($Condition))
251  {
252  # add condition to privilege set
253  $this->Privileges[] = $Condition;
254  }
255  }
256 
268  function RemoveCondition($Field, $Value = NULL, $Operator = "==")
269  {
270  # get field ID
271  $FieldId = is_object($Field) ? $Field->Id() : $Field;
272 
273  # set up condition array
274  $Condition = array(
275  "FieldId" => intval($FieldId),
276  "Operator" => trim($Operator),
277  "Value" => $Value);
278 
279  # if condition is in set
280  if ($this->IsInPrivilegeData($Condition))
281  {
282  # remove condition from privilege set
283  $Index = array_search($Condition, $this->Privileges);
284  unset($this->Privileges[$Index]);
285  }
286  }
287 
292  function AddSet(PrivilegeSet $Set)
293  {
294  # if subgroup is not already in set
295  if (!$this->IsInPrivilegeData($Set))
296  {
297  # add subgroup to privilege set
298  $this->Privileges[] = $Set;
299  }
300  }
301 
311  function AllRequired($NewValue = NULL)
312  {
313  if ($NewValue !== NULL)
314  {
315  $this->Logic = $NewValue ? "AND" : "OR";
316  }
317  return ($this->Logic == "AND") ? TRUE : FALSE;
318  }
319 
326  {
327  $Info = $this->GetPrivilegeInfo();
328  unset ($Info["Logic"]);
329 
330  $Result = array();
331  foreach ($Info as $Item)
332  {
333  if (is_object($Item))
334  {
335  $Result = array_merge($Result, $Item->PrivilegeFlagsChecked() );
336  }
337  elseif (!is_array($Item))
338  {
339  $Result []= $Item;
340  }
341  }
342  return array_unique($Result);
343  }
344 
351  function FieldsWithUserComparisons($ComparisonType)
352  {
353  $Info = $this->GetPrivilegeInfo();
354  unset ($Info["Logic"]);
355 
356  $Result = array();
357  foreach ($Info as $Item)
358  {
359  if (is_object($Item))
360  {
361  $Result = array_merge(
362  $Result,
363  $Item->FieldsWithUserComparisons( $ComparisonType ) );
364  }
365  elseif (is_array($Item))
366  {
367  if ($Item["Operator"] == $ComparisonType)
368  {
369  $Field = new MetadataField($Item["FieldId"]);
370 
371  if ($Field->Type() == MetadataSchema::MDFTYPE_USER)
372  {
373  $Result []= $Item["FieldId"];
374  }
375  }
376  }
377  }
378 
379  return array_unique($Result);
380  }
381 
382  # ---- PRIVATE INTERFACE -------------------------------------------------
383 
384  private $Privileges = array();
385  private $Logic = "OR";
386 
387  const NO_RESOURCE = "XXX NO RESOURCE XXX";
388 
393  private function LoadFromData($Serialized)
394  {
395  # save calling context in case load causes out-of-memory crash
396  $GLOBALS["AF"]->RecordContextInCaseOfCrash();
397 
398  # unpack new data
399  $Data = unserialize($Serialized);
400 
401  # unpack privilege data (if available) and load
402  if (array_key_exists("Privileges", $Data))
403  {
404  $this->Privileges = array();
405  foreach ($Data["Privileges"] as $Priv)
406  {
407  if (is_array($Priv) && array_key_exists("SUBSET", $Priv))
408  {
409  $Subset = new PrivilegeSet();
410  $Subset->LoadFromData($Priv["SUBSET"]);
411  $this->Privileges[] = $Subset;
412  }
413  else
414  {
415  $this->Privileges[] = $Priv;
416  }
417  }
418  }
419 
420  # load logic if available
421  if (array_key_exists("Logic", $Data))
422  {
423  $this->Logic = $Data["Logic"];
424  }
425  }
426 
434  private function MeetsCondition($Condition, $Resource, $User)
435  {
436  # if condition is a check for whether a resource is available
437  if ($Condition["FieldId"] == self::HAVE_RESOURCE)
438  {
439  # return a result based on whether a resource is available
440  return ((bool)($Resource == self::NO_RESOURCE)
441  != (bool)$Condition["Value"]) ? TRUE : FALSE;
442  }
443  # else if no resource is available
444  elseif ($Resource == self::NO_RESOURCE)
445  {
446  # return a result that in effect ignores the condition
447  return ($this->Logic == "AND") ? TRUE : FALSE;
448  }
449  # else if resource is valid
450  elseif ($Resource instanceof Resource)
451  {
452  # pre-process condition parameters based on type of field
453  try
454  {
455  $Field = new MetadataField($Condition["FieldId"]);
456  }
457  catch (Exception $e)
458  {
459  # if the field in a condition was invalid, the condition fails
460  return FALSE;
461  }
462 
463  $Operator = $Condition["Operator"];
464  $Value = $Condition["Value"];
465  $FieldValue = $Resource->Get($Field, TRUE);
466  switch ($Field->Type())
467  {
469  # if supplied value is NULL
470  if ($Value === NULL)
471  {
472  $Value = $User->Id();
473  }
474 
475  # convert field value to user ID
476  $FieldValue = $FieldValue->Id();
477  break;
478 
481  # date field values are Date objects, so handle those
482  if ($FieldValue instanceof Date)
483  {
484  $FieldValue = strtotime($FieldValue->Formatted());
485  }
486 
487  # timestamp field values are just the date/time string
488  else
489  {
490  $FieldValue = strtotime($FieldValue);
491  }
492 
493  # use the current time for the value if it's NULL
494  if ($Value === NULL)
495  {
496  $Value = time();
497  }
498 
499  # otherwise, parse the value to get a numeric timestamp
500  else
501  {
502  $Value = strtotime($Value);
503  }
504  break;
505 
508  break;
509 
511  # for options, construct a list of the CNIDs in this field
512  $NewValue = array();
513  foreach ($FieldValue as $CName)
514  {
515  $NewValue []= $CName->Id();
516  }
517  $FieldValue = $NewValue;
518  break;
519 
520  default:
521  throw new Exception("Unsupported metadata field type ("
522  .print_r($Field->Type(), TRUE)
523  .") for condition in privilege set.");
524  break;
525  }
526 
527  # compare field value and supplied value using specified operator
528  switch ($Operator)
529  {
530  case "==":
531  if (is_array($FieldValue))
532  {
533  # equality against an option field is a 'contains' condition,
534  # true if the specified value is one of those set
535  $Result = FALSE;
536  foreach ($FieldValue as $FieldValue_i)
537  {
538  $Result |= ($FieldValue_i == $Value);
539  }
540  }
541  else
542  {
543  $Result = ($FieldValue == $Value);
544  }
545  break;
546 
547  case "!=":
548  if (is_array($FieldValue))
549  {
550  # not equal against an option field is 'does not contains',
551  # true as long as the spcified value is not one of those set
552  $Result = TRUE;
553  foreach ($FieldValue as $FieldValue_i)
554  {
555  $Result &= ($FieldValue_i != $Value);
556  }
557  }
558  else
559  {
560  $Result = ($FieldValue != $Value);
561  }
562  break;
563 
564  case "<":
565  $Result = ($FieldValue < $Value);
566  break;
567 
568  case ">":
569  $Result = ($FieldValue > $Value);
570  break;
571 
572  case "<=":
573  $Result = ($FieldValue <= $Value);
574  break;
575 
576  case ">=":
577  $Result = ($FieldValue >= $Value);
578  break;
579 
580  default:
581  throw new Exception("Unsupported condition operator ("
582  .print_r($Operator, TRUE).") in privilege set.");
583  break;
584  }
585 
586  # report to caller whether condition was met
587  return $Result ? TRUE : FALSE;
588  }
589  else
590  {
591  # error out because resource was illegal
592  throw new Exception("Invalid Resource passed in for privilege"
593  ." set comparison.");
594  }
595  }
596 
605  private function IsInPrivilegeData($Item)
606  {
607  # step through privilege data
608  foreach ($this->Privileges as $Priv)
609  {
610  # report to caller if item is found
611  if (is_object($Item))
612  {
613  if (is_object($Priv) && ($Item == $Priv)) { return TRUE; }
614  }
615  elseif (is_array($Item))
616  {
617  if (is_array($Priv) && ($Item == $Priv)) { return TRUE; }
618  }
619  elseif ($Item == $Priv) { return TRUE; }
620  }
621 
622  # report to caller that item is not in privilege data
623  return FALSE;
624  }
625 }
AddSet(PrivilegeSet $Set)
Add subgroup of privileges/conditions to set.
HasPriv($Privilege, $Privileges=NULL)
Determine if a user has a given privilege, or satisfies the conditions specified by a given privilege...
Definition: CWUser.php:102
Set of privileges used to access resource information or other parts of the system.
MeetsRequirements(CWUser $User, $Resource=self::NO_RESOURCE)
Determine if a given user meets the requirements specified by this PrivilegeSet.
PHP
Definition: OAIClient.php:39
__construct($Data=NULL)
Class constructor, used to create a new set or reload an existing set from previously-constructed dat...
IncludesPrivilege($Privilege)
Check whether this privilege set includes the specified privilege.
GetPrivilegeInfo()
Get privilege information as an array, with numerical indexes except for the logic, which is contained in a element with the index "Logic".
PrivilegeFlagsChecked()
List which privilege flags (e.g.
GetPrivilegeList()
Get list of privileges.
Object representing a locally-defined type of metadata field.
Data($NewValue=NULL)
Get/set privilege set data, in the form of an opaque string.
Represents a "resource" in CWIS.
Definition: Resource.php:13
FieldsWithUserComparisons($ComparisonType)
List which fields in this privset are involved in UserIs or UserIsNot comparisons for this privilege ...
AddPrivilege($Privilege)
Add specified privilege to set.
CWIS-specific user class.
Definition: CWUser.php:13
AddCondition($Field, $Value=NULL, $Operator="==")
Add condition to privilege set.
RemovePrivilege($Privilege)
Remove specified privilege from set.
const HAVE_RESOURCE
AllRequired($NewValue=NULL)
Get/set whether all privileges/conditions in set are required (i.e.
RemoveCondition($Field, $Value=NULL, $Operator="==")
Remove condition from privilege set.