diff --git a/administrator/components/com_config/model/application.php b/administrator/components/com_config/model/application.php
index ffc280cf40976..17b404118f761 100644
--- a/administrator/components/com_config/model/application.php
+++ b/administrator/components/com_config/model/application.php
@@ -403,6 +403,11 @@ public function storePermissions($permission = null)
return false;
}
+ $permission['component'] = empty($permission['component']) ? 'root.1' : $permission['component'];
+
+ // Current view is global config?
+ $isGlobalConfig = $permission['component'] === 'root.1';
+
// Check if changed group has Super User permissions.
$isSuperUserGroupBefore = JAccess::checkGroup($permission['rule'], 'core.admin');
@@ -493,6 +498,15 @@ public function storePermissions($permission = null)
$parentAssetId = $parentAsset->getRootId();
}
+ /**
+ * @to do: incorrect ACL stored
+ * When changing a permission of an item that doesn't have a row in the asset table the row a new row is created.
+ * This works fine for item <-> component <-> global config scenario and component <-> global config scenario.
+ * But doesn't work properly for item <-> section(s) <-> component <-> global config scenario,
+ * because a wrong parent asset id (the component) is stored.
+ * Happens when there is no row in the asset table (ex: deleted or not created on update).
+ */
+
$asset->setLocation($parentAssetId, 'last-child');
if (!$asset->check() || !$asset->store())
@@ -541,7 +555,7 @@ public function storePermissions($permission = null)
// Store the new permissions.
try
{
- $query = $this->db->getQuery(true)
+ $query->clear()
->update($this->db->quoteName('#__assets'))
->set($this->db->quoteName('rules') . ' = ' . $this->db->quote(json_encode($temp)))
->where($this->db->quoteName('name') . ' = ' . $this->db->quote($permission['component']));
@@ -568,30 +582,54 @@ public function storePermissions($permission = null)
try
{
// Get the asset id by the name of the component.
- $query = $this->db->getQuery(true)
- ->select($this->db->quoteName('id'))
- ->from($this->db->quoteName('#__assets'))
- ->where($this->db->quoteName('name') . ' = ' . $this->db->quote($permission['component']));
+ $query->clear()
+ ->select($this->db->quoteName('id'))
+ ->from($this->db->quoteName('#__assets'))
+ ->where($this->db->quoteName('name') . ' = ' . $this->db->quote($permission['component']));
$this->db->setQuery($query);
$assetId = (int) $this->db->loadResult();
- // Get the group parent id of the current group.
- $query = $this->db->getQuery(true)
+ // Fetch the parent asset id.
+ $parentAssetId = null;
+
+ /**
+ * @to do: incorrect info
+ * When creating a new item (not saving) it uses the calculated permissions from the component (item <-> component <-> global config).
+ * But if we have a section too (item <-> section(s) <-> component <-> global config) this is not correct.
+ * Also, currently it uses the component permission, but should use the calculated permissions for achild of the component/section.
+ */
+
+ // If not in global config we need the parent_id asset to calculate permissions.
+ if (!$isGlobalConfig)
+ {
+ // In this case we need to get the component rules too.
+ $query->clear()
->select($this->db->quoteName('parent_id'))
- ->from($this->db->quoteName('#__usergroups'))
- ->where($this->db->quoteName('id') . ' = ' . (int) $permission['rule']);
+ ->from($this->db->quoteName('#__assets'))
+ ->where($this->db->quoteName('id') . ' = ' . $assetId);
+
+ $this->db->setQuery($query);
+
+ $parentAssetId = (int) $this->db->loadResult();
+ }
+
+ // Get the group parent id of the current group.
+ $query->clear()
+ ->select($this->db->quoteName('parent_id'))
+ ->from($this->db->quoteName('#__usergroups'))
+ ->where($this->db->quoteName('id') . ' = ' . (int) $permission['rule']);
$this->db->setQuery($query);
$parentGroupId = (int) $this->db->loadResult();
// Count the number of child groups of the current group.
- $query = $this->db->getQuery(true)
- ->select('COUNT(' . $this->db->quoteName('id') . ')')
- ->from($this->db->quoteName('#__usergroups'))
- ->where($this->db->quoteName('parent_id') . ' = ' . (int) $permission['rule']);
+ $query->clear()
+ ->select('COUNT(' . $this->db->quoteName('id') . ')')
+ ->from($this->db->quoteName('#__usergroups'))
+ ->where($this->db->quoteName('parent_id') . ' = ' . (int) $permission['rule']);
$this->db->setQuery($query);
@@ -611,12 +649,12 @@ public function storePermissions($permission = null)
$isSuperUserGroupAfter = JAccess::checkGroup($permission['rule'], 'core.admin');
// Get the rule for just this asset (non-recursive) and get the actual setting for the action for this group.
- $assetRule = JAccess::getAssetRules($assetId)->allow($permission['action'], $permission['rule']);
+ $assetRule = JAccess::getAssetRules($assetId, false, false)->allow($permission['action'], $permission['rule']);
// Get the group, group parent id, and group global config recursive calculated permission for the chosen action.
- $inheritedGroupRule = JAccess::checkGroup($permission['rule'], $permission['action'], $assetId);
- $inheritedGroupGlobalRule = JAccess::checkGroup($permission['rule'], $permission['action']);
- $inheritedParentGroupRule = JAccess::checkGroup($parentGroupId, $permission['action'], $assetId);
+ $inheritedGroupRule = JAccess::checkGroup($permission['rule'], $permission['action'], $assetId);
+ $inheritedGroupParentAssetRule = !empty($parentAssetId) ? JAccess::checkGroup($permission['rule'], $permission['action'], $parentAssetId) : null;
+ $inheritedParentGroupRule = !empty($parentGroupId) ? JAccess::checkGroup($parentGroupId, $permission['action'], $assetId) : null;
// Current group is a Super User group, so calculated setting is "Allowed (Super User)".
if ($isSuperUserGroupAfter)
@@ -644,6 +682,12 @@ public function storePermissions($permission = null)
// Second part: Overwrite the calculated permissions labels if there is an explicity permission in the current group.
+ /**
+ * @to do: incorect info
+ * If a component as a permission that doesn't exists in global config (ex: frontend editing in com_modules) by default
+ * we get "Not Allowed (Inherited)" when we should get "Not Allowed (Default)".
+ */
+
// If there is an explicity permission "Not Allowed". Calculated permission is "Not Allowed".
if ($assetRule === false)
{
@@ -659,23 +703,18 @@ public function storePermissions($permission = null)
// Third part: Overwrite the calculated permissions labels for special cases.
- // User in in global config Root (Public)?
- $isGlobalConfig = (empty($permission['component']) || $permission['component'] === 'root.1') ? true : false;
-
// Global configuration with "Not Set" permission. Calculated permission is "Not Allowed (Default)".
if (empty($parentGroupId) && $isGlobalConfig === true && $assetRule === null)
{
$result['class'] = 'label label-important';
$result['text'] = JText::_('JLIB_RULES_NOT_ALLOWED_DEFAULT');
}
- // Component/item root level with explicit "Denied" permission at Global configuration. Calculated permission is "Not Allowed (Locked)".
- elseif (empty($parentGroupId) && $isGlobalConfig === false && $inheritedParentGroupRule === null && $inheritedGroupGlobalRule === false)
- {
- $result['class'] = 'label label-important';
- $result['text'] = '' . JText::_('JLIB_RULES_NOT_ALLOWED_LOCKED');
- }
- // Some parent group has an explicit "Denied". Calculated permission is "Not Allowed (Locked)".
- elseif ($inheritedParentGroupRule === false)
+ /**
+ * Component/Item with explicit "Denied" permission at parent Asset (Category, Component or Global config) configuration.
+ * Or some parent group has an explicit "Denied".
+ * Calculated permission is "Not Allowed (Locked)".
+ */
+ elseif ($inheritedGroupParentAssetRule === false || $inheritedParentGroupRule === false)
{
$result['class'] = 'label label-important';
$result['text'] = '' . JText::_('JLIB_RULES_NOT_ALLOWED_LOCKED');
diff --git a/libraries/joomla/access/access.php b/libraries/joomla/access/access.php
index 036f49f6c1306..af939087e24bd 100644
--- a/libraries/joomla/access/access.php
+++ b/libraries/joomla/access/access.php
@@ -560,14 +560,15 @@ protected static function getGroupPath($groupId)
* only the rules explicitly set for the asset or the summation of all inherited rules from
* parent assets and explicit rules.
*
- * @param mixed $asset Integer asset id or the name of the asset as a string.
- * @param boolean $recursive True to return the rules object with inherited rules.
+ * @param mixed $asset Integer asset id or the name of the asset as a string.
+ * @param boolean $recursive True to return the rules object with inherited rules.
+ * @param boolean $recursiveParentAsset True to calculate the rule also based on inherited component/extension rules.
*
* @return JAccessRules JAccessRules object for the asset.
*
* @since 11.1
*/
- public static function getAssetRules($asset, $recursive = false)
+ public static function getAssetRules($asset, $recursive = false, $recursiveParentAsset = true)
{
// Get instance of the Profiler:
$_PROFILER = JProfiler::getInstance('Application');
@@ -576,7 +577,8 @@ public static function getAssetRules($asset, $recursive = false)
// Almost all calls should have recursive set to true
// so we'll get to take advantage of preloading:
- if ($recursive && isset(self::$assetPermissionsByName[$extensionName]) && isset(self::$assetPermissionsByName[$extensionName][$asset]))
+ if ($recursive && $recursiveParentAsset && isset(self::$assetPermissionsByName[$extensionName])
+ && isset(self::$assetPermissionsByName[$extensionName][$asset]))
{
// Mark in the profiler.
JDEBUG ? $_PROFILER->mark('Start JAccess::getAssetRules New (' . $asset . ')') : null;
@@ -635,7 +637,7 @@ public static function getAssetRules($asset, $recursive = false)
->from('#__assets AS a');
$extensionString = '';
- if ($extensionName !== $asset || is_numeric($asset))
+ if ($recursiveParentAsset && ($extensionName !== $asset || is_numeric($asset)))
{
$extensionString = ' OR a.name = ' . $db->quote($extensionName);
}
@@ -681,6 +683,7 @@ public static function getAssetRules($asset, $recursive = false)
$result = $db->loadResult();
$result = array($result);
}
+
// Instantiate and return the JAccessRules object for the asset rules.
$rules = new JAccessRules;
$rules->mergeCollection($result);
diff --git a/libraries/joomla/form/fields/rules.php b/libraries/joomla/form/fields/rules.php
index 2c231769fd8aa..2f0b5d4a8edbd 100644
--- a/libraries/joomla/form/fields/rules.php
+++ b/libraries/joomla/form/fields/rules.php
@@ -156,8 +156,11 @@ protected function getInput()
// Initialise some field attributes.
$section = $this->section;
- $component = $this->component;
$assetField = $this->assetField;
+ $component = empty($this->component) ? 'root.1' : $this->component;
+
+ // Current view is global config?
+ $isGlobalConfig = $component === 'root.1';
// Get the actions for the asset.
$actions = JAccess::getActions($component, $section);
@@ -172,29 +175,54 @@ protected function getInput()
}
}
- // Get the explicit rules for this asset.
- if ($section == 'component')
+ // Get the asset id.
+ // Note that for global configuration, com_config injects asset_id = 1 into the form.
+ $assetId = $this->form->getValue($assetField);
+ $newItem = empty($assetId) && $isGlobalConfig === false && $section !== 'component';
+ $parentAssetId = null;
+
+ // If the asset id is empty (component or new item).
+ if (empty($assetId))
{
- // Need to find the asset id by the name of the component.
+ // Get the component asset id as fallback.
$db = JFactory::getDbo();
$query = $db->getQuery(true)
->select($db->quoteName('id'))
->from($db->quoteName('#__assets'))
->where($db->quoteName('name') . ' = ' . $db->quote($component));
+
$db->setQuery($query);
+
$assetId = (int) $db->loadResult();
+
+ /**
+ * @to do: incorrect info
+ * When creating a new item (not saving) it uses the calculated permissions from the component (item <-> component <-> global config).
+ * But if we have a section too (item <-> section(s) <-> component <-> global config) this is not correct.
+ * Also, currently it uses the component permission, but should use the calculated permissions for achild of the component/section.
+ */
}
- else
+
+ // If not in global config we need the parent_id asset to calculate permissions.
+ if (!$isGlobalConfig)
{
- // Find the asset id of the content.
- // Note that for global configuration, com_config injects asset_id = 1 into the form.
- $assetId = $this->form->getValue($assetField);
+ // In this case we need to get the component rules too.
+ $db = JFactory::getDbo();
+
+ $query = $db->getQuery(true)
+ ->select($db->quoteName('parent_id'))
+ ->from($db->quoteName('#__assets'))
+ ->where($db->quoteName('id') . ' = ' . $assetId);
+
+ $db->setQuery($query);
+
+ $parentAssetId = (int) $db->loadResult();
}
// Full width format.
// Get the rules for just this asset (non-recursive).
- $assetRules = JAccess::getAssetRules($assetId);
+ $assetRules = JAccess::getAssetRules($assetId, false, false);
// Get the available user groups.
$groups = $this->getUserGroups();
@@ -295,13 +323,13 @@ protected function getInput()
*/
// Get the actual setting for the action for this group.
- $assetRule = $assetRules->allow($action->name, $group->value);
+ $assetRule = $newItem === false ? $assetRules->allow($action->name, $group->value) : null;
// Build the dropdowns for the permissions sliders
// The parent group has "Not Set", all children can rightly "Inherit" from that.
$html[] = '';
+ . JText::_(empty($group->parent_id) && $isGlobalConfig ? 'JLIB_RULES_NOT_SET' : 'JLIB_RULES_INHERITED') . '';
$html[] = '';
$html[] = '