Default Component ACL Rules (2.5.x)

Default Component ACL Rules
===========================

Joomla Tracker: http://joomlacode.org/gf/project/joomla/tracker/?action=TrackerItemEdit&tracker_item_id=30550  (submitted for both Joomla 2.5 and 4)

Background / Motivation
-----------------------

There is currently no way to specify the default action permission rules for a
component that has component-specific custom permission rules.  If component
developers want default ACL rules for their custom ACL rules, they need to
create code that modifies the root asset.  This is extra work for component
developers and a potential source of errors and problems.

Proposed Fix
------------

The proposed fix addresses this problem by extending the syntax of component
'access.xml' file that lists the component-specific ACL rules.  The goal is to
allow the component developer to specify the groups that should be allowed to
perform the ACL action as part of the XML definition for each ACL rule.  This
would require updates to Joomla (the platform) to interpret the additions to
the 'access.xml' and add the appropriate permissions to the system.

These additions will be backwards compatible since the additional XML
attributes will be ignored by versions of Joomla that have not implemented
this fix.

Since there are many different ways that a particular component can implement
ACL rules, a few guiding principles are necessary:

  1. If the default for a custom ACL rule is not specified, the default root
     ACL rules will not be modified.  This is the current behavior.

  2. If the group specified in the default rules does not exist in the Joomla
     installation, no root permission will be set and an information message
     will be generated.  Some Joomla installations have been known to delete
     all common groups (such as Public, Registered) and create new groups. So
     there is no guarantee that normally expected groups will exist.

  3. The component developer may specify a core rule to check for the group.
     If the core allows that ACL action for the specified group, then the
     corresponding component rule will be enabled for that group in the root
     rule.

  4. This new feature would only be applied to any custom component-specific
     rule in a components 'access.xml'.  This approach cannot be used to
     modify the core rules in the root rule.


Example 'access.xml' syntax additions
-------------------------------------

Three syntax variations are proposed.  In the following examples, the
component for the 'access.xml' file is 'com_example'.


**Syntax 1**

The simplest proposed syntax for a component 'com_example' is

```xml
<action name="example.delete.own"
        title="COM_EXAMPLE_PERMISSION_DELETEOWN"
        description="COM_EXAMPLE_PERMISSION_DELETEOWN_DESC" 
        default="Author" 
        />
```

Notice the new 'default' attribute.  If the 'Author' group exists, the root
asset will be modified so that anyone in the 'Author' group (and derived
groups) will be able to perform this action (for instance, delete example
items they created).  

Note that this could be a comma-separated list of group names.


**Syntax 2**

A more complex form could be given

```xml
<action name="example.delete.own"
        title="COM_EXAMPLE_PERMISSION_DELETEOWN"
        description="COM_EXAMPLE_PERMISSION_DELETEOWN_DESC" 
        default="Author:core.delete"
        />
```

In this case, the installer would check to see if Author has the 'core.delete'
permission for 'com_example' (the component owning the 'access.xml' file
involved) and add the corresponding permission for Author for the
'com_example' component if it does.  If not, no permissions would be modified.

As before, this could be a comma-separated list of permission definitions.


**Syntax 3**

If the developer wants the default to match the default for some other
component, they can indicate that by specifying the component to check

```xml
<action name="example.delete.own"
        title="COM_EXAMPLE_PERMISSION_DELETEOWN"
        description="COM_EXAMPLE_PERMISSION_DELETEOWN_DESC" 
        default="Author:core.delete[com_banners]"
        />
```

In this case, the installer would check to see if Author has the 'core.delete'
permission for 'com_banners' and add the corresponding permission for Author
for the 'com_example' component if it does.  If not, no permissions would be
modified.  As usual, this could be a comma-separated list of permission
definitions.


Testing the new functionality
-----------------------------

A test component 'com_permtest' is available on github:

   https://github.com/jmcameron/compnent_permissions_test

This includes a zipped up version of the component that is ready to install.

   comp_permtest.zip

This test component should work on Joomla 2.5.x and 3.x.  Obviously the
functions will not do anything if the fixes to Joomla described here are not
implemented.

To try these fixes:

   * Install the fixes on your Joomla 2.5.7+ or 3.x site (by doing 'git pull'
     or using a patch file)

   * Install the component in the regular way then go to the
     'component-permissions-test' component under the 'Components' menu in the
     back end.

   * Read the  instructions there on how to test it.

Note that these fixes include unit tests for the new capabilities.  See the
bottom of the this document.


Implementation Notes
--------------------

The functionality above is implemented by adding functions to JAccess and
JRules:


**JRules::removeActions($action_regexp)**

 * Remove all actions from the rule whose action name matches the regular
   expression


**JAccess::getGroupId($groupname)**

 * Returns a group ID for the given group name.

 * This could be moved elsewhere, but there did not seem to be a suitable
   place.  We may want to add a JUserGroup class (in
   libraries/joomla/user/group.php) and move this function into that class.


**JAccess::installComponentDefaultRules($component, $file = null)**

 * Parse the rules for custom rules in component's 'access.xml' file and
   install new permissions in the root asset, as needed.

 * Does not allow modifying core rules.

 * If groups are encountered that are unknown by the Joomla installation, they
   will be ignored.  Currently a log message is being added.  This should
   probably be a JApplication::enqueueMessage() call but I could not get
   that to work in the unit tests.

 * This function can be called any time, but it would make sense to call this
   during component installation in the postflight section.

 * The optional $file can be used to specify an alternate location for the
   'acess.xml' file and is intended for testing.


**JAccess::purgeComponentDefaultRules($component)**

 * Removes all custom rules for $component defined in the root asset

 * This function can be called at any time, but it would make sense to call
   this during the uninstallation of a component (during preflight or the
   uninstall function).


Unit tests
----------

 * Unit tests for Joomla 3 that cover the features above have been added to
   the *tests/unit/suites/libraries/access* folder.

 * The custom unit test configuration file
   **tests/system/servers/configdef.php** was added to the toplevel .gitignore
   since it could contain private data and should be ignored (like .gitignore
   already ignores the top-level phpunit config file **phpunit.xml**).


Jonathan Cameron   
April 11, 2013