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($Privileges)
149  {
150  # convert incoming value to array if needed
151  if (!is_array($Privileges))
152  {
153  $Privileges = array($Privileges);
154  }
155 
156  # for each privilege passed in
157  foreach ($Privileges as $Privilege)
158  {
159  # add privilege if not currently in set
160  if (!$this->IncludesPrivilege($Privilege))
161  {
162  if (is_object($Privilege)) { $Privilege = $Privilege->Id(); }
163  $this->Privileges[] = $Privilege;
164  }
165  }
166  }
167 
174  function RemovePrivilege($Privilege)
175  {
176  # remove privilege if currently in set
177  if ($this->IncludesPrivilege($Privilege))
178  {
179  if (is_object($Privilege)) { $Privilege = $Privilege->Id(); }
180  $Index = array_search($Privilege, $this->Privileges);
181  unset($this->Privileges[$Index]);
182  }
183  }
184 
190  function IncludesPrivilege($Privilege)
191  {
192  # check whether privilege is in our list and report to caller
193  if (is_object($Privilege)) { $Privilege = $Privilege->Id(); }
194  return $this->IsInPrivilegeData($Privilege) ? TRUE : FALSE;
195  }
196 
205  function GetPrivilegeInfo()
206  {
207  # grab privilege information and add logic
208  $Info = $this->Privileges;
209  $Info["Logic"] = $this->Logic;
210 
211  # return privilege info array to caller
212  return $Info;
213  }
214 
221  function GetPrivilegeList()
222  {
223  # create list of privileges with conditions stripped out
224  $List = array();
225  foreach ($this->Privileges as $Priv)
226  {
227  if (!is_array($Priv)) { $List[] = $Priv; }
228  }
229 
230  # return list of privileges to caller
231  return $List;
232  }
233 
248  function AddCondition($Field, $Value = NULL, $Operator = "==")
249  {
250  # get field ID
251  $FieldId = is_object($Field) ? $Field->Id() : $Field;
252 
253  # set up condition array
254  $Condition = array(
255  "FieldId" => intval($FieldId),
256  "Operator" => trim($Operator),
257  "Value" => $Value);
258 
259  # if condition is not already in set
260  if (!$this->IsInPrivilegeData($Condition))
261  {
262  # add condition to privilege set
263  $this->Privileges[] = $Condition;
264  }
265  }
266 
278  function RemoveCondition($Field, $Value = NULL, $Operator = "==")
279  {
280  # get field ID
281  $FieldId = is_object($Field) ? $Field->Id() : $Field;
282 
283  # set up condition array
284  $Condition = array(
285  "FieldId" => intval($FieldId),
286  "Operator" => trim($Operator),
287  "Value" => $Value);
288 
289  # if condition is in set
290  if ($this->IsInPrivilegeData($Condition))
291  {
292  # remove condition from privilege set
293  $Index = array_search($Condition, $this->Privileges);
294  unset($this->Privileges[$Index]);
295  }
296  }
297 
302  function AddSet(PrivilegeSet $Set)
303  {
304  # if subgroup is not already in set
305  if (!$this->IsInPrivilegeData($Set))
306  {
307  # add subgroup to privilege set
308  $this->Privileges[] = $Set;
309  }
310  }
311 
321  function AllRequired($NewValue = NULL)
322  {
323  if ($NewValue !== NULL)
324  {
325  $this->Logic = $NewValue ? "AND" : "OR";
326  }
327  return ($this->Logic == "AND") ? TRUE : FALSE;
328  }
329 
336  {
337  $Info = $this->GetPrivilegeInfo();
338  unset ($Info["Logic"]);
339 
340  $Result = array();
341  foreach ($Info as $Item)
342  {
343  if (is_object($Item))
344  {
345  $Result = array_merge($Result, $Item->PrivilegeFlagsChecked() );
346  }
347  elseif (!is_array($Item))
348  {
349  $Result []= $Item;
350  }
351  }
352  return array_unique($Result);
353  }
354 
361  function FieldsWithUserComparisons($ComparisonType)
362  {
363  $Info = $this->GetPrivilegeInfo();
364  unset ($Info["Logic"]);
365 
366  $Result = array();
367  foreach ($Info as $Item)
368  {
369  if (is_object($Item))
370  {
371  $Result = array_merge(
372  $Result,
373  $Item->FieldsWithUserComparisons( $ComparisonType ) );
374  }
375  elseif (is_array($Item))
376  {
377  if ($Item["Operator"] == $ComparisonType &&
378  $Item["FieldId"] > 0 )
379  {
380  $Field = new MetadataField($Item["FieldId"]);
381 
382  if ($Field->Type() == MetadataSchema::MDFTYPE_USER)
383  {
384  $Result []= $Item["FieldId"];
385  }
386  }
387  }
388  }
389 
390  return array_unique($Result);
391  }
392 
393  # ---- PRIVATE INTERFACE -------------------------------------------------
394 
395  private $Privileges = array();
396  private $Logic = "OR";
397 
398  const NO_RESOURCE = "XXX NO RESOURCE XXX";
399 
404  private function LoadFromData($Serialized)
405  {
406  # save calling context in case load causes out-of-memory crash
407  $GLOBALS["AF"]->RecordContextInCaseOfCrash();
408 
409  # unpack new data
410  $Data = unserialize($Serialized);
411 
412  # unpack privilege data (if available) and load
413  if (array_key_exists("Privileges", $Data))
414  {
415  $this->Privileges = array();
416  foreach ($Data["Privileges"] as $Priv)
417  {
418  if (is_array($Priv) && array_key_exists("SUBSET", $Priv))
419  {
420  $Subset = new PrivilegeSet();
421  $Subset->LoadFromData($Priv["SUBSET"]);
422  $this->Privileges[] = $Subset;
423  }
424  else
425  {
426  $this->Privileges[] = $Priv;
427  }
428  }
429  }
430 
431  # load logic if available
432  if (array_key_exists("Logic", $Data))
433  {
434  $this->Logic = $Data["Logic"];
435  }
436  }
437 
445  private function MeetsCondition($Condition, $Resource, $User)
446  {
447  # if condition is a check for whether a resource is available
448  if ($Condition["FieldId"] == self::HAVE_RESOURCE)
449  {
450  # return a result based on whether a resource is available
451  return ((bool)($Resource == self::NO_RESOURCE)
452  != (bool)$Condition["Value"]) ? TRUE : FALSE;
453  }
454  # else if no resource is available
455  elseif ($Resource == self::NO_RESOURCE)
456  {
457  # return a result that in effect ignores the condition
458  return ($this->Logic == "AND") ? TRUE : FALSE;
459  }
460  # else if resource is valid
461  elseif ($Resource instanceof Resource)
462  {
463  # pre-process condition parameters based on type of field
464  try
465  {
466  $Field = new MetadataField($Condition["FieldId"]);
467  }
468  catch (Exception $e)
469  {
470  # if the field in a condition was invalid, the condition fails
471  return FALSE;
472  }
473 
474  $Operator = $Condition["Operator"];
475  $Value = $Condition["Value"];
476  $FieldValue = $Resource->Get($Field, TRUE);
477  switch ($Field->Type())
478  {
480  # if supplied value is NULL
481  if ($Value === NULL)
482  {
483  $Value = $User->Id();
484  }
485 
486  # convert field value to user ID
487  $FieldValue = $FieldValue->Id();
488  break;
489 
492  # date field values are Date objects, so handle those
493  if ($FieldValue instanceof Date)
494  {
495  $FieldValue = strtotime($FieldValue->Formatted());
496  }
497 
498  # timestamp field values are just the date/time string
499  else
500  {
501  $FieldValue = strtotime($FieldValue);
502  }
503 
504  # use the current time for the value if it's NULL
505  if ($Value === NULL)
506  {
507  $Value = time();
508  }
509 
510  # otherwise, parse the value to get a numeric timestamp
511  else
512  {
513  $Value = strtotime($Value);
514  }
515  break;
516 
519  break;
520 
522  # for options, construct a list of the CNIDs in this field
523  $NewValue = array();
524  foreach ($FieldValue as $CName)
525  {
526  $NewValue []= $CName->Id();
527  }
528  $FieldValue = $NewValue;
529  break;
530 
531  default:
532  throw new Exception("Unsupported metadata field type ("
533  .print_r($Field->Type(), TRUE)
534  .") for condition in privilege set.");
535  break;
536  }
537 
538  # compare field value and supplied value using specified operator
539  switch ($Operator)
540  {
541  case "==":
542  if (is_array($FieldValue))
543  {
544  # equality against an option field is a 'contains' condition,
545  # true if the specified value is one of those set
546  $Result = FALSE;
547  foreach ($FieldValue as $FieldValue_i)
548  {
549  $Result |= ($FieldValue_i == $Value);
550  }
551  }
552  else
553  {
554  $Result = ($FieldValue == $Value);
555  }
556  break;
557 
558  case "!=":
559  if (is_array($FieldValue))
560  {
561  # not equal against an option field is 'does not contains',
562  # true as long as the spcified value is not one of those set
563  $Result = TRUE;
564  foreach ($FieldValue as $FieldValue_i)
565  {
566  $Result &= ($FieldValue_i != $Value);
567  }
568  }
569  else
570  {
571  $Result = ($FieldValue != $Value);
572  }
573  break;
574 
575  case "<":
576  $Result = ($FieldValue < $Value);
577  break;
578 
579  case ">":
580  $Result = ($FieldValue > $Value);
581  break;
582 
583  case "<=":
584  $Result = ($FieldValue <= $Value);
585  break;
586 
587  case ">=":
588  $Result = ($FieldValue >= $Value);
589  break;
590 
591  default:
592  throw new Exception("Unsupported condition operator ("
593  .print_r($Operator, TRUE).") in privilege set.");
594  break;
595  }
596 
597  # report to caller whether condition was met
598  return $Result ? TRUE : FALSE;
599  }
600  else
601  {
602  # error out because resource was illegal
603  throw new Exception("Invalid Resource passed in for privilege"
604  ." set comparison.");
605  }
606  }
607 
616  private function IsInPrivilegeData($Item)
617  {
618  # step through privilege data
619  foreach ($this->Privileges as $Priv)
620  {
621  # report to caller if item is found
622  if (is_object($Item))
623  {
624  if (is_object($Priv) && ($Item == $Priv)) { return TRUE; }
625  }
626  elseif (is_array($Item))
627  {
628  if (is_array($Priv) && ($Item == $Priv)) { return TRUE; }
629  }
630  elseif ($Item == $Priv) { return TRUE; }
631  }
632 
633  # report to caller that item is not in privilege data
634  return FALSE;
635  }
636 }
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.
__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.