API Resource Authorization

Directory Structure

The Support Directory

Elentra API 3.1 (Elentra ME 1.16.1+) introduces the Support directory to the top level of the API. This directory is home to the reusable "framework-like" components that are critical to supporting the Elentra API and internal developer APIs. In an effort to increase navigability for developers, this directory has been structured in a way that closely resembles Laravel's Illuminate framework (which the Elentra API is built on top of).

In Elentra API 3.1, new modernized base classes have been provided which can be extended to manage permissions and authorization of API resources. They can be found in the Support\Acl namespace within the support directory. Additionally a Facade wrapper has also been provided to simplify interacting with the Zend ACL library in a way that integrates better with Laravel applications.

app/
└── Support/
    ├── Acl/ 
    |   ├── Assertion.php
    |   ├── Policy.php
    |   └── Resource.php
    └── Facades/
        └── Acl.php

Resources & Assertions

ACL resources and assertions were have been historically defined entrada_acl.inc.php file. This has changed with Elentra API 3.1+ as they can now be defined inside your API modules. Create a new directory called Acl in our sandbox module. Inside of the Acl directory create a new directory named Resources and another called Assertions. Classes that you define in these directories should extend the base Assertion and Resource classes used by our SandboxPolicy class.

app/
└─ Modules/
    └── Sandboxes/
        ├── Acl/
        |   ├── Assertions/
        |   |   └── SandboxOwnerAssertion.php
        |   └── Resources/
        |       └── SandboxResource.php  
        ├── Models/
        |   └── Sandbox.php
        ├── Policies/
        |   └── SandboxPolicy.php
        └── Providers/
            └── AuthServiceProvider.php

Defining Permissions

As of Elentra ME 1.15, the Entrada Zend ACL "MOM array" has been replaced with entries in a series of tables within the auth database.

ACL Resource Types

Begin by inserting a new entry into the acl_lu_resource_types for our new resource type , in this example we will be adding support for authorizing sandbox resources.

ACL Inheritance

In order for our resource to be included in the ACL permission tree, we must also add an entry to the acl_resource_inheritance table.

ACL Permissions

We must add a rule to the acl_permissions table for each role or permission we intend to give access to a resource. The value of the resource_type field must be identical to the resource type that we added to the acl_lu_resource_types table. The entity type refers to the combination of groups and roles that we would like to allow access to the resource. Here we have chosen to give access to all administrators who are part of the medtech group. Optionally we can specify the fully qualified name of an assertion class that will perform further authorization checks. Finally, we set the flags for each CRUD permission we would like users to have.

Defining Resources

Resource classes are required by Zend ACL in order to resolve the type of resource that is attempting to be authorized. They also allow the developer to specify whether or not the rules should be applied to all resources of a certain type or only a specific instance. In our Sandbox API module we must create a new class called SandboxResource that extends the base Resource class in the support directory. We can then override the getResourceId method to return the value of either the general or the specific resource identifier.

Creating Assertions

Assertions classes provide additional checks to verify whether the specific user has access to the specific resource that is being authorized. In Elentra API 3.1, Eloquent and query builder are now fully supported when defining assertions inside of API an module. In our Sandbox API module we must extend the base Assertion class in the support directory. We then override the isUserAllowed method which receives the user that is being authorized; the ID of the resource; the current authorization context; and the CRUD permission that is being checked. isUserAllowed must either return true or false depending on whether the user has the necessary privileges to access the resource.

Creating Policies

Laravel provides a resource authorization system which it calls Gates. Due to the dynamic nature of gates, we are able to neatly map gate policy methods directly to Elentra's Zend ACL permission system. We begin by extending the base Policy class provided in the support directory. This class has a protected property that contains a reference to the Entrada_ACL class.

The Acl facade provided in the support directory can also be used and is preferable to directly accessing the global $ENTRADA_ACL instance.

For a standard API resource we will create public methods for each CRUD operation.

In each method we call the amIAllowed method on the policy's ACL instance, passing to it a new SandboxResource instance and the permission being requested. Because the policy in this example is only used when authorizing API requests, we are not required to pass along the $user parameter. The third parameter of amIAllowed specifies whether or not the rule's assertions should be applied. When performing general authorization without a specific resource instance, we can simply pass false to disable assertion checks.

Registering Policies

Laravel provides many different ways for resources to be authorized depending on your specific use case. In this example we'll be focusing on using Service Providers, the most commonly used method for registering policies in Elentra. We begin by creating a new class in our Sandbox module's Providers directory that extends the Illuminate\Foundation\Support\Providers\AuthServiceProvider base class. This class provides a protected array that maps models to policies, here we have mapped our Sandbox model to our SandboxPolicy . Create a new method called boot that calls the base class' registerPolicies method.

A service provider'sbootmethod will be called automatically by Laravel once the application has finished registering all of its service providers.

Authorizing Requests

The preferred method for authorizing API requests is to call the controller's authorize helper in each controller's request handler. There are times, however,where a more general or more fine-grained approach is acceptable. The authorize helper requires a string for its first parmeter that corresponds to the exact method name defined in our SandboxPolicy above. The second parameter accepts either a model instance or class name and the optional third parameter is an array of any additional arguments you would like to pass to the policy method. The authorize helper returns true if the current user is allowed to access the resource or throws an exception if they cannot. If an unauthorized exception is thrown, a status code of 403 will automatically be returned in the response.

Checking Permissions

Authorization can also be performed inline using the auth user instance. The User::can method takes the same parameters as the controller authorize helper. However it does not throw an exception and will only return either true or false depending on whether a user can access the resource.

Additional Resources

Laravel Authorization Documentation

Last updated