├── Tests
├── Fixtures
│ ├── no_name.yaml
│ ├── full_definition.yaml
│ └── content.yaml
├── TestRole.php
├── TestUser.php
├── Form
│ └── Type
│ │ ├── ValidatorExtensionTypeTestCase.php
│ │ ├── RoleFormTypeTest.php
│ │ └── TypeTestCase.php
├── Util
│ └── PermissionsHandlerTest.php
├── BundleTest.php
├── Functional
│ └── DependencyInjectionTest.php
├── Model
│ ├── RoleTest.php
│ └── UserTest.php
├── Doctrine
│ └── RoleManagerTest.php
├── DependencyInjection
│ └── EloyekunlePermissionsExtensionTest.php
└── Security
│ └── PermissionVoterTest.php
├── .gitignore
├── Resources
└── config
│ ├── serializer
│ └── Model.User.yml
│ ├── permissions.xml
│ ├── validator
│ └── validation.xml
│ ├── role.xml
│ ├── doctrine.xml
│ ├── doctrine_role.xml
│ ├── security.xml
│ ├── doctrine-mapping
│ ├── Role.orm.xml
│ └── User.orm.xml
│ ├── storage-validation
│ └── orm.xml
│ └── schema
│ └── doctrine-mapping.xsd
├── phpunit
├── Model
├── RoleManager.php
├── RoleManagerInterface.php
├── RoleInterface.php
├── UserInterface.php
├── User.php
└── Role.php
├── phpunit.xml.dist
├── Util
├── PermissionsHandlerInterface.php
└── PermissionsHandler.php
├── .php_cs.dist
├── .travis.yml
├── LICENSE
├── DependencyInjection
├── Compiler
│ └── ValidationPass.php
├── Configuration.php
└── EloyekunlePermissionsExtension.php
├── composer.json
├── Form
└── Type
│ └── RoleFormType.php
├── EloyekunlePermissionsBundle.php
├── Security
└── PermissionsVoter.php
├── Doctrine
└── RoleManager.php
└── README.md
/Tests/Fixtures/no_name.yaml:
--------------------------------------------------------------------------------
1 | permissions:
2 | 'delete users':
3 | title: 'Delete Users'
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | vendor/
3 | composer.lock
4 | phpunit.xml
5 | .php_cs
6 | .php_cs.cache
7 | .phpunit
--------------------------------------------------------------------------------
/Tests/Fixtures/full_definition.yaml:
--------------------------------------------------------------------------------
1 | title: Users
2 |
3 | permissions:
4 | 'edit users':
5 | title: 'Edit Users'
6 |
--------------------------------------------------------------------------------
/Resources/config/serializer/Model.User.yml:
--------------------------------------------------------------------------------
1 | Eloyekunle\PermissionsBundle\Model\User:
2 | properties:
3 | userRoles:
4 | expose: true
--------------------------------------------------------------------------------
/phpunit:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\Tests;
13 |
14 | use Eloyekunle\PermissionsBundle\Model\Role;
15 |
16 | class TestRole extends Role
17 | {
18 | }
19 |
--------------------------------------------------------------------------------
/Tests/TestUser.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\Tests;
13 |
14 | use Eloyekunle\PermissionsBundle\Model\User;
15 |
16 | class TestUser extends User
17 | {
18 | }
19 |
--------------------------------------------------------------------------------
/Resources/config/permissions.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 | %eloyekunle_permissions.module.definitions_path%
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Resources/config/validator/validation.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Model/RoleManager.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\Model;
13 |
14 | abstract class RoleManager implements RoleManagerInterface
15 | {
16 | /**
17 | * {@inheritdoc}
18 | */
19 | public function createRole()
20 | {
21 | $class = $this->getClass();
22 | $role = new $class();
23 |
24 | return $role;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ./Tests
7 |
8 |
9 |
10 |
11 |
12 | ./
13 |
14 | ./Resources
15 | ./Tests
16 | ./vendor
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Resources/config/role.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 | %eloyekunle_permissions.model.role.class%
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Resources/config/doctrine.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 | %eloyekunle_permissions.model_manager_name%
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Util/PermissionsHandlerInterface.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\Util;
13 |
14 | interface PermissionsHandlerInterface
15 | {
16 | /**
17 | * Gets all available permissions.
18 | *
19 | * @return array
20 | * A multi-dimensional array with the permission key as the keys, and other fields in an array as the value
21 | */
22 | public function getPermissions();
23 | }
24 |
--------------------------------------------------------------------------------
/Resources/config/doctrine_role.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 | %eloyekunle_permissions.model.role.class%
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Resources/config/security.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Resources/config/doctrine-mapping/Role.orm.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Resources/config/storage-validation/orm.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.php_cs.dist:
--------------------------------------------------------------------------------
1 |
7 |
8 | For the full copyright and license information, please view the LICENSE
9 | file that was distributed with this source code.
10 | EOF;
11 |
12 | return PhpCsFixer\Config::create()
13 | ->setRules([
14 | '@Symfony' => true,
15 | 'combine_consecutive_unsets' => true,
16 | 'header_comment' => ['header' => $header],
17 | 'linebreak_after_opening_tag' => true,
18 | 'no_php4_constructor' => true,
19 | 'no_useless_else' => true,
20 | 'ordered_class_elements' => true,
21 | 'ordered_imports' => true,
22 | 'php_unit_construct' => true,
23 | 'php_unit_strict' => true,
24 | 'phpdoc_no_empty_return' => false,
25 | ])
26 | ->setUsingCache(true)
27 | ->setRiskyAllowed(true)
28 | ->setFinder(
29 | PhpCsFixer\Finder::create()
30 | ->in(__DIR__)
31 | )
32 | ;
33 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | sudo: false
4 |
5 | cache:
6 | directories:
7 | - .phpunit
8 | - $HOME/.composer/cache/files
9 |
10 | branches:
11 | only:
12 | - master
13 | - /^\d+\.\d+$/
14 |
15 | matrix:
16 | fast_finish: true
17 | include:
18 | - php: 5.6
19 | # Symfony 3 LTS
20 | - php: 7.0
21 | env: SYMFONY_LTS='^3'
22 | # Symfony 4
23 | - php: 7.1
24 | - php: 7.2
25 | # development dependencies
26 | - php: 7.2
27 | env: DEPENDENCIES='dev'
28 | allow_failures:
29 | - php: 7.2
30 | env: DEPENDENCIES='dev'
31 |
32 | before_install:
33 | - echo "memory_limit=4G" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
34 | - if [ "$TRAVIS_PHP_VERSION" != "hhvm" ]; then phpenv config-rm xdebug.ini; fi
35 | - if [ "$DEPENDENCIES" != "" ]; then composer config minimum-stability $DEPENDENCIES; fi
36 | - if [ "$SYMFONY_LTS" != "" ]; then composer require --dev --no-update symfony/lts=$SYMFONY_LTS; fi
37 |
38 | install:
39 | - composer update $COMPOSER_FLAGS --prefer-dist
40 | - ./phpunit install
41 |
42 | script: ./phpunit
43 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2018 Elijah Oyekunle (eloyekunle@gmail.com)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is furnished
8 | to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/Resources/config/doctrine-mapping/User.orm.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/DependencyInjection/Compiler/ValidationPass.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\DependencyInjection\Compiler;
13 |
14 | use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
15 | use Symfony\Component\DependencyInjection\ContainerBuilder;
16 |
17 | /**
18 | * Registers the additional validators according to the storage.
19 | */
20 | class ValidationPass implements CompilerPassInterface
21 | {
22 | /**
23 | * {@inheritdoc}
24 | */
25 | public function process(ContainerBuilder $container)
26 | {
27 | $storage = $container->getParameter('eloyekunle_permissions.storage');
28 |
29 | $configDir = __DIR__.'/../../Resources/config';
30 | $validationFile = $configDir.'/storage-validation/'.$storage.'.xml';
31 |
32 | $validatorBuilder = $container->getDefinition('validator.builder');
33 | $validatorBuilder->addMethodCall('addXmlMappings', [[$validationFile, $configDir.'/validator/validation.xml']]);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Tests/Form/Type/ValidatorExtensionTypeTestCase.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\Tests\Form\Type;
13 |
14 | use Symfony\Component\Form\Extension\Validator\Type\FormTypeValidatorExtension;
15 | use Symfony\Component\Validator\ConstraintViolationList;
16 |
17 | /**
18 | * Class ValidatorExtensionTypeTestCase
19 | * FormTypeValidatorExtension added as default. Useful for form types with `constraints` option.
20 | *
21 | * @author Sullivan Senechal
22 | */
23 | class ValidatorExtensionTypeTestCase extends TypeTestCase
24 | {
25 | /**
26 | * @return array
27 | */
28 | protected function getTypeExtensions()
29 | {
30 | $validator = $this->getMockBuilder('Symfony\Component\Validator\Validator\ValidatorInterface')->getMock();
31 | $validator->method('validate')->will($this->returnValue(new ConstraintViolationList()));
32 |
33 | return array(
34 | new FormTypeValidatorExtension($validator),
35 | );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Tests/Form/Type/RoleFormTypeTest.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\Tests\Form\Type;
13 |
14 | use Eloyekunle\PermissionsBundle\Form\Type\RoleFormType;
15 | use Eloyekunle\PermissionsBundle\Tests\TestRole;
16 |
17 | class RoleFormTypeTest extends ValidatorExtensionTypeTestCase
18 | {
19 | public function testSubmit()
20 | {
21 | $role = new TestRole();
22 |
23 | $form = $this->factory->create(RoleFormType::class, $role);
24 | $formData = [
25 | 'role' => 'Content Admin',
26 | 'permissions' => ['view content', 'delete content'],
27 | ];
28 | $form->submit($formData);
29 |
30 | $this->assertTrue($form->isSynchronized());
31 | $this->assertSame($role, $form->getData());
32 | $this->assertSame('Content Admin', $role->getRole());
33 | $this->assertSame($formData['permissions'], $role->getPermissions());
34 | }
35 |
36 | /**
37 | * @return array
38 | */
39 | protected function getTypes()
40 | {
41 | return array_merge(parent::getTypes(), array(
42 | new RoleFormType('Eloyekunle\PermissionsBundle\Tests\TestRole'),
43 | ));
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Tests/Util/PermissionsHandlerTest.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\Tests\Util;
13 |
14 | use Eloyekunle\PermissionsBundle\Util\PermissionsHandler;
15 | use Eloyekunle\PermissionsBundle\Util\PermissionsHandlerInterface;
16 | use PHPUnit\Framework\TestCase;
17 |
18 | class PermissionsHandlerTest extends TestCase
19 | {
20 | /** @var PermissionsHandlerInterface */
21 | protected $permissionsHandler;
22 |
23 | public function setUp()
24 | {
25 | $this->permissionsHandler = new PermissionsHandler(__DIR__.'/../Fixtures');
26 | }
27 |
28 | public function testHandlerReadsDefinitions()
29 | {
30 | $permissions = $this->permissionsHandler->getPermissions();
31 | $this->assertArrayHasKey('edit users', $permissions);
32 | $this->assertSame('full_definition', $permissions['edit users']['provider']);
33 | $this->assertSame('Edit Users', $permissions['edit users']['title']);
34 |
35 | $this->assertArrayHasKey('delete users', $permissions);
36 | $this->assertSame('no_name', $permissions['delete users']['provider']);
37 | $this->assertSame('Delete Users', $permissions['delete users']['title']);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Tests/Form/Type/TypeTestCase.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\Tests\Form\Type;
13 |
14 | use Symfony\Component\Form\FormBuilder;
15 | use Symfony\Component\Form\Forms;
16 | use Symfony\Component\Form\Test\TypeTestCase as BaseTypeTestCase;
17 |
18 | /**
19 | * Class TypeTestCase.
20 | *
21 | * @author Sullivan Senechal
22 | *
23 | * Could be removed for using directly base class since PR: https://github.com/symfony/symfony/pull/14506
24 | */
25 | abstract class TypeTestCase extends BaseTypeTestCase
26 | {
27 | protected function setUp()
28 | {
29 | parent::setUp();
30 |
31 | $this->factory = Forms::createFormFactoryBuilder()
32 | ->addTypes($this->getTypes())
33 | ->addExtensions($this->getExtensions())
34 | ->addTypeExtensions($this->getTypeExtensions())
35 | ->getFormFactory();
36 |
37 | $this->builder = new FormBuilder(null, null, $this->dispatcher, $this->factory);
38 | }
39 |
40 | /**
41 | * @return array
42 | */
43 | protected function getTypeExtensions()
44 | {
45 | return array();
46 | }
47 |
48 | /**
49 | * @return array
50 | */
51 | protected function getTypes()
52 | {
53 | return array();
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Tests/BundleTest.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\Tests;
13 |
14 | use Eloyekunle\PermissionsBundle\DependencyInjection\Compiler\DoctrineMappingPass;
15 | use Eloyekunle\PermissionsBundle\DependencyInjection\Compiler\ValidationPass;
16 | use Eloyekunle\PermissionsBundle\EloyekunlePermissionsBundle;
17 | use PHPUnit\Framework\TestCase;
18 | use Symfony\Component\DependencyInjection\ContainerBuilder;
19 |
20 | class BundleTest extends TestCase
21 | {
22 | public function testBuildCompilerPasses()
23 | {
24 | $container = new ContainerBuilder();
25 | $bundle = new EloyekunlePermissionsBundle();
26 | $bundle->build($container);
27 |
28 | $config = $container->getCompilerPassConfig();
29 | $passes = $config->getBeforeOptimizationPasses();
30 |
31 | $foundMappingPass = false;
32 | $foundValidation = false;
33 |
34 | foreach ($passes as $pass) {
35 | if ($pass instanceof ValidationPass) {
36 | $foundValidation = true;
37 | } elseif ($pass instanceof DoctrineMappingPass) {
38 | $foundMappingPass = true;
39 | }
40 | }
41 |
42 | $this->assertTrue($foundMappingPass, 'DoctrineMappingPass was not found');
43 | $this->assertTrue($foundValidation, 'ValidationPass was not found');
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "eloyekunle/permissions-bundle",
3 | "description": "A Simple Permission Management Bundle for Symfony",
4 | "type": "symfony-bundle",
5 | "keywords": ["User management"],
6 | "require": {
7 | "php": "^5.5.9 || ^7.0",
8 | "doctrine/doctrine-bundle": "^1.9",
9 | "doctrine/orm": "^2.5 || ^2.6",
10 | "symfony/framework-bundle": "^2.7 || ^3.0 || ^4.0",
11 | "symfony/form": "^2.7 || ^3.0 || ^4.0",
12 | "symfony/yaml": "^2.7 || ^3.0 || ^4.0",
13 | "symfony/validator": "^2.8 || ^3.0 || ^4.0",
14 | "symfony/security-bundle": "^2.8 || ^3.0 || ^4.0",
15 | "symfony/twig-bundle": "^2.8 || ^3.0 || ^4.0",
16 | "symfony/templating": "^2.8 || ^3.0 || ^4.0",
17 | "twig/twig": "^1.28 || ^2.0",
18 | "paragonie/random_compat": "^1 || ^2"
19 | },
20 | "require-dev": {
21 | "friendsofphp/php-cs-fixer": "^2.2",
22 | "symfony/phpunit-bridge": "^2.8 || ^3.0 || ^4.0"
23 | },
24 | "license": "MIT",
25 | "authors": [
26 | {
27 | "name": "Elijah Oyekunle",
28 | "email": "eloyekunle@gmail.com"
29 | }
30 | ],
31 | "autoload": {
32 | "psr-4": {
33 | "Eloyekunle\\PermissionsBundle\\": ""
34 | },
35 | "exclude-from-classmap": [
36 | "/Tests"
37 | ]
38 | },
39 | "autoload-dev": {
40 | "psr-4": {
41 | "Eloyekunle\\PermissionsBundle\\Tests\\": "/Tests"
42 | }
43 | },
44 | "extra": {
45 | "branch-alias": {
46 | "dev-master": "master"
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Form/Type/RoleFormType.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\Form\Type;
13 |
14 | use Symfony\Component\Form\AbstractType;
15 | use Symfony\Component\Form\Extension\Core\Type\CollectionType;
16 | use Symfony\Component\Form\Extension\Core\Type\TextType;
17 | use Symfony\Component\Form\FormBuilderInterface;
18 | use Symfony\Component\OptionsResolver\OptionsResolver;
19 |
20 | class RoleFormType extends AbstractType
21 | {
22 | /** @var string */
23 | private $class;
24 |
25 | public function __construct($class)
26 | {
27 | $this->class = $class;
28 | }
29 |
30 | /**
31 | * {@inheritdoc}
32 | */
33 | public function buildForm(FormBuilderInterface $builder, array $options)
34 | {
35 | $builder
36 | ->add('role', TextType::class)
37 | ->add(
38 | 'permissions',
39 | CollectionType::class,
40 | [
41 | 'entry_type' => TextType::class,
42 | 'allow_add' => true,
43 | ]
44 | );
45 | }
46 |
47 | /**
48 | * {@inheritdoc}
49 | */
50 | public function configureOptions(OptionsResolver $resolver)
51 | {
52 | $resolver->setDefaults(
53 | [
54 | 'data_class' => $this->class,
55 | 'csrf_protection' => false,
56 | ]
57 | );
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Model/RoleManagerInterface.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\Model;
13 |
14 | interface RoleManagerInterface
15 | {
16 | public function findRoles();
17 |
18 | /**
19 | * Creates and empty role.
20 | *
21 | * @return RoleInterface
22 | */
23 | public function createRole();
24 |
25 | /**
26 | * Returns the role's fully qualified class name.
27 | *
28 | * @return string
29 | */
30 | public function getClass();
31 |
32 | /**
33 | * Updates a role.
34 | *
35 | * @param \Eloyekunle\PermissionsBundle\Model\RoleInterface $role
36 | * @param bool $andFlush
37 | *
38 | * @return mixed
39 | */
40 | public function updateRole(RoleInterface $role, $andFlush = true);
41 |
42 | /**
43 | * Finds one role by criteria.
44 | *
45 | * @param array $criteria
46 | *
47 | * @return RoleInterface|null
48 | */
49 | public function findRoleBy(array $criteria);
50 |
51 | /**
52 | * Find one role by ID.
53 | *
54 | * @param int $id
55 | *
56 | * @return RoleInterface|null
57 | */
58 | public function findRole($id);
59 |
60 | /**
61 | * Deletes a role.
62 | *
63 | * @param \Eloyekunle\PermissionsBundle\Model\RoleInterface $role
64 | *
65 | * @return void
66 | */
67 | public function deleteRole(RoleInterface $role);
68 | }
69 |
--------------------------------------------------------------------------------
/EloyekunlePermissionsBundle.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle;
13 |
14 | use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\DoctrineOrmMappingsPass;
15 | use Eloyekunle\PermissionsBundle\DependencyInjection\Compiler\ValidationPass;
16 | use Symfony\Component\DependencyInjection\ContainerBuilder;
17 | use Symfony\Component\HttpKernel\Bundle\Bundle;
18 |
19 | class EloyekunlePermissionsBundle extends Bundle
20 | {
21 | /**
22 | * @param ContainerBuilder $container
23 | */
24 | public function build(ContainerBuilder $container)
25 | {
26 | parent::build($container);
27 | $container->addCompilerPass(new ValidationPass());
28 | $this->addRegisterMappingsPass($container);
29 | }
30 |
31 | /**
32 | * @param ContainerBuilder $container
33 | */
34 | private function addRegisterMappingsPass(ContainerBuilder $container)
35 | {
36 | $mappings = [
37 | realpath(
38 | __DIR__.'/Resources/config/doctrine-mapping'
39 | ) => 'Eloyekunle\PermissionsBundle\Model',
40 | ];
41 | if (class_exists(
42 | 'Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\DoctrineOrmMappingsPass'
43 | )) {
44 | $container->addCompilerPass(
45 | DoctrineOrmMappingsPass::createXmlMappingDriver(
46 | $mappings,
47 | ['eloyekunle_permissions.model_manager_name'],
48 | 'eloyekunle_permissions.backend_type_orm'
49 | )
50 | );
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Util/PermissionsHandler.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\Util;
13 |
14 | use Symfony\Component\Finder\Finder;
15 | use Symfony\Component\Yaml\Parser;
16 |
17 | class PermissionsHandler implements PermissionsHandlerInterface
18 | {
19 | /** @var string */
20 | protected $definitionsPath;
21 |
22 | /** @var array */
23 | protected $modules;
24 |
25 | /** @var Finder */
26 | protected $finder;
27 |
28 | /** @var Parser */
29 | protected $parser;
30 |
31 | /** @var array */
32 | protected $permissions;
33 |
34 | public function __construct($definitionsPath)
35 | {
36 | $this->definitionsPath = $definitionsPath;
37 | $this->finder = Finder::create()->files()->name('*.yaml')->in($this->definitionsPath);
38 | $this->parser = new Parser();
39 |
40 | $this->buildPermissionsYaml();
41 | }
42 |
43 | /**
44 | * {@inheritdoc}
45 | */
46 | public function getPermissions()
47 | {
48 | return $this->permissions;
49 | }
50 |
51 | /**
52 | * Builds the list of currently active modules with their permissions.
53 | */
54 | protected function buildPermissionsYaml()
55 | {
56 | $permissions = [];
57 |
58 | foreach ($this->finder as $definitionsFile) {
59 | $module = $this->parser->parseFile($definitionsFile->getPathname());
60 | $moduleKey = $definitionsFile->getBasename('.yaml');
61 |
62 | foreach ($module['permissions'] as $key => $permission) {
63 | $permissions[$key] = $permission + ['provider' => $moduleKey];
64 | }
65 | }
66 |
67 | $this->permissions = $permissions;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/DependencyInjection/Configuration.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\DependencyInjection;
13 |
14 | use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
15 | use Symfony\Component\Config\Definition\Builder\TreeBuilder;
16 | use Symfony\Component\Config\Definition\ConfigurationInterface;
17 |
18 | class Configuration implements ConfigurationInterface
19 | {
20 | /**
21 | * {@inheritdoc}
22 | */
23 | public function getConfigTreeBuilder()
24 | {
25 | $treeBuilder = new TreeBuilder('eloyekunle_permissions');
26 | $rootNode = method_exists(TreeBuilder::class, 'getRootNode') ? $treeBuilder->getRootNode() : $treeBuilder->root('eloyekunle_permissions');
27 |
28 | $supportedDrivers = ['orm'];
29 |
30 | $rootNode
31 | ->addDefaultsIfNotSet()
32 | ->children()
33 | ->scalarNode('db_driver')
34 | ->validate()
35 | ->ifNotInArray($supportedDrivers)
36 | ->thenInvalid('The driver %s is not supported. Please choose one of '.json_encode($supportedDrivers))
37 | ->end()
38 | ->cannotBeOverwritten()
39 | ->defaultValue('orm')
40 | ->end()
41 | ->scalarNode('role_class')->isRequired()->cannotBeEmpty()->end()
42 | ->scalarNode('model_manager_name')->defaultNull()->end()
43 | ->end();
44 |
45 | $this->addModuleSection($rootNode);
46 |
47 | return $treeBuilder;
48 | }
49 |
50 | private function addModuleSection(ArrayNodeDefinition $node)
51 | {
52 | $node
53 | ->children()
54 | ->arrayNode('module')
55 | ->addDefaultsIfNotSet()
56 | ->canBeUnset()
57 | ->children()
58 | ->scalarNode('definitions_path')->cannotBeEmpty()->isRequired()->end()
59 | ->end();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Security/PermissionsVoter.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\Security;
13 |
14 | use Eloyekunle\PermissionsBundle\Model\RoleInterface;
15 | use Eloyekunle\PermissionsBundle\Model\UserInterface;
16 | use Eloyekunle\PermissionsBundle\Util\PermissionsHandlerInterface;
17 | use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
18 | use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
19 | use Symfony\Component\Security\Core\Authorization\Voter\Voter;
20 |
21 | class PermissionsVoter extends Voter
22 | {
23 | /**
24 | * @var AccessDecisionManagerInterface
25 | */
26 | protected $decisionManager;
27 |
28 | /**
29 | * @var PermissionsHandlerInterface
30 | */
31 | protected $moduleHandler;
32 |
33 | public function __construct(AccessDecisionManagerInterface $accessDecisionManager, PermissionsHandlerInterface $permissionsHandler)
34 | {
35 | $this->decisionManager = $accessDecisionManager;
36 | $this->moduleHandler = $permissionsHandler;
37 | }
38 |
39 | /**
40 | * {@inheritdoc}
41 | */
42 | protected function supports($attribute, $subject)
43 | {
44 | // Check if attribute is declared as permission.
45 | if (!in_array($attribute, array_keys($this->moduleHandler->getPermissions()))) {
46 | return false;
47 | }
48 |
49 | return true;
50 | }
51 |
52 | /**
53 | * {@inheritdoc}
54 | */
55 | protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
56 | {
57 | // Super Admin Pass
58 | if ($this->decisionManager->decide($token, [RoleInterface::ROLE_SUPER_ADMIN])) {
59 | return true;
60 | }
61 |
62 | // Deny access if user is not logged in.
63 | $user = $token->getUser();
64 | if (!$user instanceof UserInterface) {
65 | return false;
66 | }
67 |
68 | return $user->hasPermission($attribute);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/Doctrine/RoleManager.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\Doctrine;
13 |
14 | use Doctrine\Common\Persistence\ObjectManager;
15 | use Doctrine\Common\Persistence\ObjectRepository;
16 | use Eloyekunle\PermissionsBundle\Model\RoleInterface;
17 | use Eloyekunle\PermissionsBundle\Model\RoleManager as BaseRoleManager;
18 |
19 | class RoleManager extends BaseRoleManager
20 | {
21 | /** @var ObjectManager */
22 | protected $objectManager;
23 |
24 | /** @var string */
25 | protected $class;
26 |
27 | public function __construct(ObjectManager $om, $class)
28 | {
29 | $this->objectManager = $om;
30 | $this->class = $class;
31 | }
32 |
33 | /**
34 | * {@inheritdoc}
35 | */
36 | public function getClass()
37 | {
38 | return $this->class;
39 | }
40 |
41 | /**
42 | * {@inheritdoc}
43 | */
44 | public function findRoles()
45 | {
46 | return $this->getRepository()->findAll();
47 | }
48 |
49 | /**
50 | * {@inheritdoc}
51 | */
52 | public function findRoleBy(array $criteria)
53 | {
54 | return $this->getRepository()->findOneBy($criteria);
55 | }
56 |
57 | /**
58 | * {@inheritdoc}
59 | */
60 | public function findRole($id)
61 | {
62 | return $this->getRepository()->find($id);
63 | }
64 |
65 | /**
66 | * {@inheritdoc}
67 | */
68 | public function updateRole(RoleInterface $role, $andFlush = true)
69 | {
70 | $this->objectManager->persist($role);
71 |
72 | if ($andFlush) {
73 | $this->objectManager->flush();
74 | }
75 | }
76 |
77 | /**
78 | * {@inheritdoc}
79 | */
80 | public function deleteRole(RoleInterface $role)
81 | {
82 | $this->objectManager->remove($role);
83 | $this->objectManager->flush();
84 | }
85 |
86 | /**
87 | * @return ObjectRepository
88 | */
89 | protected function getRepository()
90 | {
91 | return $this->objectManager->getRepository($this->getClass());
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/Model/RoleInterface.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\Model;
13 |
14 | interface RoleInterface
15 | {
16 | /**
17 | * Role ID for anonymous users; should match what's in the "role" table.
18 | */
19 | const ROLE_DEFAULT = 'ROLE_USER';
20 |
21 | /**
22 | * Role ID for super admin users; should match what's in the "role" table.
23 | */
24 | const ROLE_SUPER_ADMIN = 'ROLE_SUPER_ADMIN';
25 |
26 | /**
27 | * @return int
28 | */
29 | public function getId();
30 |
31 | /**
32 | * @return null|string
33 | */
34 | public function getRole();
35 |
36 | /**
37 | * @param null|string $name
38 | */
39 | public function setRole($name);
40 |
41 | /**
42 | * Returns a list of permissions assigned to the role.
43 | *
44 | * @return array
45 | * The permissions assigned to the role
46 | */
47 | public function getPermissions();
48 |
49 | /**
50 | * Sets the permissions of a role.
51 | * This overwrites all previous roles.
52 | *
53 | * @param array $permissions
54 | */
55 | public function setPermissions(array $permissions);
56 |
57 | /**
58 | * Checks if the role has a permission.
59 | *
60 | * @param string $permission
61 | * The permission to check for
62 | *
63 | * @return bool
64 | * TRUE if the role has the permission, FALSE if not
65 | */
66 | public function hasPermission($permission);
67 |
68 | /**
69 | * Grant permissions to the role.
70 | *
71 | * @param string $permission
72 | * The permission to grant
73 | *
74 | * @return $this
75 | */
76 | public function grantPermission($permission);
77 |
78 | /**
79 | * Revokes a permissions from the user role.
80 | *
81 | * @param string $permission
82 | * The permission to revoke
83 | *
84 | * @return $this
85 | */
86 | public function revokePermission($permission);
87 |
88 | /**
89 | * Indicates that a role has all available permissions.
90 | *
91 | * @return bool
92 | * TRUE if the role has all permissions
93 | */
94 | public function isSuperAdmin();
95 | }
96 |
--------------------------------------------------------------------------------
/Model/UserInterface.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\Model;
13 |
14 | interface UserInterface
15 | {
16 | /**
17 | * Returns the roles granted to the user.
18 | *
19 | *
20 | * public function getRoles()
21 | * {
22 | * return array('ROLE_USER');
23 | * }
24 | *
25 | *
26 | * This returns an array of the role names because Symfony expects a User::getRoles() method that returns a string
27 | * array of user roles. User::getUserRoles() currently returns RoleInterfaces[].
28 | *
29 | * @return string[] The user roles
30 | */
31 | public function getRoles();
32 |
33 | /**
34 | * Tells if the the given user has the super admin role.
35 | *
36 | * @return bool
37 | */
38 | public function isSuperAdmin();
39 |
40 | /**
41 | * Checks whether a user has a certain permission.
42 | *
43 | * @param string $permission
44 | * The permission string to check
45 | *
46 | * @return bool
47 | * TRUE if the user has the permission, FALSE otherwise
48 | */
49 | public function hasPermission($permission);
50 |
51 | /**
52 | * Whether a user has a certain role.
53 | *
54 | * @param string $role
55 | * The role ID to check
56 | *
57 | * @return bool
58 | * Returns TRUE if the user has the role, otherwise FALSE
59 | */
60 | public function hasRole(RoleInterface $role);
61 |
62 | /**
63 | * Sets the roles of the user.
64 | *
65 | * This overwrites any previous roles.
66 | *
67 | * @param \Eloyekunle\PermissionsBundle\Model\RoleInterface[] $roles
68 | *
69 | * @return static
70 | */
71 | public function setUserRoles(array $roles);
72 |
73 | /**
74 | * @return \Eloyekunle\PermissionsBundle\Model\RoleInterface[]|null
75 | */
76 | public function getUserRoles();
77 |
78 | /**
79 | * Add a role to a user.
80 | *
81 | * @param \Eloyekunle\PermissionsBundle\Model\RoleInterface $role
82 | * The role to add
83 | */
84 | public function addRole(RoleInterface $role);
85 |
86 | /**
87 | * Remove a role from a user.
88 | *
89 | * @param \Eloyekunle\PermissionsBundle\Model\RoleInterface $role
90 | * The role to remove
91 | */
92 | public function removeRole(RoleInterface $role);
93 | }
94 |
--------------------------------------------------------------------------------
/Tests/Functional/DependencyInjectionTest.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\Tests\Functional;
13 |
14 | use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
15 | use Eloyekunle\PermissionsBundle\Doctrine\RoleManager;
16 | use Eloyekunle\PermissionsBundle\EloyekunlePermissionsBundle;
17 | use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
18 | use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
19 | use Symfony\Component\Config\Loader\LoaderInterface;
20 | use Symfony\Component\DependencyInjection\ContainerBuilder;
21 | use Symfony\Component\HttpKernel\Kernel;
22 |
23 | class DependencyInjectionTest extends KernelTestCase
24 | {
25 | public function testBundleLoaded()
26 | {
27 | self::bootKernel();
28 | $container = self::$kernel->getContainer();
29 |
30 | $this->assertInstanceOf(RoleManager::class, $container->get('eloyekunle_permissions.role_manager'));
31 | }
32 |
33 | protected static function getKernelClass()
34 | {
35 | return TestKernel::class;
36 | }
37 | }
38 |
39 | class TestKernel extends Kernel
40 | {
41 | public function registerBundles()
42 | {
43 | return [
44 | new FrameworkBundle(),
45 | new DoctrineBundle(),
46 | new EloyekunlePermissionsBundle(),
47 | ];
48 | }
49 |
50 | public function registerContainerConfiguration(LoaderInterface $loader)
51 | {
52 | $loader->load(function (ContainerBuilder $container) {
53 | $container->loadFromExtension('framework', [
54 | 'secret' => 'test',
55 | 'router' => array(
56 | 'resource' => '%kernel.root_dir%/config/routing.yml',
57 | ),
58 | ]);
59 | $container->loadFromExtension('eloyekunle_permissions', [
60 | 'db_driver' => 'orm',
61 | 'role_class' => 'Eloyekunle\PermissionsBundle\Tests\TestRole',
62 | ]);
63 | $container->loadFromExtension('doctrine', [
64 | 'dbal' => [
65 | 'driver' => 'pdo_sqlite',
66 | 'path' => $this->getCacheDir().'/testing.db',
67 | ],
68 | 'orm' => [],
69 | ]);
70 | });
71 | }
72 |
73 | public function getCacheDir()
74 | {
75 | return sys_get_temp_dir().'/'.str_replace('\\', '-', get_class($this)).'/cache/'.$this->environment;
76 | }
77 |
78 | public function getLogDir()
79 | {
80 | return sys_get_temp_dir().'/'.str_replace('\\', '-', get_class($this)).'/log/'.$this->environment;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/Tests/Model/RoleTest.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\Tests\Model;
13 |
14 | use Eloyekunle\PermissionsBundle\Model\RoleInterface;
15 | use PHPUnit\Framework\TestCase;
16 |
17 | class RoleTest extends TestCase
18 | {
19 | public function testName()
20 | {
21 | $role = $this->getRole();
22 | $this->assertNull($role->getRole());
23 |
24 | $role->setRole('System Administrator');
25 | $this->assertSame('System Administrator', $role->getRole());
26 | }
27 |
28 | public function testGrantPermission()
29 | {
30 | $role = $this->getRole();
31 | $this->assertFalse($role->hasPermission('Administer Systems'));
32 |
33 | $role->grantPermission('Administer Systems');
34 | $this->assertTrue($role->hasPermission('Administer Systems'));
35 | }
36 |
37 | public function testRevokePermission()
38 | {
39 | $role = $this->getRole();
40 | $role->grantPermission('Administer Systems');
41 | $this->assertTrue($role->hasPermission('Administer Systems'));
42 |
43 | $role->revokePermission('Administer Systems');
44 | $this->assertFalse($role->hasPermission('Administer Systems'));
45 | }
46 |
47 | public function testSuperAdminPermissions()
48 | {
49 | $role = $this->getRole();
50 | $this->assertFalse($role->hasPermission('Administer Systems'));
51 |
52 | $role->setRole(RoleInterface::ROLE_SUPER_ADMIN);
53 | $this->assertTrue($role->hasPermission('Administer Systems'));
54 | $role->grantPermission('Play with Cats');
55 | $this->assertSame([], $role->getPermissions());
56 | $role->revokePermission('Play with Cats');
57 | $this->assertSame([], $role->getPermissions());
58 |
59 | $role->setRole('Not Admin');
60 | $this->assertFalse($role->hasPermission('Administer Systems'));
61 | }
62 |
63 | public function testSetPermissions()
64 | {
65 | $role = $this->getRole();
66 | $this->assertFalse($role->hasPermission('Administer Systems'));
67 | $this->assertFalse($role->hasPermission('View Reports'));
68 |
69 | $permissions = ['Administer Systems', 'View Reports', ''];
70 | $role->setPermissions($permissions);
71 | $this->assertTrue($role->hasPermission('Administer Systems'));
72 | $this->assertTrue($role->hasPermission('View Reports'));
73 | $this->assertSame(2, count($role->getPermissions()));
74 | }
75 |
76 | /**
77 | * @return RoleInterface
78 | *
79 | * @throws \ReflectionException
80 | */
81 | protected function getRole()
82 | {
83 | return $this->getMockForAbstractClass('Eloyekunle\PermissionsBundle\Model\Role');
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/Model/User.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\Model;
13 |
14 | use Doctrine\Common\Collections\ArrayCollection;
15 | use Doctrine\Common\Collections\Collection;
16 |
17 | /**
18 | * Storage agnostic user object.
19 | */
20 | abstract class User implements UserInterface
21 | {
22 | /**
23 | * @var RoleInterface[]|Collection
24 | */
25 | protected $userRoles;
26 |
27 | /**
28 | * User constructor.
29 | */
30 | public function __construct()
31 | {
32 | $this->userRoles = new ArrayCollection();
33 | }
34 |
35 | /**
36 | * {@inheritdoc}
37 | */
38 | public function getRoles()
39 | {
40 | $roleNames = [];
41 | $roles = $this->getUserRoles();
42 |
43 | foreach ($roles as $role) {
44 | $roleNames[] = $role->getRole();
45 | }
46 |
47 | return array_unique($roleNames);
48 | }
49 |
50 | /**
51 | * {@inheritdoc}
52 | */
53 | public function hasRole(RoleInterface $role)
54 | {
55 | return $this->userRoles->contains($role);
56 | }
57 |
58 | /**
59 | * {@inheritdoc}
60 | */
61 | public function isSuperAdmin()
62 | {
63 | $isSuperAdmin = false;
64 | foreach ($this->getUserRoles() as $role) {
65 | if ($role->isSuperAdmin()) {
66 | return true;
67 | }
68 | }
69 |
70 | return $isSuperAdmin;
71 | }
72 |
73 | /**
74 | * {@inheritdoc}
75 | */
76 | public function removeRole(RoleInterface $role)
77 | {
78 | if (!$this->userRoles->contains($role)) {
79 | return;
80 | }
81 |
82 | $this->userRoles->removeElement($role);
83 | }
84 |
85 | /**
86 | * {@inheritdoc}
87 | */
88 | public function addRole(RoleInterface $role)
89 | {
90 | if ($this->userRoles->contains($role)) {
91 | return;
92 | }
93 |
94 | $this->userRoles->add($role);
95 | }
96 |
97 | /**
98 | * {@inheritdoc}
99 | */
100 | public function setUserRoles(array $userRoles)
101 | {
102 | foreach ($userRoles as $role) {
103 | $this->addRole($role);
104 | }
105 | }
106 |
107 | /**
108 | * {@inheritdoc}
109 | */
110 | public function hasPermission($permission)
111 | {
112 | $hasPermission = false;
113 |
114 | foreach ($this->getUserRoles() as $role) {
115 | if ($role->isSuperAdmin() || $role->hasPermission($permission)) {
116 | return true;
117 | }
118 | }
119 |
120 | return $hasPermission;
121 | }
122 |
123 | /**
124 | * @return RoleInterface[]
125 | */
126 | public function getUserRoles()
127 | {
128 | return $this->userRoles;
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/Model/Role.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\Model;
13 |
14 | abstract class Role implements RoleInterface
15 | {
16 | /**
17 | * The machine name of this role.
18 | *
19 | * @var mixed
20 | */
21 | protected $id;
22 |
23 | /**
24 | * The human-readable name of this role.
25 | *
26 | * @var string
27 | */
28 | protected $role;
29 |
30 | /**
31 | * The permissions belonging to this role.
32 | *
33 | * @var array
34 | */
35 | protected $permissions;
36 |
37 | public function __construct($role = null)
38 | {
39 | $this->role = $role;
40 | $this->permissions = [];
41 | }
42 |
43 | /**
44 | * {@inheritdoc}
45 | */
46 | public function getId()
47 | {
48 | return $this->id;
49 | }
50 |
51 | public function getRole()
52 | {
53 | return $this->role;
54 | }
55 |
56 | /**
57 | * {@inheritdoc}
58 | */
59 | public function setRole($role)
60 | {
61 | $this->role = $role;
62 |
63 | return $this;
64 | }
65 |
66 | /**
67 | * {@inheritdoc}
68 | */
69 | public function getPermissions()
70 | {
71 | if ($this->isSuperAdmin()) {
72 | return [];
73 | }
74 |
75 | return $this->permissions;
76 | }
77 |
78 | /**
79 | * {@inheritdoc}
80 | */
81 | public function setPermissions(array $permissions)
82 | {
83 | $this->permissions = [];
84 |
85 | foreach ($permissions as $permission) {
86 | if (!$permission) {
87 | break;
88 | }
89 | $this->grantPermission($permission);
90 | }
91 |
92 | return $this;
93 | }
94 |
95 | /**
96 | * {@inheritdoc}
97 | */
98 | public function hasPermission($permission)
99 | {
100 | if ($this->isSuperAdmin()) {
101 | return true;
102 | }
103 |
104 | return in_array($permission, $this->getPermissions(), true);
105 | }
106 |
107 | /**
108 | * {@inheritdoc}
109 | */
110 | public function grantPermission($permission)
111 | {
112 | if ($this->isSuperAdmin()) {
113 | return $this;
114 | }
115 | if (!$this->hasPermission($permission)) {
116 | $this->permissions[] = $permission;
117 | }
118 |
119 | return $this;
120 | }
121 |
122 | /**
123 | * {@inheritdoc}
124 | */
125 | public function revokePermission($permission)
126 | {
127 | if ($this->isSuperAdmin()) {
128 | return $this;
129 | }
130 | $this->permissions = array_diff($this->permissions, [$permission]);
131 |
132 | return $this;
133 | }
134 |
135 | /**
136 | * {@inheritdoc}
137 | */
138 | public function isSuperAdmin()
139 | {
140 | return $this->getRole() === static::ROLE_SUPER_ADMIN;
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/Tests/Model/UserTest.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\Tests\Model;
13 |
14 | use Eloyekunle\PermissionsBundle\Model\RoleInterface;
15 | use Eloyekunle\PermissionsBundle\Model\UserInterface;
16 | use Eloyekunle\PermissionsBundle\Tests\TestRole;
17 | use PHPUnit\Framework\TestCase;
18 |
19 | class UserTest extends TestCase
20 | {
21 | public function testTrueHasRole()
22 | {
23 | $user = $this->getUser();
24 | $newrole = $this->createMockRole('ROLE_X');
25 |
26 | $user->addRole($newrole);
27 | $this->assertTrue($user->hasRole($newrole));
28 |
29 | // Role already exists (added above), so addRole should return without doing anything
30 | $user->addRole($newrole);
31 | $this->assertTrue($user->hasRole($newrole));
32 |
33 | $user->removeRole($newrole);
34 | $this->assertFalse($user->hasRole($newrole));
35 |
36 | // Role already removed (removed above), so removeRole should return without doing anything
37 | $user->removeRole($newrole);
38 | $this->assertFalse($user->hasRole($newrole));
39 | }
40 |
41 | public function testFalseHasRole()
42 | {
43 | $user = $this->getUser();
44 | $newrole = $this->createMockRole('ROLE_X');
45 |
46 | $this->assertFalse($user->hasRole($newrole));
47 | $user->addRole($newrole);
48 | $this->assertTrue($user->hasRole($newrole));
49 | }
50 |
51 | public function testIsSuperAdmin()
52 | {
53 | $user = $this->getUser();
54 | $permission = 'do stuff';
55 |
56 | $this->assertFalse($user->isSuperAdmin());
57 | $this->assertFalse($user->hasPermission($permission));
58 |
59 | $superAdminRole = $this->createMockRole(RoleInterface::ROLE_SUPER_ADMIN);
60 | $user->addRole($superAdminRole);
61 |
62 | $this->assertTrue($user->isSuperAdmin());
63 | $this->assertTrue($user->hasPermission($permission));
64 | }
65 |
66 | public function testSetUserRoles()
67 | {
68 | $roleNames = ['Content Admin', 'Service Admin'];
69 | $roles = [];
70 | foreach ($roleNames as $roleName) {
71 | $roles[] = $this->createMockRole($roleName);
72 | }
73 | $user1 = $this->getUser();
74 | $user2 = $this->getUser();
75 | $user2->setUserRoles($roles);
76 |
77 | foreach ($roles as $role) {
78 | $this->assertFalse($user1->hasRole($role));
79 | $this->assertTrue($user2->hasRole($role));
80 | }
81 |
82 | $this->assertSame($roleNames, $user2->getRoles());
83 | }
84 |
85 | /**
86 | * @param $roleName
87 | *
88 | * @return RoleInterface
89 | */
90 | protected function createMockRole($roleName)
91 | {
92 | return new TestRole($roleName);
93 | }
94 |
95 | /**
96 | * @return UserInterface
97 | *
98 | * @throws \ReflectionException
99 | */
100 | protected function getUser()
101 | {
102 | return $this->getMockForAbstractClass('Eloyekunle\PermissionsBundle\Model\User');
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/Tests/Doctrine/RoleManagerTest.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\Tests\Doctrine;
13 |
14 | use Eloyekunle\PermissionsBundle\Doctrine\RoleManager;
15 | use Eloyekunle\PermissionsBundle\Model\RoleManagerInterface;
16 | use PHPUnit\Framework\TestCase;
17 |
18 | class RoleManagerTest extends TestCase
19 | {
20 | const ROLE_CLASS = 'Eloyekunle\PermissionsBundle\Tests\TestRole';
21 |
22 | /** @var \PHPUnit_Framework_MockObject_MockObject */
23 | protected $repository;
24 |
25 | /** @var \PHPUnit_Framework_MockObject_MockObject */
26 | protected $om;
27 |
28 | /** @var RoleManagerInterface */
29 | protected $roleManager;
30 |
31 | public function setUp()
32 | {
33 | if (!interface_exists('Doctrine\Common\Persistence\ObjectManager')) {
34 | $this->markTestSkipped('Doctrine Common has to be installed for this test to run.');
35 | }
36 |
37 | $class = $this->getMockBuilder('Doctrine\Common\Persistence\Mapping\ClassMetadata')->getMock();
38 | $this->om = $this->getMockBuilder('Doctrine\Common\Persistence\ObjectManager')->getMock();
39 | $this->repository = $this->getMockBuilder('Doctrine\Common\Persistence\ObjectRepository')->getMock();
40 |
41 | $this->om->expects($this->any())
42 | ->method('getRepository')
43 | ->with($this->equalTo(static::ROLE_CLASS))
44 | ->will($this->returnValue($this->repository));
45 | $this->om->expects($this->any())
46 | ->method('getClassMetadata')
47 | ->with($this->equalTo(static::ROLE_CLASS))
48 | ->will($this->returnValue($class));
49 | $class->expects($this->any())
50 | ->method('getName')
51 | ->will($this->returnValue(static::ROLE_CLASS));
52 |
53 | $this->roleManager = new RoleManager($this->om, static::ROLE_CLASS);
54 | }
55 |
56 | public function testGetClass()
57 | {
58 | $this->assertSame(static::ROLE_CLASS, $this->roleManager->getClass());
59 | }
60 |
61 | public function testFindRoles()
62 | {
63 | $this->repository->expects($this->once())->method('findAll');
64 |
65 | $this->roleManager->findRoles();
66 | }
67 |
68 | public function testFindRoleBy()
69 | {
70 | $crit = ['name' => 'finestRole'];
71 | $this->repository->expects($this->once())->method('findOneBy')->with($crit);
72 |
73 | $this->roleManager->findRoleBy($crit);
74 | }
75 |
76 | public function testFindRole()
77 | {
78 | $id = 10;
79 | $this->repository->expects($this->once())->method('find')->with($id);
80 |
81 | $this->roleManager->findRole($id);
82 | }
83 |
84 | public function testUpdateRole()
85 | {
86 | $role = $this->getRole();
87 | $this->om->expects($this->once())->method('persist')->with($role);
88 | $this->om->expects($this->once())->method('flush');
89 |
90 | $this->roleManager->updateRole($role);
91 | }
92 |
93 | public function testDeleteRole()
94 | {
95 | $role = $this->getRole();
96 | $this->om->expects($this->once())->method('remove')->with($role);
97 | $this->om->expects($this->once())->method('flush');
98 |
99 | $this->roleManager->deleteRole($role);
100 | }
101 |
102 | protected function getRole()
103 | {
104 | return $this->roleManager->createRole();
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/Tests/DependencyInjection/EloyekunlePermissionsExtensionTest.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\Tests\DependencyInjection;
13 |
14 | use Eloyekunle\PermissionsBundle\DependencyInjection\EloyekunlePermissionsExtension;
15 | use PHPUnit\Framework\TestCase;
16 | use Symfony\Component\DependencyInjection\ContainerBuilder;
17 | use Symfony\Component\Yaml\Parser;
18 |
19 | /**
20 | * EloyekunlePermissionsExtension Test.
21 | *
22 | * @author Elijah Oyekunle
23 | */
24 | class EloyekunlePermissionsExtensionTest extends TestCase
25 | {
26 | /** @var ContainerBuilder */
27 | private $container;
28 |
29 | /** @var EloyekunlePermissionsExtension */
30 | private $extension;
31 |
32 | /**
33 | * {@inheritdoc}
34 | */
35 | public function setUp()
36 | {
37 | $this->container = new ContainerBuilder();
38 | $this->extension = new EloyekunlePermissionsExtension();
39 | }
40 |
41 | /**
42 | * {@inheritdoc}
43 | */
44 | public function tearDown()
45 | {
46 | unset($this->container, $this->extension);
47 | }
48 |
49 | /**
50 | * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
51 | */
52 | public function testLoadThrowsExceptionUnlessDatabaseDriverIsValid()
53 | {
54 | $config = $this->getEmptyConfig();
55 | $config['db_driver'] = 'bar';
56 | $this->extension->load([$config], $this->container);
57 | }
58 |
59 | public function testLoadManagerClassWithDefaults()
60 | {
61 | $this->createEmptyConfig();
62 |
63 | $this->assertParameter('orm', 'eloyekunle_permissions.storage');
64 | $this->assertAlias('eloyekunle_permissions.role_manager.default', 'eloyekunle_permissions.role_manager');
65 | }
66 |
67 | public function testModelClassWithDefaults()
68 | {
69 | $this->createEmptyConfig();
70 |
71 | $this->assertParameter('Acme\MyBundle\Document\Role', 'eloyekunle_permissions.model.role.class');
72 | }
73 |
74 | protected function createEmptyConfig()
75 | {
76 | $config = $this->getEmptyConfig();
77 | $this->extension->load(array($config), $this->container);
78 | $this->assertTrue($this->container instanceof ContainerBuilder);
79 | }
80 |
81 | protected function createFullConfig()
82 | {
83 | $config = $this->getFullConfig();
84 | $this->extension->load(array($config), $this->container);
85 | $this->assertTrue($this->container instanceof ContainerBuilder);
86 | }
87 |
88 | /**
89 | * getEmptyConfig.
90 | *
91 | * @return array
92 | */
93 | protected function getEmptyConfig()
94 | {
95 | $yaml = <<parse($yaml);
102 | }
103 |
104 | /**
105 | * getFullConfig.
106 | *
107 | * @return array
108 | */
109 | protected function getFullConfig()
110 | {
111 | $yaml = <<parse($yaml);
120 | }
121 |
122 | /**
123 | * @param string $value
124 | * @param string $key
125 | */
126 | private function assertAlias($value, $key)
127 | {
128 | $this->assertSame($value, (string) $this->container->getAlias($key), sprintf('%s alias is correct', $key));
129 | }
130 |
131 | /**
132 | * @param mixed $value
133 | * @param string $key
134 | */
135 | private function assertParameter($value, $key)
136 | {
137 | $this->assertSame($value, $this->container->getParameter($key), sprintf('%s parameter is correct', $key));
138 | }
139 |
140 | /**
141 | * @param string $id
142 | */
143 | private function assertHasDefinition($id)
144 | {
145 | $this->assertTrue($this->container->hasDefinition($id) ?: $this->container->hasParameter($id));
146 | }
147 |
148 | /**
149 | * @param string $id
150 | */
151 | private function assertNotHasDefinition($id)
152 | {
153 | $this->assertTrue($this->container->hasDefinition($id) ?: $this->container->hasParameter($id));
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/DependencyInjection/EloyekunlePermissionsExtension.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\DependencyInjection;
13 |
14 | use Symfony\Component\Config\Definition\Processor;
15 | use Symfony\Component\Config\FileLocator;
16 | use Symfony\Component\DependencyInjection\Alias;
17 | use Symfony\Component\DependencyInjection\ContainerBuilder;
18 | use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
19 | use Symfony\Component\DependencyInjection\Reference;
20 | use Symfony\Component\HttpKernel\DependencyInjection\Extension;
21 |
22 | class EloyekunlePermissionsExtension extends Extension
23 | {
24 | /**
25 | * @var array
26 | */
27 | private static $doctrineDrivers = array(
28 | 'orm' => array(
29 | 'registry' => 'doctrine',
30 | 'tag' => 'doctrine.event_subscriber',
31 | ),
32 | );
33 |
34 | /**
35 | * {@inheritdoc}
36 | */
37 | public function load(array $configs, ContainerBuilder $container)
38 | {
39 | $processor = new Processor();
40 | $configuration = new Configuration();
41 |
42 | $config = $processor->processConfiguration($configuration, $configs);
43 |
44 | $loader = new XmlFileLoader(
45 | $container,
46 | new FileLocator(__DIR__.'/../Resources/config')
47 | );
48 |
49 | $loader->load('doctrine.xml');
50 | $container->setAlias(
51 | 'eloyekunle_permissions.doctrine_registry',
52 | new Alias(self::$doctrineDrivers[$config['db_driver']]['registry'], false)
53 | );
54 | $container->setParameter($this->getAlias().'.backend_type_'.$config['db_driver'], true);
55 |
56 | if (isset(self::$doctrineDrivers[$config['db_driver']])) {
57 | $definition = $container->getDefinition('eloyekunle_permissions.object_manager');
58 | $definition->setFactory([new Reference('eloyekunle_permissions.doctrine_registry'), 'getManager']);
59 | }
60 |
61 | $this->remapParametersNamespaces($config, $container, [
62 | '' => [
63 | 'db_driver' => 'eloyekunle_permissions.storage',
64 | 'role_class' => 'eloyekunle_permissions.model.role.class',
65 | 'model_manager_name' => 'eloyekunle_permissions.model_manager_name',
66 | ],
67 | ]
68 | );
69 |
70 | $this->loadRole($config, $container, $loader);
71 |
72 | if (!empty($config['module'])) {
73 | $this->loadPermissions($config['module'], $container, $loader);
74 | }
75 | }
76 |
77 | /**
78 | * @param array $config
79 | * @param ContainerBuilder $container
80 | * @param array $map
81 | */
82 | protected function remapParameters(array $config, ContainerBuilder $container, array $map)
83 | {
84 | foreach ($map as $name => $paramName) {
85 | if (array_key_exists($name, $config)) {
86 | $container->setParameter($paramName, $config[$name]);
87 | }
88 | }
89 | }
90 |
91 | /**
92 | * @param array $config
93 | * @param ContainerBuilder $container
94 | * @param array $namespaces
95 | */
96 | protected function remapParametersNamespaces(array $config, ContainerBuilder $container, array $namespaces)
97 | {
98 | foreach ($namespaces as $ns => $map) {
99 | if ($ns) {
100 | if (!array_key_exists($ns, $config)) {
101 | continue;
102 | }
103 | $namespaceConfig = $config[$ns];
104 | } else {
105 | $namespaceConfig = $config;
106 | }
107 | if (is_array($map)) {
108 | $this->remapParameters($namespaceConfig, $container, $map);
109 | } else {
110 | foreach ($namespaceConfig as $name => $value) {
111 | $container->setParameter(sprintf($map, $name), $value);
112 | }
113 | }
114 | }
115 | }
116 |
117 | private function loadRole(array $config, ContainerBuilder $container, XmlFileLoader $loader)
118 | {
119 | $loader->load('role.xml');
120 | $loader->load('doctrine_role.xml');
121 |
122 | $container->setAlias('eloyekunle_permissions.role_manager', new Alias('eloyekunle_permissions.role_manager.default', true)
123 | );
124 | }
125 |
126 | private function loadPermissions(array $config, ContainerBuilder $container, XmlFileLoader $loader)
127 | {
128 | $loader->load('permissions.xml');
129 |
130 | $this->remapParametersNamespaces(
131 | $config,
132 | $container,
133 | [
134 | '' => [
135 | 'definitions_path' => 'eloyekunle_permissions.module.definitions_path',
136 | ],
137 | ]
138 | );
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/Tests/Security/PermissionVoterTest.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | namespace Eloyekunle\PermissionsBundle\Tests\Security;
13 |
14 | use Eloyekunle\PermissionsBundle\Model\RoleInterface;
15 | use Eloyekunle\PermissionsBundle\Security\PermissionsVoter;
16 | use Eloyekunle\PermissionsBundle\Tests\TestRole;
17 | use Eloyekunle\PermissionsBundle\Tests\TestUser;
18 | use Eloyekunle\PermissionsBundle\Util\PermissionsHandler;
19 | use Eloyekunle\PermissionsBundle\Util\PermissionsHandlerInterface;
20 | use PHPUnit\Framework\TestCase;
21 | use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
22 | use Symfony\Component\Security\Core\Authorization\AccessDecisionManager;
23 | use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
24 | use Symfony\Component\Security\Core\Authorization\Voter\RoleVoter;
25 | use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
26 |
27 | class PermissionVoterTest extends TestCase
28 | {
29 | /** @var TokenInterface */
30 | protected $token;
31 |
32 | /** @var PermissionsVoter */
33 | protected $voter;
34 |
35 | /** @var AccessDecisionManagerInterface */
36 | protected $accessDecisionManager;
37 |
38 | /** @var PermissionsHandlerInterface */
39 | protected $permissionsHandler;
40 |
41 | protected function setUp()
42 | {
43 | $this->accessDecisionManager = new AccessDecisionManager([new RoleVoter()]);
44 | $this->token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock();
45 | $this->permissionsHandler = new PermissionsHandler(__DIR__.'/../Fixtures');
46 |
47 | $this->voter = $this->createPermissionsVoter();
48 | }
49 |
50 | public function getTests()
51 | {
52 | return [
53 | [['delete users'], VoterInterface::ACCESS_DENIED, new \StdClass(), ''],
54 | [['review articles'], VoterInterface::ACCESS_ABSTAIN, new \StdClass(), 'Access Abstain if permission is not declared in modules.'],
55 | ];
56 | }
57 |
58 | public function getTestsNew()
59 | {
60 | return [
61 | [['delete users'], new \StdClass()],
62 | [['review articles'], new \StdClass(), VoterInterface::ACCESS_ABSTAIN],
63 | ];
64 | }
65 |
66 | /**
67 | * @dataProvider getTests
68 | *
69 | * @param array $attributes
70 | * @param $expectedVote
71 | * @param $subject
72 | * @param $message
73 | */
74 | public function testVote(array $attributes, $expectedVote, $subject, $message)
75 | {
76 | $voter = new PermissionsVoter(new AccessDecisionManager(), $this->permissionsHandler);
77 | $token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock();
78 |
79 | $this->assertSame($expectedVote, $voter->vote($token, $subject, $attributes), $message);
80 |
81 | if (VoterInterface::ACCESS_ABSTAIN !== $expectedVote) {
82 | $role = $this->createMockRole();
83 | foreach ($attributes as $attribute) {
84 | $role->grantPermission($attribute);
85 | }
86 | $user = $this->createMockUser();
87 | $user->addRole($role);
88 | $token->expects($this->atLeastOnce())
89 | ->method('getUser')
90 | ->willReturn($user);
91 |
92 | $this->assertSame(VoterInterface::ACCESS_GRANTED, $voter->vote($token, $subject, $attributes));
93 |
94 | foreach ($attributes as $attribute) {
95 | $role->revokePermission($attribute);
96 | }
97 |
98 | $this->assertSame(VoterInterface::ACCESS_DENIED, $voter->vote($token, $subject, $attributes));
99 | }
100 | }
101 |
102 | /**
103 | * @dataProvider getTestsNew
104 | *
105 | * @param array $attributes
106 | * @param $subject
107 | * @param $expectedVote
108 | */
109 | public function testSuperAdminPass(array $attributes, $subject, $expectedVote = VoterInterface::ACCESS_GRANTED)
110 | {
111 | $this->assertSame($expectedVote, $this->voter->vote($this->getToken([RoleInterface::ROLE_SUPER_ADMIN]), $subject, $attributes));
112 | }
113 |
114 | protected function createPermissionsVoter()
115 | {
116 | return new PermissionsVoter($this->accessDecisionManager, $this->permissionsHandler);
117 | }
118 |
119 | protected function getToken(array $roles)
120 | {
121 | foreach ($roles as $i => $role) {
122 | $roles[$i] = $this->createMockRole()->setRole($role);
123 | }
124 | $token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock();
125 | $token->expects($this->any())
126 | ->method('getRoles')
127 | ->will($this->returnValue($roles));
128 |
129 | return $token;
130 | }
131 |
132 | protected function createMockRole()
133 | {
134 | return new TestRole();
135 | }
136 |
137 | protected function createMockUser()
138 | {
139 | return new TestUser();
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | EloyekunlePermissionsBundle
2 | ===========================
3 |
4 | [](https://travis-ci.org/eloyekunle/PermissionsBundle)
5 | [](https://scrutinizer-ci.com/g/eloyekunle/PermissionsBundle/?branch=master)
6 | [](https://scrutinizer-ci.com/g/eloyekunle/PermissionsBundle/?branch=master)
7 |
8 | The EloyekunlePermissionsBundle provides support for a database-backed permissions system in Symfony2.
9 | It provides a flexible framework for permissions management that aims to handle common tasks such as flexible
10 | Permissions Definitions, Roles Creation and Authorization Checking (using Symfony Voters).
11 |
12 | Features include:
13 |
14 | - Roles can be stored via Doctrine ORM.
15 | - Flexible & Modular permissions definitions in YAML files. From few permissions to hundreds, this bundle has your back.
16 | - Symfony Voter for Authorization Checking.
17 | - Unit tested.
18 |
19 | CONTENTS
20 | --------
21 |
22 | * [Installation](#installation)
23 | * [Usage](#usage)
24 | * [Contributions](#contributions)
25 | * [Support](#support)
26 | * [Credits](#credits)
27 |
28 | ## INSTALLATION
29 | Installation is a quick (I promise!) 5 step process:
30 |
31 | 1. [Download EloyekunlePermissionsBundle using composer](#step-1-download-the-bundle)
32 | 2. [Enable the Bundle](#step-2-enable-the-bundle)
33 | 3. [Create your Role class](#step-3-create-role-class)
34 | 4. [Configure your User class](#step-4-configure-your-user-class)
35 | 5. [Configure the bundle](#step-5-configure-the-bundle)
36 | 6. [Update your database schema](#step-5-update-your-database-schema)
37 |
38 | ### Step 1: Download the bundle
39 |
40 | Open a command console, enter your project directory and execute the
41 | following command to download the latest stable version of this bundle:
42 |
43 | ```bash
44 | $ composer require "eloyekunle/permissions-bundle"
45 | ```
46 |
47 | This command requires you to have Composer installed globally, as explained
48 | in the [installation chapter](https://getcomposer.org/doc/00-intro.md) of the Composer documentation.
49 |
50 | ### Step 2: Enable the bundle
51 |
52 | Then, enable the bundle by adding the following line in the ``config/bundles.php``
53 | file of your project, e.g. (Symfony >=4):
54 |
55 | ```php
56 | // config/bundles.php
57 | return [
58 | // ...
59 | Eloyekunle\PermissionsBundle\EloyekunlePermissionsBundle::class => ['all' => true],
60 | ];
61 | ```
62 |
63 | ### Step 3: Create Role class
64 |
65 | The goal of this bundle is to persist some ``Role`` class to a database.
66 | Your first job, then, is to create the ``Role`` class
67 | for your application. This class can look and act however you want: add any
68 | properties or methods you find useful. This is *your* ``Role`` class.
69 |
70 | The bundle provides base classes which are already mapped for most fields
71 | to make it easier to create your entity. Here is how you use it:
72 |
73 | 1. Extend the base ``Role`` class (from the ``Model`` folder if you are using
74 | any of the doctrine variants)
75 | 2. Map the ``id`` field. It must be protected as it is inherited from the parent class.
76 | 3. When you extend from the mapped superclass provided by the bundle, don't
77 | redefine the mapping for the other fields as it is provided by the bundle.
78 | 4. If you override the __construct() method in your Role class, be sure
79 | to call parent::__construct(), as the base Role class depends on this to initialize some fields.
80 |
81 | #### Doctrine ORM Role class
82 |
83 | If you're persisting your roles via the Doctrine ORM, then your ``Role`` class
84 | should live in the ``Entity`` namespace of your bundle and look like this to
85 | start:
86 |
87 | ##### PHP
88 |
89 | ```php
90 |
234 | * array (
235 | * 'title' => 'Edit Content',
236 | * 'description' => 'Grants permission to edit content.',
237 | * 'dependencies' =>
238 | * array (
239 | * 0 => 'view content',
240 | * ),
241 | * 'provider' => 'content',
242 | * ),
243 | * 'view content' =>
244 | * array (
245 | * 'title' => 'View Content',
246 | * 'description' => 'Grants permission to view content.',
247 | * 'provider' => 'content',
248 | * ),
249 | * )
250 | */
251 | $permissions = $permissionsHandler->getPermissions();
252 | // ........................
253 | }
254 | }
255 | ```
256 |
257 | ### 2. Set up a Role
258 |
259 | The bundle ships with a [`RoleManager`](https://github.com/eloyekunle/PermissionsBundle/blob/master/Model/RoleManagerInterface.php)
260 | which is available as a service and can be injected into your Controllers/Services. It contains useful utility methods
261 | to manager roles. You can also `get` it from the container as `eloyekunle_permissions.role_manager`.
262 |
263 | ```php
264 | createRole();
275 | $role->setRole('Content Admin');
276 |
277 | $roleManager->updateRole($role);
278 | // ......
279 | }
280 | }
281 | ```
282 |
283 | This creates and persists a `Role` entity to your database.
284 |
285 | ### 3. Check Permissions in your Controllers
286 |
287 | The bundle ships with a [voter](https://symfony.com/doc/current/security/voters.html), [`PermissionsVoter`](https://github.com/eloyekunle/PermissionsBundle/blob/master/Security/PermissionsVoter.php).
288 | You can check for user permissions by using the `isGranted()` method on Symfony's authorization checker or call
289 | `denyAccessUnlessGranted()` in a controller.
290 |
291 | ```php
292 | denyAccessUnlessGranted('edit content');
310 | // Get a Content object - e.g. query for it.
311 | // $content = ......;
312 | }
313 |
314 | /**
315 | * @Route("/content/{id}", name="content_show")
316 | */
317 | public function show($id)
318 | {
319 | $this->denyAccessUnlessGranted('view content');
320 | // Get a Content object - e.g. query for it.
321 | // $content = ......;
322 | }
323 | }
324 | ```
325 |
326 | ## CONTRIBUTIONS
327 |
328 | Contributions of any kind are welcome: code, documentation, ideas etc.
329 | Issues and feature requests are tracked in the [Github issue tracker](https://github.com/eloyekunle/PermissionsBundle/issues).
330 |
331 | ## SUPPORT
332 | If you need any support related to this bundle, you can contact me on the [Symfony Slack group](http://symfony-devs.slack.com)
333 | (eloyekunle), or send me an email (eloyekunle@gmail.com).
334 |
335 | ## CREDITS
336 | - Bundle inspired by the [Drupal Permissions System](https://api.drupal.org/api/drupal/core!core.api.php/group/user_api/8.5.x)!
337 | - Implementation inspired by some excellent Symfony bundles, especially [FOSUserBundle](https://github.com/FriendsOfSymfony/FOSUserBundle).
338 | - [Elijah Oyekunle](https://elijahoyekunle.com) - [LinkedIn](https://www.linkedin.com/in/elijahoyekunle) - [Twitter](https://twitter.com/elijahoyekunle) - [Github](https://github.com/eloyekunle)
--------------------------------------------------------------------------------
/Resources/config/schema/doctrine-mapping.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
--------------------------------------------------------------------------------