Archived talk

Difference between revisions of "Developing a MVC Component/Adding ACL"

From Joomla! Documentation

m (Reverted edits by Ilie.pandia (talk) to last revision by Vipantonio)
(5 intermediate revisions by 3 users not shown)
Line 1: Line 1:
 +
== Checking the permissions on the Server Side ==
 +
 +
The tutorial at the moment of writing is not enforcing the permissions on the server side, allowing a forged request to modify data. (Permissions are only declared and set, but not checked!)
 +
 +
Looking at how this is handled in other components in Joomla I've noticed that:
 +
 +
'''"core.delete"''' is enforced in the model class: ''admin/models/helloworld.php'' by adding these lines:
 +
 +
<source lang='php'>
 +
        /**
 +
        * Method to check if it's OK to delete a message. Overwrites JModelAdmin::canDelete
 +
        */
 +
        protected function canDelete($record)
 +
        {
 +
            if( !empty( $record->id ) ){
 +
                $user = JFactory::getUser();
 +
                return $user->authorise( "core.delete", "com_helloworld.message." . $record->id );
 +
            }
 +
        }
 +
</source>
 +
 +
'''"core.edit"''' (and '''core.add''' if you wish) are enforced in the sub-controller (NOT in the model). I don't know why this is so, but that's how other components do it. You need to add the following lines in the file: ''/admin/controllers/helloworld.php''
 +
 +
<source lang='php'>
 +
 +
    /**
 +
    * Implement to allowAdd or not
 +
    *
 +
    * Not used at this time (but you can look at how other components use this....)
 +
    * Overwrites: JControllerForm::allowAdd
 +
    *
 +
    * @param array $data
 +
    * @return bool
 +
    */
 +
    protected function allowAdd($data = array())
 +
    {
 +
        return parent::allowAdd($data);
 +
    }
 +
 +
    /**
 +
    * Implement to allow edit or not
 +
    * Overwrites: JControllerForm::allowEdit
 +
    *
 +
    * @param array $data
 +
    * @param string $key
 +
    * @return bool
 +
    */
 +
    protected function allowEdit($data = array(), $key = 'id')
 +
    {
 +
        $id = isset( $data[ $key ] ) ? $data[ $key ] : 0;
 +
        if( !empty( $id ) ){
 +
            $user = JFactory::getUser();
 +
            return $user->authorise( "core.edit", "com_helloworld.message." . $id );
 +
        }
 +
    }
 +
 +
</source>
 +
 +
Once you implement the changes above the tutorial should work as intended. (''allowAdd'' should also be implemented to check for category permission at least, but since the author of the tutorial did not add a "core.add" action for the "message" section, I'll leave like it is.
 +
 +
[[User:Ilie.pandia|Ilie Pandia]] ([[User talk:Ilie.pandia|talk]]) 06:08, 11 October 2012 (CDT)
 +
 
Somehow the ACL doesn't work on Edit permission for me. It shows both Save & New and Save as Copy buttons when it has no create rights. Gone through the code twice, but cannot see anything wrong with it... Anybody else have same problem? --[[User:A2Ggeir|A2Ggeir]] 10:19, 6 December 2010 (UTC)
 
Somehow the ACL doesn't work on Edit permission for me. It shows both Save & New and Save as Copy buttons when it has no create rights. Gone through the code twice, but cannot see anything wrong with it... Anybody else have same problem? --[[User:A2Ggeir|A2Ggeir]] 10:19, 6 December 2010 (UTC)
  
Line 64: Line 126:
  
 
[[User:Vipantonio|Vipantonio]] 06:19, 9 August 2012 (CDT)
 
[[User:Vipantonio|Vipantonio]] 06:19, 9 August 2012 (CDT)
 +
 +
== Adding Dependent Table Permissions (Expanded from the tutorial and not part of it) ==
 +
 +
It might be worth noting that if one is using dependent tables in a component, the permissions need to be extended to the dependent table's views. For example, if you had a component for making picture Galleries with pictures as Gallery Items, you would have views for Galleries, Gallery (Edit Form), GalleryItems,and GalleryItem (Edit Form).
 +
 +
Adding permissions to the Gallery views (Galleries and Gallery) would be the same as shown in the tutorial. To add the permissions to the Gallery Item views (GalleryItems and GalleryItem) is slightly different.
 +
 +
Assuming one wants the Gallery Items to have the same permissions as their parent Gallery (and not individual permissions for each item), the foreign key needs to be fed back to the getActions function.
 +
 +
In the GalleryItems view the statement would be:
 +
 +
<pre>$this->canDo = GalleryHelper::getActions($this->items[0]->gallery_id);
 +
// gallery_id being the foreign key to the gallery table</pre>
 +
 +
Since this is the list view of the items contained in the gallery, the view gets items (plural). Their foreign keys are all the same though, so looking at the first one in the array gets the correct value.
 +
 +
The GalleryItem view, which only pulls up one item would be:
 +
 +
<pre>$this->canDo = GalleryHelper::getActions($this->item->gallery_id);</pre>
 +
 +
The logic may be slightly different as well. For example, adding or deleting a Gallery Item is editing the Gallery, so it may be better to simply use core.edit for every action in the Gallery Items portion of the component.
 +
 +
Lastly, the permission code in the tutorial prevents the tasks from being completed. The views can still be loaded by direct url access as long as the user is logged into the back end and has access to the component. If there are actions that can be taken like using a media manager which may not require the form to be submitted, or if something confidential may be displayed, consider preventing the view with something like this for the dependent table (GalleryItems) where no action should be taken without edit permission:
 +
 +
<pre>if ($this->canDo->get('core.edit'))
 +
{
 +
parent::display($tpl);
 +
} else {
 +
JFactory::getApplication()->enqueueMessage(JText::_('COM_GALLERY_NO_EDIT_PERMISSION'), 'error');
 +
}</pre>
 +
 +
or this for the primary table (Galleries) where one might create a new gallery even if they can't edit some of the galleries:
 +
<pre>if ($this->item->gallery_id)
 +
{
 +
if ($this->canDo->get('core.edit'))
 +
{
 +
parent::display($tpl);
 +
} else {
 +
JFactory::getApplication()->enqueueMessage(JText::_('COM_GALLERY_NO_EDIT_PERMISSION'), 'error');
 +
}
 +
// IF THIS IS A NEW ITEM (gallery_id == null)
 +
} else {
 +
if ($this->canDo->get('core.create'))
 +
{
 +
parent::display($tpl);
 +
} else {
 +
JFactory::getApplication()->enqueueMessage(JText::_('COM_GALLERY_NO_CREATE_PERMISSION'), 'error');
 +
}
 +
}</pre>
 +
 +
[[User:Neo314|Neo314]] ([[User talk:Neo314|talk]]) 07:59, 12 March 2013 (CDT)
 +
 +
== Setting of permissions on the item level is shown twice ==
 +
 +
The setting of permissions on the item level is shown twice. One time directly "under" categories-selection and one time below the complete form (which is the correct one).
 +
Here's my vereinsverwaltung.xml (i replaced "helloworld" with "vereinsverwaltung" so its admin/models/forms/helloworld.xml)
 +
 +
<source lang='xml'>
 +
<?xml version="1.0" encoding="utf-8"?>
 +
<form addrulepath="/administrator/components/com_vereinsverwaltung/models/rules">
 +
<fieldset>
 +
<field name="id" type="hidden" />
 +
<field name="greeting" type="text"
 +
label="COM_VEREINSVERWALTUNG_VEREINSVERWALTUNG_GREETING_LABEL"
 +
description="COM_VEREINSVERWALTUNG_VEREINSVERWALTUNG_GREETING_DESC"
 +
size="40" class="inputbox validate-greeting" validate="greeting"
 +
required="true" default="" />
 +
<field name="catid" type="category" extension="com_vereinsverwaltung"
 +
class="inputbox" default=""
 +
label="COM_VEREINSVERWALTUNG_VEREINSVERWALTUNG_FIELD_CATID_LABEL"
 +
description="COM_VEREINSVERWALTUNG_VEREINSVERWALTUNG_FIELD_CATID_DESC"
 +
required="true">
 +
<option value="0">JOPTION_SELECT_CATEGORY</option>
 +
</field>
 +
</fieldset>
 +
    <fieldset name="accesscontrol">
 +
        <field name="asset_id" type="hidden" filter="unset" />
 +
        <field name="rules"
 +
                type="rules"
 +
                label="JFIELD_RULES_LABEL"
 +
                translate_label="false"
 +
                filter="rules"
 +
                validate="rules"
 +
                class="inputbox"
 +
                component="com_vereinsverwaltung"
 +
                section="message"
 +
        />
 +
    </fieldset>
 +
<fields name="params">
 +
<fieldset
 +
name = "params"
 +
label = "JGLOBAL_FIELDSET_DISPLAY_OPTIONS"
 +
>
 +
<field
 +
name="show_category"
 +
type="list"
 +
label="COM_VEREINSVERWALTUNG_VEREINSVERWALTUNG_FIELD_SHOW_CATEGORY_LABEL"
 +
description="COM_VEREINSVERWALTUNG_VEREINSVERWALTUNG_FIELD_SHOW_CATEGORY_DESC"
 +
default=""
 +
>
 +
<option value="">JGLOBAL_USE_GLOBAL</option>
 +
<option value="0">JHIDE</option>
 +
<option value="1">JSHOW</option>
 +
</field>
 +
</fieldset>
 +
</fields>
 +
</form>
 +
</source>
 +
 +
Maybe someone could help me to fix it?

Revision as of 14:46, 3 May 2013

Checking the permissions on the Server Side[edit]

The tutorial at the moment of writing is not enforcing the permissions on the server side, allowing a forged request to modify data. (Permissions are only declared and set, but not checked!)

Looking at how this is handled in other components in Joomla I've noticed that:

"core.delete" is enforced in the model class: admin/models/helloworld.php by adding these lines:

        /**
         * Method to check if it's OK to delete a message. Overwrites JModelAdmin::canDelete
         */
        protected function canDelete($record)
        {
            if( !empty( $record->id ) ){
                $user = JFactory::getUser();
                return $user->authorise( "core.delete", "com_helloworld.message." . $record->id );
            }
        }

"core.edit" (and core.add if you wish) are enforced in the sub-controller (NOT in the model). I don't know why this is so, but that's how other components do it. You need to add the following lines in the file: /admin/controllers/helloworld.php

    /**
     * Implement to allowAdd or not
     *
     * Not used at this time (but you can look at how other components use this....)
     * Overwrites: JControllerForm::allowAdd
     *
     * @param array $data
     * @return bool
     */
    protected function allowAdd($data = array())
    {
        return parent::allowAdd($data);
    }

    /**
     * Implement to allow edit or not
     * Overwrites: JControllerForm::allowEdit
     *
     * @param array $data
     * @param string $key
     * @return bool
     */
    protected function allowEdit($data = array(), $key = 'id')
    {
        $id = isset( $data[ $key ] ) ? $data[ $key ] : 0;
        if( !empty( $id ) ){
            $user = JFactory::getUser();
            return $user->authorise( "core.edit", "com_helloworld.message." . $id );
        }
    }

Once you implement the changes above the tutorial should work as intended. (allowAdd should also be implemented to check for category permission at least, but since the author of the tutorial did not add a "core.add" action for the "message" section, I'll leave like it is.

Ilie Pandia (talk) 06:08, 11 October 2012 (CDT)

Somehow the ACL doesn't work on Edit permission for me. It shows both Save & New and Save as Copy buttons when it has no create rights. Gone through the code twice, but cannot see anything wrong with it... Anybody else have same problem? --A2Ggeir 10:19, 6 December 2010 (UTC)

Did a little debug and it seems the values from function canDo() in Helper does not return the right values when it is in edit view.

Result when in listview:

  'core.admin' => NULL,
  'core.manage' => true,
  'core.create' => false,
  'core.edit' => true,
  'core.delete' => false,

Result when in editview:

  'core.admin' => NULL,
  'core.manage' => NULL,
  'core.create' => true,
  'core.edit' => true,
  'core.delete' => true,

--A2Ggeir 12:02, 7 December 2010 (UTC)

Delet dosn't work[edit]

when you want to delete a message it goes wrong and the message appears:

500 - Es ist ein Fehler aufgetreten

Layout „default“ nicht gefunden


downt know why its not working... maybee some can check this out.

Greetz


Ok, so I have carefully followed the tutorial to here. What I need to know now is HOW do I allow a user who only has edit.own rights to get to the admin edit for the component??

I tried for a while to create an edit page on the front end, but no luck and no help. It occurred to me that perhaps if I could not bring the mountain to Mohammed, I could get Mohammed access to the mountain. But how to do it without making every user an administrator? Even a manager has too much other access.

"In theory, there's no difference between theory and practice; in practice, there is" --Yogi Berra 10:14, 12 November 2011 (CST) Using v1.7


I think that this example is missing something in the bind method.

       // Bind the rules.
       if (isset($array['rules']) && is_array($array['rules']))
       {
           $rules = new JAccessRules($array['rules']);
           $this->setRules($rules);
       }

If we don't bind the rules then they are not saved in the asset table for the message/item...


Missing asset_id field[edit]

I think database table is missing field "asset_id", which is required. Watch this link here.

https://www.joomlajingle.com/blog/39-joomla-acl-for-developers

Vipantonio 06:19, 9 August 2012 (CDT)

Adding Dependent Table Permissions (Expanded from the tutorial and not part of it)[edit]

It might be worth noting that if one is using dependent tables in a component, the permissions need to be extended to the dependent table's views. For example, if you had a component for making picture Galleries with pictures as Gallery Items, you would have views for Galleries, Gallery (Edit Form), GalleryItems,and GalleryItem (Edit Form).

Adding permissions to the Gallery views (Galleries and Gallery) would be the same as shown in the tutorial. To add the permissions to the Gallery Item views (GalleryItems and GalleryItem) is slightly different.

Assuming one wants the Gallery Items to have the same permissions as their parent Gallery (and not individual permissions for each item), the foreign key needs to be fed back to the getActions function.

In the GalleryItems view the statement would be:

$this->canDo = GalleryHelper::getActions($this->items[0]->gallery_id);
// gallery_id being the foreign key to the gallery table

Since this is the list view of the items contained in the gallery, the view gets items (plural). Their foreign keys are all the same though, so looking at the first one in the array gets the correct value.

The GalleryItem view, which only pulls up one item would be:

$this->canDo = GalleryHelper::getActions($this->item->gallery_id);

The logic may be slightly different as well. For example, adding or deleting a Gallery Item is editing the Gallery, so it may be better to simply use core.edit for every action in the Gallery Items portion of the component.

Lastly, the permission code in the tutorial prevents the tasks from being completed. The views can still be loaded by direct url access as long as the user is logged into the back end and has access to the component. If there are actions that can be taken like using a media manager which may not require the form to be submitted, or if something confidential may be displayed, consider preventing the view with something like this for the dependent table (GalleryItems) where no action should be taken without edit permission:

if ($this->canDo->get('core.edit'))
{
	parent::display($tpl);
} else {
	JFactory::getApplication()->enqueueMessage(JText::_('COM_GALLERY_NO_EDIT_PERMISSION'), 'error');
}

or this for the primary table (Galleries) where one might create a new gallery even if they can't edit some of the galleries:

if ($this->item->gallery_id)
{
	if ($this->canDo->get('core.edit'))
	{
		parent::display($tpl);
	} else {
		JFactory::getApplication()->enqueueMessage(JText::_('COM_GALLERY_NO_EDIT_PERMISSION'), 'error');
	}
// IF THIS IS A NEW ITEM (gallery_id == null)
} else {
	if ($this->canDo->get('core.create'))
	{
		parent::display($tpl);
	} else {
		JFactory::getApplication()->enqueueMessage(JText::_('COM_GALLERY_NO_CREATE_PERMISSION'), 'error');
	}
}

Neo314 (talk) 07:59, 12 March 2013 (CDT)

Setting of permissions on the item level is shown twice[edit]

The setting of permissions on the item level is shown twice. One time directly "under" categories-selection and one time below the complete form (which is the correct one). Here's my vereinsverwaltung.xml (i replaced "helloworld" with "vereinsverwaltung" so its admin/models/forms/helloworld.xml)

<?xml version="1.0" encoding="utf-8"?>
<form addrulepath="/administrator/components/com_vereinsverwaltung/models/rules">
	<fieldset>
		<field name="id" type="hidden" />
		<field name="greeting" type="text"
			label="COM_VEREINSVERWALTUNG_VEREINSVERWALTUNG_GREETING_LABEL"
			description="COM_VEREINSVERWALTUNG_VEREINSVERWALTUNG_GREETING_DESC"
			size="40" class="inputbox validate-greeting" validate="greeting"
			required="true" default="" />
		<field name="catid" type="category" extension="com_vereinsverwaltung"
			class="inputbox" default=""
			label="COM_VEREINSVERWALTUNG_VEREINSVERWALTUNG_FIELD_CATID_LABEL"
			description="COM_VEREINSVERWALTUNG_VEREINSVERWALTUNG_FIELD_CATID_DESC"
			required="true">
			<option value="0">JOPTION_SELECT_CATEGORY</option>
		</field>
	</fieldset>
    <fieldset name="accesscontrol">
        <field name="asset_id" type="hidden" filter="unset" />
        <field name="rules"
                type="rules"
                label="JFIELD_RULES_LABEL"
                translate_label="false"
                filter="rules"
                validate="rules"
                class="inputbox"
                component="com_vereinsverwaltung"
                section="message"
        />
    </fieldset>
	<fields name="params">
		<fieldset
			name = "params"
			label = "JGLOBAL_FIELDSET_DISPLAY_OPTIONS"
		>
			<field
				name="show_category"
				type="list"
				label="COM_VEREINSVERWALTUNG_VEREINSVERWALTUNG_FIELD_SHOW_CATEGORY_LABEL"
				description="COM_VEREINSVERWALTUNG_VEREINSVERWALTUNG_FIELD_SHOW_CATEGORY_DESC"
				default=""
			>
				<option value="">JGLOBAL_USE_GLOBAL</option>
				<option value="0">JHIDE</option>
				<option value="1">JSHOW</option>
			</field>
		</fieldset>
	</fields>
</form>

Maybe someone could help me to fix it?