All Data Structures Functions Variables Pages
PermissionsCache.php
1 <?php
2  /*********************************************************************************
3  * Zurmo is a customer relationship management program developed by
4  * Zurmo, Inc. Copyright (C) 2017 Zurmo Inc.
5  *
6  * Zurmo is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU Affero General Public License version 3 as published by the
8  * Free Software Foundation with the addition of the following permission added
9  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
10  * IN WHICH THE COPYRIGHT IS OWNED BY ZURMO, ZURMO DISCLAIMS THE WARRANTY
11  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
12  *
13  * Zurmo is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Affero General Public License along with
19  * this program; if not, see http://www.gnu.org/licenses or write to the Free
20  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21  * 02110-1301 USA.
22  *
23  * You can contact Zurmo, Inc. with a mailing address at 27 North Wacker Drive
24  * Suite 370 Chicago, IL 60606. or at email address contact@zurmo.com.
25  *
26  * The interactive user interfaces in original and modified versions
27  * of this program must display Appropriate Legal Notices, as required under
28  * Section 5 of the GNU Affero General Public License version 3.
29  *
30  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
31  * these Appropriate Legal Notices must retain the display of the Zurmo
32  * logo and Zurmo copyright notice. If the display of the logo is not reasonably
33  * feasible for technical reasons, the Appropriate Legal Notices must display the words
34  * "Copyright Zurmo Inc. 2017. All rights reserved".
35  ********************************************************************************/
36 
37  // This is so that accessing a securable item several times, specifically
38  // setting several of its attributes in succession, will not recalculate
39  // the user's permissions every time. Changes to permissions during a
40  // request may be ignored, then will be picked up during the next request.
41  // Permissions are cached at three levels, in php - they will be remembered
42  // during the request, in memcache - they will be remembered across requests,
43  // in the database - they will be remembered across requests even if
44  // memcache doesn't have them.
46  {
47  private static $securableItemToPermitableToCombinedPermissions = array();
48 
49  private static $namedSecurableItemActualPermissions = array();
50 
51  public static $cacheType = 'P:';
52 
53  public static $modulePermissionsDataCachePrefix = 'MD:';
54 
61  public static function getCombinedPermissions(SecurableItem $securableItem, Permitable $permitable)
62  {
63  if ($securableItem->getClassId('SecurableItem') == 0 ||
64  $permitable ->getClassId('Permitable') == 0)
65  {
66  throw new NotFoundException();
67  }
68 
69  $securableItemModelIdentifer = $securableItem->getModelIdentifier();
70  $permitableModelIdentifier = $permitable ->getModelIdentifier();
71 
72  if (static::supportsAndAllowsPhpCaching())
73  {
74  if (isset(static::$securableItemToPermitableToCombinedPermissions
75  [$securableItemModelIdentifer]
76  [$permitableModelIdentifier]))
77  {
78  return static::$securableItemToPermitableToCombinedPermissions
79  [$securableItemModelIdentifer]
80  [$permitableModelIdentifier];
81  }
82  }
83 
84  if (static::supportsAndAllowsMemcache())
85  {
86  $prefix = static::getCachePrefix($securableItemModelIdentifer);
87  $permitablesCombinedPermissions = static::getCachedValueAndValidateChecksum($prefix . $securableItemModelIdentifer);
88  if ($permitablesCombinedPermissions !== false)
89  {
90  assert('is_array($permitablesCombinedPermissions)');
91  if (isset($permitablesCombinedPermissions[$permitableModelIdentifier]))
92  {
93  $combinedPermissions = $permitablesCombinedPermissions[$permitableModelIdentifier];
94  if (static::supportsAndAllowsPhpCaching())
95  {
96  static::$securableItemToPermitableToCombinedPermissions
97  [$securableItemModelIdentifer]
98  [$permitableModelIdentifier] = $combinedPermissions;
99  }
100  return $combinedPermissions;
101  }
102  }
103  }
104 
105  // NOTE: the db level will get the permissions from the db level cache
106  // when php asks for them to be calculated so it doesn't need to be done
107  // explicity here.
108 
109  throw new NotFoundException();
110  }
111 
117  public static function cacheCombinedPermissions(SecurableItem $securableItem, Permitable $permitable,
118  $combinedPermissions)
119  {
120  assert('is_int($combinedPermissions) || ' .
121  'is_numeric($combinedPermissions[0]) && is_string($combinedPermissions[0])');
122 
123  if ($securableItem->getClassId('SecurableItem') == 0 ||
124  $permitable ->getClassId('Permitable') == 0)
125  {
126  return;
127  }
128 
129  $securableItemModelIdentifer = $securableItem->getModelIdentifier();
130  $permitableModelIdentifier = $permitable ->getModelIdentifier();
131 
132  if (static::supportsAndAllowsPhpCaching())
133  {
134  static::$securableItemToPermitableToCombinedPermissions
135  [$securableItemModelIdentifer]
136  [$permitableModelIdentifier] = $combinedPermissions;
137  }
138 
139  if (static::supportsAndAllowsMemcache())
140  {
141  $prefix = static::getCachePrefix($securableItemModelIdentifer);
142  $permitablesCombinedPermissions = static::getCachedValueAndValidateChecksum($prefix . $securableItemModelIdentifer);
143  if ($permitablesCombinedPermissions === false)
144  {
145  $permitablesCombinedPermissions = array($permitableModelIdentifier => $combinedPermissions);
146  static::cacheValueAndChecksum($prefix . $securableItemModelIdentifer, $permitablesCombinedPermissions);
147  }
148  else
149  {
150  assert('is_array($permitablesCombinedPermissions)');
151  $permitablesCombinedPermissions[$permitableModelIdentifier] = $combinedPermissions;
152  static::cacheValueAndChecksum($prefix . $securableItemModelIdentifer, $permitablesCombinedPermissions);
153  }
154  }
155 
156  // NOTE: the db level caches the permissions when it calculates
157  // them so php does not need to explicitly cache them here.
158  }
159 
168  public static function cacheNamedSecurableItemActualPermissions($namedSecurableItemName, $permitable, $actualPermissions,
169  $cacheToDatabase = true)
170  {
171  assert('is_string($namedSecurableItemName)');
172  assert('$permitable instanceof Permitable');
173  assert('is_array($actualPermissions)');
174  assert('is_bool($cacheToDatabase)');
175  $cacheKeyName = $namedSecurableItemName . get_class($permitable) . $permitable->id . 'ActualPermissions';
176  if (static::supportsAndAllowsPhpCaching())
177  {
178  static::$namedSecurableItemActualPermissions[$cacheKeyName] = $actualPermissions;
179  }
180  if (static::supportsAndAllowsMemcache())
181  {
182  $prefix = static::getCachePrefix($cacheKeyName);
183  static::cacheValueAndChecksum($prefix . $cacheKeyName, $actualPermissions);
184  }
185  if (static::supportsAndAllowsDatabaseCaching() && $cacheToDatabase)
186  {
187  if ($permitable->getClassId('Permitable') > 0)
188  {
189  ZurmoRedBean::exec("insert into named_securable_actual_permissions_cache
190  (securableitem_name, permitable_id, allow_permissions, deny_permissions)
191  values ('" . $namedSecurableItemName . "', " . $permitable->getClassId('Permitable') . ", " .
192  $actualPermissions[0] . ", " . $actualPermissions[1] . ") on duplicate key
193  update allow_permissions = " . $actualPermissions[0] . " AND deny_permissions = " .
194  $actualPermissions[1]);
195  }
196  }
197  }
198 
206  public static function getNamedSecurableItemActualPermissions($namedSecurableItemName, $permitable)
207  {
208  assert('is_string($namedSecurableItemName)');
209  assert('$permitable instanceof Permitable');
210  $cacheKeyName = $namedSecurableItemName . get_class($permitable) . $permitable->id . 'ActualPermissions';
211  if (static::supportsAndAllowsPhpCaching())
212  {
213  if (isset(static::$namedSecurableItemActualPermissions[$cacheKeyName]))
214  {
215  return static::$namedSecurableItemActualPermissions[$cacheKeyName];
216  }
217  }
218  if (static::supportsAndAllowsMemcache())
219  {
220  $prefix = static::getCachePrefix($cacheKeyName);
221  $actualPermissions = static::getCachedValueAndValidateChecksum($prefix . $cacheKeyName);
222  if ($actualPermissions !== false)
223  {
224  assert('is_array($actualPermissions)');
225  return $actualPermissions;
226  }
227  }
228  if (static::supportsAndAllowsDatabaseCaching())
229  {
230  if ($permitable->getClassId('Permitable') > 0)
231  {
232  $row = ZurmoRedBean::getRow("select allow_permissions, deny_permissions " .
233  "from named_securable_actual_permissions_cache " .
234  "where securableitem_name = '" . $namedSecurableItemName . "' and " .
235  "permitable_id = '" . $permitable->getClassId('Permitable'). "'");
236  if ($row != null && isset($row['allow_permissions']) && isset($row['deny_permissions']))
237  {
238  static::cacheNamedSecurableItemActualPermissions($namedSecurableItemName, $permitable,
239  array($row['allow_permissions'], $row['deny_permissions']), false);
240  return array($row['allow_permissions'], $row['deny_permissions']);
241  }
242  }
243  }
244  throw new NotFoundException();
245  }
246 
252  public static function getAllModulePermissionsDataByPermitable($permitable)
253  {
254  assert('$permitable instanceof Permitable');
255  if ($permitable->getClassId('Permitable') == 0)
256  {
257  throw new NotFoundException();
258  }
259  $permitableModelIdentifier = $permitable->getModelIdentifier();
260  if (static::supportsAndAllowsMemcache())
261  {
262  $prefix = static::getCachePrefix($permitableModelIdentifier) . static::$modulePermissionsDataCachePrefix;
263  $data = static::getCachedValueAndValidateChecksum($prefix . $permitableModelIdentifier);
264  if ($data !== false)
265  {
266  return $data;
267  }
268  }
269  throw new NotFoundException();
270  }
271 
276  public static function cacheAllModulePermissionsDataByPermitables($permitable, array $data)
277  {
278  assert('$permitable instanceof Permitable');
279  if ($permitable->getClassId('Permitable') == 0)
280  {
281  return;
282  }
283  $permitableModelIdentifier = $permitable->getModelIdentifier();
284  if (static::supportsAndAllowsMemcache())
285  {
286  $prefix = static::getCachePrefix($permitableModelIdentifier) . static::$modulePermissionsDataCachePrefix;
287  static::cacheValueAndChecksum($prefix . $permitableModelIdentifier, $data);
288  }
289  }
290 
291  // The $forgetDbLevel cache is for testing.
292  public static function forgetSecurableItem(SecurableItem $securableItem, $forgetDbLevelCache = true)
293  {
294  if ($securableItem->getClassId('SecurableItem') == 0)
295  {
296  return;
297  }
298 
299  $securableItemModelIdentifer = $securableItem->getModelIdentifier();
300 
301  if (static::supportsAndAllowsPhpCaching())
302  {
303  static::$securableItemToPermitableToCombinedPermissions[$securableItemModelIdentifer] = array();
304  }
305 
306  if (static::supportsAndAllowsMemcache())
307  {
308  $prefix = static::getCachePrefix($securableItemModelIdentifer);
309  Yii::app()->cache->delete($prefix . $securableItemModelIdentifer);
310  }
311 
312  if (SECURITY_OPTIMIZED && static::supportsAndAllowsDatabaseCaching() && $forgetDbLevelCache)
313  {
314  $securableItemId = $securableItem->getClassID('SecurableItem');
316  callProcedureWithoutOuts("clear_cache_securableitem_actual_permissions($securableItemId)");
317  }
318  }
319 
320  // The $forgetDbLevel cache is for testing.
321  public static function forgetAll($forgetDbLevelCache = true)
322  {
323  if (static::supportsAndAllowsPhpCaching())
324  {
325  static::$securableItemToPermitableToCombinedPermissions = array();
326  static::$namedSecurableItemActualPermissions = array();
327  }
328 
329  if (SECURITY_OPTIMIZED && static::supportsAndAllowsDatabaseCaching() && $forgetDbLevelCache)
330  {
331  ZurmoDatabaseCompatibilityUtil::callProcedureWithoutOuts("clear_cache_all_actual_permissions()");
332  }
333  if (static::supportsAndAllowsDatabaseCaching() && $forgetDbLevelCache)
334  {
336  callProcedureWithoutOuts("clear_cache_named_securable_all_actual_permissions()");
337  }
338  static::clearMemcacheCache();
339  }
340  }
341 ?>
static cacheNamedSecurableItemActualPermissions($namedSecurableItemName, $permitable, $actualPermissions, $cacheToDatabase=true)
getClassId($modelClassName)
static cacheAllModulePermissionsDataByPermitables($permitable, array $data)
static getAllModulePermissionsDataByPermitable($permitable)
static cacheCombinedPermissions(SecurableItem $securableItem, Permitable $permitable, $combinedPermissions)
static getNamedSecurableItemActualPermissions($namedSecurableItemName, $permitable)
static getCombinedPermissions(SecurableItem $securableItem, Permitable $permitable)
Generated on Thu May 28 2020 07:10:36