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 
17 {
18 
19  # used as a field ID in conditions to test whether a resources is
20  # available as part of the privilege check
21  const HAVE_RESOURCE = -1;
22 
30  public function __construct($Data = NULL)
31  {
32  # if privilege data supplied
33  if ($Data !== NULL)
34  {
35  # if data is in legacy form (an array of privileges)
36  if (is_array($Data))
37  {
38  # set internal privilege set from array
39  $this->Privileges = $Data;
40  }
41  else
42  {
43  # set internal values from data
44  $this->LoadFromData($Data);
45  }
46  }
47  }
48 
58  public function Data($NewValue = NULL)
59  {
60  # if new data supplied
61  if ($NewValue !== NULL)
62  {
63  # unpack privilege data and load
64  $this->LoadFromData($NewValue);
65  }
66 
67  # serialize current data and return to caller
68  $Data = array();
69  if (count($this->Privileges))
70  {
71  foreach ($this->Privileges as $Priv)
72  {
73  $Data["Privileges"][] = is_object($Priv)
74  ? array("SUBSET" => $Priv->Data())
75  : $Priv;
76  }
77  }
78  $Data["Logic"] = $this->Logic;
79  return serialize($Data);
80  }
81 
92  public function MeetsRequirements(CWUser $User, $Resource = self::NO_RESOURCE)
93  {
94  # when there are no requirements, then every user meets them
95  $Satisfied = TRUE;
96 
97  # for each privilege requirement
98  foreach ($this->Privileges as $Priv)
99  {
100  # if privilege is actually a privilege subgroup
101  if (is_object($Priv))
102  {
103  # check if the subgroup is satisfied
104  $Satisfied = $Priv->MeetsRequirements($User, $Resource);
105  }
106  # else if privilege is actually a condition
107  elseif (is_array($Priv))
108  {
109  # check if condition is satisfied for the given resource
110  $Satisfied = $this->MeetsCondition($Priv, $Resource, $User);
111  }
112  # else privilege is actually a privilege
113  else
114  {
115  # check if user has the spcified privilege
116  $Satisfied = $User->HasPriv( $Priv );
117  }
118 
119  # for AND logic, we can bail as soon as the first
120  # condition is not met
121  if ($this->Logic == "AND")
122  {
123  if (!$Satisfied)
124  {
125  break;
126  }
127  }
128  # conversely, for OR logic, we can bail as soon as any
129  # condition is met
130  else
131  {
132  if ($Satisfied)
133  {
134  break;
135  }
136  }
137  }
138 
139  # report result of the test back to caller
140  return $Satisfied;
141  }
142 
149  public function AddPrivilege($Privileges)
150  {
151  # convert incoming value to array if needed
152  if (!is_array($Privileges))
153  {
154  $Privileges = array($Privileges);
155  }
156 
157  # for each privilege passed in
158  foreach ($Privileges as $Privilege)
159  {
160  # add privilege if not currently in set
161  if (!$this->IncludesPrivilege($Privilege))
162  {
163  if (is_object($Privilege)) { $Privilege = $Privilege->Id(); }
164  $this->Privileges[] = $Privilege;
165  }
166  }
167  }
168 
175  public function RemovePrivilege($Privilege)
176  {
177  # remove privilege if currently in set
178  if ($this->IncludesPrivilege($Privilege))
179  {
180  if (is_object($Privilege)) { $Privilege = $Privilege->Id(); }
181  $Index = array_search($Privilege, $this->Privileges);
182  unset($this->Privileges[$Index]);
183  }
184  }
185 
191  public function IncludesPrivilege($Privilege)
192  {
193  # check whether privilege is in our list and report to caller
194  if (is_object($Privilege)) { $Privilege = $Privilege->Id(); }
195  return $this->IsInPrivilegeData($Privilege) ? TRUE : FALSE;
196  }
197 
206  public function GetPrivilegeInfo()
207  {
208  # grab privilege information and add logic
209  $Info = $this->Privileges;
210  $Info["Logic"] = $this->Logic;
211 
212  # return privilege info array to caller
213  return $Info;
214  }
215 
222  public function GetPrivilegeList()
223  {
224  # create list of privileges with conditions stripped out
225  $List = array();
226  foreach ($this->Privileges as $Priv)
227  {
228  if (!is_array($Priv)) { $List[] = $Priv; }
229  }
230 
231  # return list of privileges to caller
232  return $List;
233  }
234 
249  public function AddCondition($Field, $Value = NULL, $Operator = "==")
250  {
251  # get field ID
252  $FieldId = is_object($Field) ? $Field->Id() : $Field;
253 
254  # set up condition array
255  $Condition = array(
256  "FieldId" => intval($FieldId),
257  "Operator" => trim($Operator),
258  "Value" => $Value);
259 
260  # if condition is not already in set
261  if (!$this->IsInPrivilegeData($Condition))
262  {
263  # add condition to privilege set
264  $this->Privileges[] = $Condition;
265  return TRUE;
266  }
267  return FALSE;
268  }
269 
281  public function RemoveCondition($Field, $Value = NULL, $Operator = "==")
282  {
283  # get field ID
284  $FieldId = is_object($Field) ? $Field->Id() : $Field;
285 
286  # set up condition array
287  $Condition = array(
288  "FieldId" => intval($FieldId),
289  "Operator" => trim($Operator),
290  "Value" => $Value);
291 
292  # if condition is in set
293  if ($this->IsInPrivilegeData($Condition))
294  {
295  # remove condition from privilege set
296  $Index = array_search($Condition, $this->Privileges);
297  unset($this->Privileges[$Index]);
298  return TRUE;
299  }
300  return FALSE;
301  }
302 
307  public function AddSet(PrivilegeSet $Set)
308  {
309  # if subgroup is not already in set
310  if (!$this->IsInPrivilegeData($Set))
311  {
312  # add subgroup to privilege set
313  $this->Privileges[] = $Set;
314  }
315  }
316 
326  public function AllRequired($NewValue = NULL)
327  {
328  if ($NewValue !== NULL)
329  {
330  $this->Logic = $NewValue ? "AND" : "OR";
331  }
332  return ($this->Logic == "AND") ? TRUE : FALSE;
333  }
334 
340  public function PrivilegeFlagsChecked()
341  {
342  $Info = $this->GetPrivilegeInfo();
343  unset ($Info["Logic"]);
344 
345  $Result = array();
346  foreach ($Info as $Item)
347  {
348  if (is_object($Item))
349  {
350  $Result = array_merge($Result, $Item->PrivilegeFlagsChecked() );
351  }
352  elseif (!is_array($Item))
353  {
354  $Result[]= $Item;
355  }
356  }
357  return array_unique($Result);
358  }
359 
366  public function FieldsWithUserComparisons($ComparisonType)
367  {
368  $Info = $this->GetPrivilegeInfo();
369  unset ($Info["Logic"]);
370 
371  $Result = array();
372  foreach ($Info as $Item)
373  {
374  if (is_object($Item))
375  {
376  $Result = array_merge(
377  $Result,
378  $Item->FieldsWithUserComparisons( $ComparisonType ) );
379  }
380  elseif (is_array($Item))
381  {
382  if ($Item["Operator"] == $ComparisonType &&
383  $Item["FieldId"] > 0 )
384  {
385  $Field = new MetadataField($Item["FieldId"]);
386 
387  if ($Field->Type() == MetadataSchema::MDFTYPE_USER)
388  {
389  $Result[]= $Item["FieldId"];
390  }
391  }
392  }
393  }
394 
395  return array_unique($Result);
396  }
397 
398  # ---- PRIVATE INTERFACE -------------------------------------------------
399 
400  private $Privileges = array();
401  private $Logic = "OR";
402 
403  const NO_RESOURCE = "XXX NO RESOURCE XXX";
404 
409  private function LoadFromData($Serialized)
410  {
411  # save calling context in case load causes out-of-memory crash
412  $GLOBALS["AF"]->RecordContextInCaseOfCrash();
413 
414  # unpack new data
415  $Data = unserialize($Serialized);
416 
417  # unpack privilege data (if available) and load
418  if (array_key_exists("Privileges", $Data))
419  {
420  $this->Privileges = array();
421  foreach ($Data["Privileges"] as $Priv)
422  {
423  if (is_array($Priv) && array_key_exists("SUBSET", $Priv))
424  {
425  $Subset = new PrivilegeSet();
426  $Subset->LoadFromData($Priv["SUBSET"]);
427  $this->Privileges[] = $Subset;
428  }
429  else
430  {
431  $this->Privileges[] = $Priv;
432  }
433  }
434  }
435 
436  # load logic if available
437  if (array_key_exists("Logic", $Data))
438  {
439  $this->Logic = $Data["Logic"];
440  }
441  }
442 
450  private function MeetsCondition($Condition, $Resource, $User)
451  {
452  # if condition is a check for whether a resource is available
453  if ($Condition["FieldId"] == self::HAVE_RESOURCE)
454  {
455  # return a result based on whether a resource is available
456  return ((bool)($Resource == self::NO_RESOURCE)
457  != (bool)$Condition["Value"]) ? TRUE : FALSE;
458  }
459  # else if no resource is available
460  elseif ($Resource == self::NO_RESOURCE)
461  {
462  # return a result that in effect ignores the condition
463  return ($this->Logic == "AND") ? TRUE : FALSE;
464  }
465  # else if resource is valid
466  elseif ($Resource instanceof Resource)
467  {
468  # pre-process condition parameters based on type of field
469  try
470  {
471  $Field = new MetadataField($Condition["FieldId"]);
472  }
473  catch (Exception $e)
474  {
475  # if the field in a condition was invalid, the condition fails
476  return FALSE;
477  }
478 
479  $Operator = $Condition["Operator"];
480  $Value = $Condition["Value"];
481  $FieldValue = $Resource->Get($Field, TRUE);
482  switch ($Field->Type())
483  {
485  # if supplied value is NULL
486  if ($Value === NULL)
487  {
488  $Value = $User->Id();
489  }
490 
491  # get the UserIds contained in this field
492  $FieldValue = array_keys($FieldValue);
493  break;
494 
497  # date field values are Date objects, so handle those
498  if ($FieldValue instanceof Date)
499  {
500  $FieldValue = strtotime($FieldValue->Formatted());
501  }
502 
503  # timestamp field values are just the date/time string
504  else
505  {
506  $FieldValue = strtotime($FieldValue);
507  }
508 
509  # use the current time for the value if it's NULL
510  if ($Value === NULL)
511  {
512  $Value = time();
513  }
514 
515  # otherwise, parse the value to get a numeric timestamp
516  else
517  {
518  $Value = strtotime($Value);
519  }
520  break;
521 
524  break;
525 
527  # for options, construct a list of the CNIDs in this field
528  $NewValue = array();
529  foreach ($FieldValue as $CName)
530  {
531  $NewValue[]= $CName->Id();
532  }
533  $FieldValue = $NewValue;
534  break;
535 
536  default:
537  throw new Exception("Unsupported metadata field type ("
538  .print_r($Field->Type(), TRUE)
539  .") for condition in privilege set.");
540  break;
541  }
542 
543  # compare field value and supplied value using specified operator
544  switch ($Operator)
545  {
546  case "==":
547  if (is_array($FieldValue))
548  {
549  # equality against an option field is a 'contains' condition,
550  # true if the specified value is one of those set
551  $Result = FALSE;
552  foreach ($FieldValue as $FieldValue_i)
553  {
554  $Result |= ($FieldValue_i == $Value);
555  }
556  }
557  else
558  {
559  $Result = ($FieldValue == $Value);
560  }
561  break;
562 
563  case "!=":
564  if (is_array($FieldValue))
565  {
566  # not equal against an option field is 'does not contains',
567  # true as long as the spcified value is not one of those set
568  $Result = TRUE;
569  foreach ($FieldValue as $FieldValue_i)
570  {
571  $Result &= ($FieldValue_i != $Value);
572  }
573  }
574  else
575  {
576  $Result = ($FieldValue != $Value);
577  }
578  break;
579 
580  case "<":
581  $Result = ($FieldValue < $Value);
582  break;
583 
584  case ">":
585  $Result = ($FieldValue > $Value);
586  break;
587 
588  case "<=":
589  $Result = ($FieldValue <= $Value);
590  break;
591 
592  case ">=":
593  $Result = ($FieldValue >= $Value);
594  break;
595 
596  default:
597  throw new Exception("Unsupported condition operator ("
598  .print_r($Operator, TRUE).") in privilege set.");
599  break;
600  }
601 
602  # report to caller whether condition was met
603  return $Result ? TRUE : FALSE;
604  }
605  else
606  {
607  # error out because resource was illegal
608  throw new Exception("Invalid Resource passed in for privilege"
609  ." set comparison.");
610  }
611  }
612 
621  private function IsInPrivilegeData($Item)
622  {
623  # step through privilege data
624  foreach ($this->Privileges as $Priv)
625  {
626  # report to caller if item is found
627  if (is_object($Item))
628  {
629  if (is_object($Priv) && ($Item == $Priv)) { return TRUE; }
630  }
631  elseif (is_array($Item))
632  {
633  if (is_array($Priv) && ($Item == $Priv)) { return TRUE; }
634  }
635  elseif ($Item == $Priv) { return TRUE; }
636  }
637 
638  # report to caller that item is not in privilege data
639  return FALSE;
640  }
641 }
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:104
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.
Definition: Date.php:18
__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".
AddPrivilege($Privileges)
Add specified privilege to set.
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 ...
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.