diff --git a/core/modules/simpletest/tests/Drupal/simpletest/Tests/phpunit_error.xml b/core/modules/simpletest/tests/Drupal/simpletest/Tests/phpunit_error.xml
index a8cf4d9..95bde5d 100644
--- a/core/modules/simpletest/tests/Drupal/simpletest/Tests/phpunit_error.xml
+++ b/core/modules/simpletest/tests/Drupal/simpletest/Tests/phpunit_error.xml
@@ -17,22 +17,22 @@ Undefined index: foo
-
-
+
+
- Drupal\Tests\Core\Route\RouterRoleTest::testRoleAccess with data set #0 ('role_test_1', array(Drupal\user\Plugin\Core\Entity\User, Drupal\user\Plugin\Core\Entity\User))
+ Drupal\Tests\Core\Route\RoleAccessCheckTest::testRoleAccess with data set #0 ('role_test_1', array(Drupal\user\Plugin\Core\Entity\User, Drupal\user\Plugin\Core\Entity\User))
Access granted for user with the roles role_test_1 on path: role_test_1
Failed asserting that false is true.
- Drupal\Tests\Core\Route\RouterRoleTest::testRoleAccess with data set #1 ('role_test_2', array(Drupal\user\Plugin\Core\Entity\User, Drupal\user\Plugin\Core\Entity\User))
+ Drupal\Tests\Core\Route\RoleAccessCheckTest::testRoleAccess with data set #1 ('role_test_2', array(Drupal\user\Plugin\Core\Entity\User, Drupal\user\Plugin\Core\Entity\User))
Access granted for user with the roles role_test_2 on path: role_test_2
Failed asserting that false is true.
- Drupal\Tests\Core\Route\RouterRoleTest::testRoleAccess with data set #2 ('role_test_3', array(Drupal\user\Plugin\Core\Entity\User))
+ Drupal\Tests\Core\Route\RoleAccessCheckTest::testRoleAccess with data set #2 ('role_test_3', array(Drupal\user\Plugin\Core\Entity\User))
Access granted for user with the roles role_test_1, role_test_2 on path: role_test_3
Failed asserting that false is true.
diff --git a/core/modules/user/lib/Drupal/user/Access/RoleAccessCheck.php b/core/modules/user/lib/Drupal/user/Access/RoleAccessCheck.php
new file mode 100644
index 0000000..104763d
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/Access/RoleAccessCheck.php
@@ -0,0 +1,60 @@
+getRequirements());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function access(Route $route, Request $request) {
+ // Requirements just allow strings, so this might be a comma separated list.
+ $rid_string = $route->getRequirement('_role');
+
+ // @todo Replace the role check with a correctly injected and session-using
+ // alternative.
+ $account = $GLOBALS['user'];
+
+ $explode_and = array_filter(array_map('trim', explode('+', $rid_string)));
+ if (count($explode_and) > 1) {
+ $diff = array_diff($explode_and, array_keys($account->roles));
+ if (empty($diff)) {
+ return TRUE;
+ }
+ }
+ else {
+ $explode_or = array_filter(array_map('trim', explode(',', $rid_string)));
+ $intersection = array_intersect($explode_or, array_keys($account->roles));
+ if (!empty($intersection)) {
+ return TRUE;
+ }
+ }
+
+ // If there is no allowed role, return NULL to give other checks a chance.
+ return NULL;
+ }
+
+}
diff --git a/core/modules/user/user.services.yml b/core/modules/user/user.services.yml
index e8c5e52..77f93e2 100644
--- a/core/modules/user/user.services.yml
+++ b/core/modules/user/user.services.yml
@@ -7,6 +7,10 @@ services:
class: Drupal\user\Access\RegisterAccessCheck
tags:
- { name: access_check }
+ access_check.user.role:
+ class: Drupal\user\Access\RoleAccessCheck
+ tags:
+ - { name: access_check }
user.data:
class: Drupal\user\UserData
arguments: ['@database']
diff --git a/core/tests/Drupal/Tests/Core/Route/RoleAccessCheckTest.php b/core/tests/Drupal/Tests/Core/Route/RoleAccessCheckTest.php
new file mode 100644
index 0000000..2561c55
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Route/RoleAccessCheckTest.php
@@ -0,0 +1,157 @@
+ 'Router Role tests',
+ 'description' => 'Test for the role based access checker in the routing system.',
+ 'group' => 'Routing',
+ );
+ }
+
+ /**
+ * Generates the test route collection.
+ *
+ * @return \Symfony\Component\Routing\RouteCollection
+ * Returns the test route collection.
+ */
+ protected function getTestRouteCollection() {
+ $route_collection = new RouteCollection();
+ $route_collection->add('role_test_1', new Route('/role_test_1',
+ array(
+ '_controller' => '\Drupal\router_test\TestControllers::test1',
+ ),
+ array(
+ '_role' => 'role_test_1',
+ )
+ ));
+ $route_collection->add('role_test_2', new Route('/role_test_2',
+ array(
+ '_controller' => '\Drupal\router_test\TestControllers::test1',
+ ),
+ array(
+ '_role' => 'role_test_2',
+ )
+ ));
+ $route_collection->add('role_test_3', new Route('/role_test_3',
+ array(
+ '_controller' => '\Drupal\router_test\TestControllers::test1',
+ ),
+ array(
+ '_role' => 'role_test_1+role_test_2',
+ )
+ ));
+ $route_collection->add('role_test_4', new Route('/role_test_4',
+ array(
+ '_controller' => '\Drupal\router_test\TestControllers::test1',
+ ),
+ array(
+ '_role' => 'role_test_1,role_test_2',
+ )
+ ));
+
+ return $route_collection;
+ }
+
+ /**
+ * Provides data for the role access test.
+ *
+ * @see \Drupal\Tests\Core\Route\RouterRoleTest::testRoleAccess
+ */
+ public function roleAccessProvider() {
+ // Setup two different roles used in the test.
+ $rid_1 = 'role_test_1';
+ $rid_2 = 'role_test_2';
+
+ // Setup one user with the first role, one with the second, one with both
+ // and one final without any of these two roles.
+ $account_1 = new User(array('uid' => 1), 'user');
+ $account_1->roles[$rid_1] = $rid_1;
+
+ $account_2 = new User(array('uid' => 2), 'user');
+ $account_2->roles[$rid_2] = $rid_2;
+
+ $account_12 = new User(array('uid' => 3), 'user');
+ $account_12->roles[$rid_1] = $rid_1;
+ $account_12->roles[$rid_2] = $rid_2;
+
+ $account_none = new User(array('uid' => 4), 'user');
+
+ // Setup expected values; specify which paths can be accessed by which user.
+ return array(
+ array('role_test_1', array($account_1, $account_12), array($account_2, $account_none)),
+ array('role_test_2', array($account_2, $account_12), array($account_1, $account_none)),
+ array('role_test_3', array($account_12), array($account_1, $account_2, $account_none)),
+ array('role_test_4', array($account_1, $account_2, $account_12), array()),
+ );
+ }
+
+ /**
+ * Tests role requirements on routes.
+ *
+ * @param string $path
+ * The path to check access for.
+ * @param array $grant_accounts
+ * A list of accounts which should have access to the given path.
+ * @param array $deny_accounts
+ * A list of accounts which should not have access to the given path.
+ *
+ * @see \Drupal\Tests\Core\Route\RouterRoleTest::getTestRouteCollection
+ * @see \Drupal\Tests\Core\Route\RouterRoleTest::roleAccessProvider
+ *
+ * @dataProvider roleAccessProvider
+ */
+ public function testRoleAccess($path, $grant_accounts, $deny_accounts) {
+ $role_access_check = new RoleAccessCheck();
+ $collection = $this->getTestRouteCollection();
+
+ foreach ($grant_accounts as $account) {
+ // @todo Replace the global user with a properly injection session.
+ $GLOBALS['user'] = $account;
+
+ $subrequest = Request::create($path, 'GET');
+ $message = sprintf('Access granted for user with the roles %s on path: %s', implode(', ', $account->roles), $path);
+ $this->assertTrue($role_access_check->access($collection->get($path), $subrequest), $message);
+ }
+
+ // Check all users which don't have access.
+ foreach ($deny_accounts as $account) {
+ $GLOBALS['user'] = $account;
+
+ $subrequest = Request::create($path, 'GET');
+ $message = sprintf('Access denied for user %s with the roles %s on path: %s', $account->id(), implode(', ', $account->roles), $path);
+ $has_access = $role_access_check->access($collection->get($path), $subrequest);
+ $this->assertEmpty($has_access , $message);
+ }
+ }
+
+}