2017 © Pedro Peláez
 

library gate-crasher

Safer Laravel superuser auth

image

unstoppablecarl/gate-crasher

Safer Laravel superuser auth

  • Thursday, May 31, 2018
  • by unstoppablecarl
  • Repository
  • 1 Watchers
  • 4 Stars
  • 2 Installations
  • PHP
  • 0 Dependents
  • 1 Suggesters
  • 0 Forks
  • 0 Open issues
  • 6 Versions
  • 0 % Grown

The README.md

Gate Crasher

Safer Laravel superuser auth., (*1)

Source Code ![Latest Version][badge-release] Software License ![Build Status][badge-build] [Coverage Status][coverage] ![Total Downloads][badge-downloads], (*2)

About

Gate Crasher leverages the Laravel Gate::before($beforeCallback) api to authorize superuser abilities skipping the normal Gate ability/policy functionality. When Gate::allows() is called, If the $beforeCallback returns a non-null result that result will be considered the result of the check., (*3)

See https://laravel.com/docs/5.2/authorization, (*4)

See Illuminate\Auth\Access\Gate::before() and Illuminate\Contracts\Auth\Access\Gate::before() in the Laravel framework., (*5)

Requirements

  • PHP >= 5.5.9
  • Laravel >= 5.2

Installation

The preferred method of installation is via Packagist and Composer. Run the following command to install the package and add it as a requirement to your project's composer.json:, (*6)

composer require unstoppablecarl/gate-crasher

Usage

A Gate Crasher instance should be registered within the boot() method of a service provider., (*7)

Minimal gate crasher setup

<?php

use Gate;
use Illuminate\Contracts\Auth\Access\Gate as GateContract;
use Illuminate\Support\ServiceProvider;
use UnstoppableCarl\GateCrasher\GateCrasher;

class GateCrasherServiceProvider extends ServiceProvider
{
    public function boot(GateContract $gate)
    {
        // define a way to identify super users
        $superUserChecker = function ($user) {
            return $user->isSuperUser();
        };

        $gateCrasher = new GateCrasher($superUserChecker);

        $beforeCallback = function ($user, $ability, $args) use ($gateCrasher) {
            return $gateCrasher->before($user, $ability, $args);
        };

        // get Gate instance via boot() dependency injection or app()
        $gate = app(GateContract::class);

        // set before callback to a Gate instance
        $gate->before($beforeCallback);

        // set before callback using facade
        Gate::before($beforeCallback);

        // PRO TIP: use `GateCrasher::register()`
        // to create and set the before callback on a Gate instance for you
        $gateCrasher->register($gate);
    }
}

The default configuration of a Gate Crasher instance creates the following behavior:, (*8)

<?php

// login a super user
$gate = Gate::withUser($mySuperUser);

// allows ALL non-policy abilities
$gate->allows('foo'); // true

// allows ALL non-Super User policy abilities
$gate->allows('update', $someUser); // true

// denies abilities that target self
$gate->allows('delete', $mySuperUser);

// denies abilities that target other Super Users (even when logged in as a Super User)
$gate->allows('delete', $someOtherSuperUser);

Configuring Abilities

<?php

use UnstoppableCarl\GateCrasher\GateCrasher;

$superUserChecker = function ($user) {
    return $user->isSuperUser();
};

// the default result of any ability checks in the given context
$contextDefaults = [
    // ignored if null, falls back to default Gate::allows() check
    GateCrasher::SUPER_USER__TARGETING__SELF           => null,

    // deny all abilities from non-super users targeting super users
    GateCrasher::SUPER_USER__TARGETING__SUPER_USER     => false,

    // deny all abilities from non-super users targeting super users
    GateCrasher::NON_SUPER_USER__TARGETING__SUPER_USER => false,
];

// the result of specific ability checks in the given context
$abilityOverrides = [
    // super users can always update but never delete themselves
    GateCrasher::SUPER_USER__TARGETING__SELF           => [
        'update' => true,
        'delete' => false,
        // ...
    ],
    // super users can never update or delete other super users
    GateCrasher::SUPER_USER__TARGETING__SUPER_USER     => [
        'update' => false,
        'delete' => false,
        // ...
    ],
    // non-super users can never update or delete other super users
    GateCrasher::NON_SUPER_USER__TARGETING__SUPER_USER => [
        // ignored if null, falls back to $contextDefaults then to Gate::allows() check
        'view'   => null,
        'update' => false,
        'delete' => false,
        // ...
    ],
];

$gateCrasher = new GateCrasher($superUserChecker, $contextDefaults, $abilityOverrides);
use Illuminate\Contracts\Auth\Access\Gate as GateContract;

$gate = app(GateContract::class);
$gateCrasher->register($gate);

Examples

An example service provider is included here:, (*9)

examples/GateCrasherServiceProvider.php, (*10)

How It Works

This is an abstract description of how Gate Crasher works. See the source code for exact details., (*11)

<?php

use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;

Gate::allows('foo', $target);

$targetIsUser = $target instanceof AuthenticatableContract;

// allow ANY non-Super User target
// (target can be a User, another Model, or any other value)
if($sourceIsSuperUser && !$targetIsSuperUser){
    return true;
}

// determine the context
if($sourceIsSuperUser && $targetIsSuperUser){
    $context = GateCrasher::SUPER_USER__TARGETING__SUPER_USER;
}
else if($sourceIsSuperUser && $targetIsSelf){
    $context = GateCrasher::SUPER_USER__TARGETING__SELF;
}
else if(!$sourceIsSuperUser && $targetIsSuperUser){
    $context = GateCrasher::NON_SUPER_USER__TARGETING__SUPER_USER;
}

// check for non-null ability override
$abilityOverrideValue = $abilityOverrides[$context]['foo'];
if ($abilityOverrideValue !== null) {
    return $abilityOverrideValue;
}

// check for non-null context default
$contextDefaultValue = $contextDefaults[$context];
if($contextDefaultValue !== null){
    return $contextDefaultValue;
}

// DEFAULT GATE BEHAVIOR

// if a policy is registered for $target use the policy
// if an ability callback is registered for 'foo' use the registered callback
// return false;

Running the tests

Run Unit Tests, (*12)

$ composer phpunit

Run Codesniffer (psr-2), (*13)

$ composer phpcs

Run both, (*14)

$ composer test

Contributing

Contributions and Pull Requests welcome!, (*15)

Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests to us., (*16)

Authors

See also the list of contributors who participated in this project., (*17)

License

This project is licensed under the MIT License - see the LICENSE.md file for details, (*18)

The Versions

26/07 2017
24/07 2017
24/07 2017