Categories


Archives


Recent Posts


Categories


Magento 2: Understanding Access Control List Rules

astorm

Frustrated by Magento? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

No Frills Magento Layout is the only Magento front end book you'll ever need. Get your copy today!

The Magento backend application, (sometimes called “The Admin” or adminhtml area), is where a system owner manages their Magento store. This is where users interact with web forms to add new products, change configurations, etc. Magento is a multiuser application — i.e. a business owner may have a backend account for herself, but also give each individual member of her staff an account to access the Magento backend. Furthermore, that business owner can turn off features for different accounts.

For example, the customer support staff may only have access to the customer and orders sections, while the sales staff may have access to both these sections and the marketing section. In the Magento backend, a system owner can accomplish this via the System -> Users and Systems -> Roles sections. These two sections implement an authentication and authorization system.

For those of you too busy to read the wikipedia article, authentication is the act of ensuring a user is who they say they are. In simplified terms, this is the user entering an account name and password in a login screen. Systems with a higher level of general security or special PCI compliance requirements are often required to implement two factor authentication. A common two factor authentication process is a password, combined with an SMS/Text message sent to their phone.

Once a user proves who they are, the next step is an authorization system. Authorization systems implement rules that say what a user is allowed to do in a system. Magento’s authorization system allows a system owner to

  1. Create an unlimited number of logical Roles. Some example of roles might include Sales Staff, Support Staff, IT Staff, Contract Developers, Executive Team, etc.

  2. Assign a set of Access Control List (ACL) rules to each individual role

Each access control rule defines a specific permission granted to the user in the system. You can see a list of these rules by navigating to

System -> User Roles -> Add/Edit Role -> Role Resources

and selecting Custom from the drop down menu

Each individual rule controls access to a system feature. Tailoring a set of rules into a set of Roles that an individual business can use to run their online store is one of the many things a Magento system integrator or store owner will need to do.

The special Resource Access: all role is a super user role. These users are granted access to every resource in the system.

ACL Rules for Developers

As a module developer, ACL rules present a few interesting challenges. First, there are several places that you, as a module developer, are expected to add ACL rule checks to your module. A few examples

  1. Every URL endpoint/controller in the admin application must implement an _isAllowed method that determines if a user can access the URL endpoint.
  2. Every Menu Item in the left hand navigation also has a specific ACL rule that controls whether or not the menu displays for the logged in user. This is often the same rule from _isAllowed)

  3. Every configuration field in System -> Configuration has a specific ACL rule that controls whether or not the menu displays

Despite being required fields, there are no hard and fast rules as to how a module developer should setup and structure their own rules. Also, a module developer will likely want additional rules that are specific to their module. This article can’t answer these hard questions for you, but we will show you how to check the current user against a specific ACL rule, look up ID values for existing rules, and how to create your own tree of ACL rules.

Looking up a Rule ID

In Magento 2, each specific ACL rule is assigned an arbitrary string ID. You can find these IDs in a module’s etc/acl.xml file. For example, Magento defines the Stores -> Settings -> Google API ACL rule here

<!-- File: vendor/magento/module-google-analytics/etc/acl.xml -->
<?xml version="1.0"?>
<!--
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd">
    <acl>
        <resources>
            <resource id="Magento_Backend::admin">
                <resource id="Magento_Backend::stores">
                    <resource id="Magento_Backend::stores_settings">
                        <resource id="Magento_Config::config">
                            <resource id="Magento_GoogleAnalytics::google" title="Google API" />
                        </resource>
                    </resource>
                </resource>
            </resource>
        </resources>
    </acl>
</config>

You can find the specific rule by its title attribute. If you’re having trouble, it’s this one

<!-- File: vendor/magento/module-google-analytics/etc/acl.xml -->    
<resource id="Magento_GoogleAnalytics::google" title="Google API" />    

The ACL rule with the title “Google API” has an ACL ID of Magento_GoogleAnalytics::google. This is the ID you’ll use to check if the logged in user has access to this resource.

ACL IDs are mostly arbitrary strings. By convention, a Magento 2 ACL rule ID name is

  1. The name of the module
  2. Followed by two colon characters ::
  3. Followed by a lower case string describing the rule’s purpose

Also, Magento’s new XSD/XML validation system

<!-- File: vendor/magento/framework/Acl/etc/acl.xsd -->
<xs:simpleType name="typeId">
    <xs:annotation>
        <xs:documentation>
            Item id attribute can has only [a-z0-9/_]. Minimal length 3 symbol. Case insensitive.
        </xs:documentation>
    </xs:annotation>

    <xs:restriction base="xs:string">
        <xs:pattern value="([A-Z]+[a-zA-Z0-9]{1,}){1,}_[A-Z]+[A-Z0-9a-z]{1,}::[A-Za-z_0-9]{1,}" />
    </xs:restriction>
</xs:simpleType>

forces the rule to conform to the following regular expression

([A-Z]+[a-zA-Z0-9]{1,}){1,}_[A-Z]+[A-Z0-9a-z]{1,}::[A-Za-z_0-9]{1,}

All in all, while it’s possible to deviate slightly from Magento’s convention, it’s best to stick to it.

If you’re curious about the placement of the Magento_GoogleAnalytics::google rule inside the node structure of acl.xml files (i.e. what are its parent nodes), an acl.xml file is an infinitely deep XML tree of <resource/> nodes, with each node defining a new level in the ACL hierarchy. If that didn’t make sense, don’t worry, we’ll be running through a few examples later that should clear things up.

Before we move on to creating our own ACL rules, Magento 1 developers will want to take note. Magento 1 ACL rules did not have an explicit ID. Instead, the system derived an ID from the names of the XML nodes that defined the rules (i.e. foo/baz/bar). This means, in Magento 2, you can no longer look at an ID and be sure where it lives in the hierarchy, you can only be sure of the module that created it.

When I’m hunting through a Magento 2 installation for a specific ACL rule, I use a number of different unix commands in a terminal to search through the acl.xml files. For example, to find the Google API rule above, I used the following

$ find vendor/magento/ -name 'acl.xml' -exec grep -i 'Google API' '{}' +
vendor/magento//module-google-analytics/etc/acl.xml:
<resource id="Magento_GoogleAnalytics::google" title="Google API" />

This searches every acl.xml in vendor/magento for the string Google API.

Creating Your Own ACL Rules

When you create Magento admin features, you’ll need to add ACL rules to your module. We’re going to show you how to do this using pestle, and then explain what each file pestle created is for. If you’re not familiar with it, pestle is a free and open source PHP command line system that features a number of useful Magento 2 code generation tools.

First, we’ll want to create a blank module named Pulsestorm_AclExample. You can create the base module files using pestle’s generate_module command.

$ pestle.phar generate_module Pulsestorm AclExample 0.0.1

and then enable the module in Magento by running the following two commands

$ php bin/magento module:enable Pulsestorm_AclExample
$ php bin/magento setup:upgrade    

If you’re interested in creating a module by hand, or curious what the above pestle command is actually doing, take a look at our Introduction to Magento 2 — No More MVC article.

Next, we’re going to use pestle’s generate_acl command.

# with interactive input

$ pestle.phar generate_acl
Which Module? (Pulsestorm_HelloWorld)] Pulsestorm_AclExample
Rule IDs? (Pulsestorm_AclExample::top,Pulsestorm_AclExample::config,)] 
Created /path/to/magento/app/code/Pulsestorm/AclExample/etc/acl.xml

#without interactive input
$ pestle.phar generate_acl Pulsestorm_AclExample Pulsestorm_AclExample::top,Pulsestorm_AclExample::config

The first argument (Which Module?) lets pestle know which module’s acl.xml file it should use or create. The second argument (Rule IDs), is a comma separated list of Rule IDs — each comma represents a <resource/> sub-node in acl.xml.

If that didn’t make sense, open up the generated acl.xml

<?xml version="1.0"?>
<!-- File: app/code/Pulsestorm/AclExample/etc/acl.xml -->    
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd">
    <acl>
        <resources>
            <resource id="Magento_Backend::admin">
                <resource id="Pulsestorm_AclExample::top" title="TITLE HERE FOR">
                    <resource id="Pulsestorm_AclExample::config" title="TITLE HERE FOR"/>
                </resource>
            </resource>
        </resources>
    </acl>
</config>

Here you can see pestle created a Pulsestorm_AclExample::top rule that’s a parent of the Pulsestorm_AclExample::config rule (i.e. the first two rules in our comma separated list). You’ll also notice pestle created both these rules under the Magento_Backend::admin resource — all Magento ACL rules go under this node — it’s the top level node.

Let’s edit this file to give our rules some less generic titles

<!-- File: app/code/Pulsestorm/AclExample/etc/acl.xml -->    

<resource id="Pulsestorm_AclExample::top" title="Pulse Storm ACL Example Module">
    <resource id="Pulsestorm_AclExample::config" title="The First Rule"/>
</resource>

And, while we’re at it, lets add a second rule!

<!-- File: app/code/Pulsestorm/AclExample/etc/acl.xml -->    

<resource id="Pulsestorm_AclExample::top" title="Pulse Storm ACL Example Module">
    <resource id="Pulsestorm_AclExample::config" title="The First Rule"/>
    <resource id="Pulsestorm_AclExample::more_rules" title="The Second Rule"/>        
</resource>

With the above in place, clear your cache, and take a look at the Roles menu at System -> User Roles -> Add/Edit Role -> Role Resources. You should see your rules added to the system

That’s all there is to it! Your rules can now be assigned to admin roles in the system, and those admin roles can be assigned to users.

Programmatically Checking ACL Rules

The following assumes some base familiarity with Magento’s object and automatic constructor dependency injection systems, although if you’re not 100% comfortable with these concepts, just power through for the code snippets you’ll need!

Magento provides an abstract type, Magento\Framework\AuthorizationInterface, which a client programmer (you!) can use to validate the currently logged in user against a specific access control rule. i.e., if you were playing fast and loose with Magento’s Don’t use the Object Manager guidelines, the following

$auth = $object_manger->get('Magento\Framework\AuthorizationInterface');
if($auth->isAllowed('Pulsestorm_AclExample::config'))
{
    //user is logged in here
}
else
{
    //user is not logged in here
}

would check if the currently logged in user was assigned our Pulsestorm_AclExample::config rule. If you’re not playing fast and loose with Magento’s Don’t use the Object Manager guidelines, you can inject the auth checking object with something like this

public function __construct(Magento\Framework\AuthorizationInterface $auth)
{
    $this->authorization = $auth;
}

If you’re in a controller that extends the \Magento\Backend\App\Action controller, you automatically have access to the authorization checking object via the _authorization property.

namespace Pulsestorm\HelloAdmin\Controller\Adminhtml\Index;
class Index extends \Magento\Backend\App\Action
{
    protected function someControllerMethod()
    {
        return $this->_authorization->isAllowed('Pulsestorm_HelloAdmin::pulsestorm_helloadmin_index_index');
    }            

}

Regarding the controller method above — if you’re injecting additional arguments via the __construct method, don’t forget to include the admin context object (Magento\Backend\App\Action\Context). This context object is where the auth checking object is, itself, instantiated and injected.

class Index extends \Magento\Backend\App\Action
{
    protected $resultPageFactory;
    public function __construct(
        \Magento\Backend\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $resultPageFactory)
    {
        $this->resultPageFactory = $resultPageFactory;        
        return parent::__construct($context);
    }
    //...
}

Finally, for the curious, in a stock Magento install (circa spring 2016), the Magento\Framework\AuthorizationInterface object type resolves to a Magento\Framework\Authorization object. The class for this object is found here

#File: vendor/magento/framework/Authorization.php

If you’re having trouble with ACL rule debugging, this is where you’ll want to start.

Wrap Up

Access Control Rules are an important, but often overlooked part, of Magento extensions. While an extension’s functionality and ability to solve a business or technical problem is paramount, giving your extension users the ability to turn certain admin features on and off for certain users can often be the differences between a manager or store owner choosing your extension over a competitor’s.

However, even if you don’t want to slice your extension’s functionality into narrow bands, there are places in the Magento Admin where you’ll need to add ACL rules. Next time we’ll explore one of these sections, when we cover how to create Magento Admin MCV/MVVM controller endpoints.

Originally published May 2, 2016
Series Navigation<< Magento 2: Understanding Object RepositoriesMagento 2: Admin Menu Items >>