access_policy-1.0.x-dev/tests/src/Kernel/AccessPolicyOperationsAccessTest.php
tests/src/Kernel/AccessPolicyOperationsAccessTest.php
<?php namespace Drupal\Tests\access_policy\Kernel; use Drupal\access_policy\Entity\AccessPolicy; use Drupal\Core\Session\UserSession; use Drupal\taxonomy\Entity\Term; use Drupal\taxonomy\Entity\Vocabulary; /** * Tests Access Policy permissions. * * @group access_policy */ class AccessPolicyOperationsAccessTest extends AccessPolicyKernelTestBase { /** * The entity storage. * * @var \Drupal\Core\Entity\RevisionableStorageInterface */ protected $storage; /** * The modules required for this test. * * @var string[] */ protected static $modules = [ 'field', 'filter', 'node', 'taxonomy', 'options', 'access_policy', 'access_policy_test', 'system', 'text', 'user', ]; /** * The default permissions of each user. * * @var array */ protected $defaultPermissions = [ 'access content', 'edit any page content', 'delete any page content', 'view all revisions', 'revert page revisions', 'delete page revisions', ]; /** * {@inheritdoc} */ protected function setUp(): void { parent::setUp(); $this->installConfig(['access_policy']); $this->installConfig(['access_policy_test']); $this->installEntitySchema('taxonomy_term'); $vocabulary = Vocabulary::create([ 'name' => 'tags', 'vid' => 'tags', ]); $vocabulary->save(); // First user is always admin. $this->createUser(); $this->createAccessPolicyFixtures(); $this->contentAccessPolicyManager = $this->container->get('access_policy.content_policy_manager'); $this->storage = $this->container->get('entity_type.manager')->getStorage('node'); } /** * Create access policy fixtures. * * These different access policies will be test against as part of each * test defined in the data providers. */ public function createAccessPolicyFixtures() { AccessPolicy::create([ 'id' => 'public', 'label' => 'Public test policy', 'access_rules' => [], 'target_entity_type_id' => 'node', 'operations' => [ 'view' => [], 'view_all_revisions' => [ 'permission' => TRUE, ], 'edit' => [ 'permission' => TRUE, ], 'delete' => [ 'permission' => TRUE, ], 'view_unpublished' => [ 'permission' => TRUE, ], 'manage_access' => [], ], ])->save(); $public_with_rules = AccessPolicy::create([ 'id' => 'public_with_rules', 'label' => 'Public test policy with access rules', 'access_rules' => [], 'target_entity_type_id' => 'node', 'operations' => [ 'view' => [], 'view_all_revisions' => [ 'access_rules' => TRUE, ], 'edit' => [ 'access_rules' => TRUE, ], 'delete' => [ 'access_rules' => TRUE, ], 'view_unpublished' => [ 'access_rules' => TRUE, ], 'manage_access' => [ 'access_rules' => TRUE, ], ], ]); $access_rule = $this->accessRuleManager->getHandler('node', 'is_own'); $public_with_rules->addHandler('access_rule', $access_rule); $selection_rule = $this->selectionRuleManager->getHandler('node', 'is_own'); $public_with_rules->addHandler('selection_rule', $selection_rule); $public_with_rules->save(); AccessPolicy::create([ 'id' => 'group', 'label' => 'Group test policy without rules', 'target_entity_type_id' => 'node', ])->save(); $group_with_rules = AccessPolicy::create([ 'id' => 'group_with_rules', 'label' => 'Group test policy without rules', 'target_entity_type_id' => 'node', ]); $access_rule = $this->accessRuleManager->getHandler('user', 'field_text'); $access_rule->setSettings([ 'operator' => '=', 'value' => 'Foo', ]); $group_with_rules->addHandler('access_rule', $access_rule); $group_with_rules->save(); $private_policy = AccessPolicy::create([ 'id' => 'private', 'label' => 'Private policy', 'target_entity_type_id' => 'node', 'operations' => [ 'view' => [ 'access_rules' => TRUE, ], 'view_all_revisions' => [ 'access_rules' => TRUE, ], 'edit' => [ 'access_rules' => TRUE, ], 'delete' => [ 'access_rules' => TRUE, ], 'view_unpublished' => [ 'access_rules' => TRUE, ], 'manage_access' => [], ], ]); $access_rule = $this->accessRuleManager->getHandler('node', 'is_own'); $private_policy->addHandler('access_rule', $access_rule); $selection_rule = $this->selectionRuleManager->getHandler('node', 'is_own'); $private_policy->addHandler('selection_rule', $selection_rule); $private_policy->save(); } /** * Tests the access policy operations for various policy types. * * @dataProvider providerAccessPolicyOperations */ public function testAccessPolicyOperations($policy, $user, $expected_operations, $expected_contexts) { $perms = array_merge($this->defaultPermissions, $user['permissions']); $user_fields = $user['fields'] ?? []; $account = $this->createUser($perms, 'user', FALSE, $user_fields); $this->setCurrentUser($account); $policy = $this->entityTypeManager->getStorage('access_policy')->load($policy); $node = $this->createNode(['type' => 'page', 'uid' => 2]); $this->contentAccessPolicyManager->assign($node, $policy); // Create a new revision, this is necessary for revert/delete revisions. $node->setNewRevision(); $node->set('title', 'New revision'); $node->save(); foreach ($expected_operations as $op => $expected_access) { $revision_ops = [ 'view all revisions', 'view revision', 'delete revision', 'revert revision', ]; if (in_array($op, $revision_ops)) { $entity = $this->storage->loadRevision(1); } else { $entity = $node; } $result = $entity->access($op, $account, TRUE); if ($expected_operations[$op]) { $this->assertTrue($result->isAllowed(), 'Operation "' . $op . '" should be allowed for node ' . $entity->id()); } else { $this->assertTrue($result->isForbidden(), 'Operation "' . $op . '" should be forbidden for node ' . $entity->id()); } // It's only necessary to check this for the view operation. if ($op == 'view') { // Verify the cache contexts. Public content does not have access rules // so it will always be user.permissions. $result = $node->access($op, $account, TRUE); $contexts = $result->getCacheContexts(); $this->assertEquals($expected_contexts, $contexts, 'The cache contexts is incorrect.'); $tags = $result->getCacheTags(); $expected = [ 'node:1', 'config:access_policy.access_policy.' . $policy->id(), ]; $this->assertEquals($expected, $tags, 'The cache tags are incorrect for operation: ' . $op); $this->setCurrentUser($account); $expected_query = ($expected_operations['view']) ? [$node->id()] : []; $this->assertQueryResults('node', $expected_query); } } } /** * Data provider for access policy operations test. */ public function providerAccessPolicyOperations() { return [ 'user has access to public content' => [ 'policy' => 'public', 'user' => [ 'permissions' => [ 'edit public content', 'delete public content', 'view all public content revisions', 'set entity access policy', 'assign public access policy', ], ], 'expected operations' => [ 'view' => TRUE, 'update' => TRUE, 'delete' => TRUE, 'manage access' => TRUE, 'view all revisions' => TRUE, 'view revision' => TRUE, 'delete revision' => TRUE, 'revert revision' => TRUE, ], 'expected contexts' => ['user.permissions'], ], 'user only has view access to public content' => [ 'policy' => 'public', 'user' => [ 'permissions' => [], ], 'expected operations' => [ 'view' => TRUE, 'update' => FALSE, 'delete' => FALSE, 'manage access' => FALSE, 'view all revisions' => FALSE, 'view revision' => FALSE, 'delete revision' => FALSE, 'revert revision' => FALSE, ], 'expected contexts' => ['user.permissions'], ], 'user has access to public content (with access rules)' => [ 'policy' => 'public_with_rules', 'user' => [ 'permissions' => [], // This is not the original author. 'fields' => ['uid' => 3], ], 'expected operations' => [ 'view' => TRUE, 'update' => FALSE, 'delete' => FALSE, 'manage access' => FALSE, 'view all revisions' => FALSE, 'view revision' => FALSE, 'delete revision' => FALSE, 'revert revision' => FALSE, ], 'expected contexts' => ['user', 'user.permissions'], ], 'user has access to group content (without access rules)' => [ 'policy' => 'group', 'user' => [ 'permissions' => [ 'view group content', 'edit group content', 'delete group content', 'view all group content revisions', 'set entity access policy', 'assign group access policy', ], ], 'expected operations' => [ 'view' => TRUE, 'update' => TRUE, 'delete' => TRUE, 'manage access' => TRUE, 'view all revisions' => TRUE, 'view revision' => TRUE, 'delete revision' => TRUE, 'revert revision' => TRUE, ], 'expected contexts' => ['user.permissions'], ], 'user does not have access to group content (without access rules)' => [ 'policy' => 'group', 'user' => [ 'permissions' => [], ], 'expected operations' => [ 'view' => FALSE, 'update' => FALSE, 'delete' => FALSE, 'manage access' => FALSE, 'view all revisions' => FALSE, 'view revision' => FALSE, 'delete revision' => FALSE, 'revert revision' => FALSE, ], 'expected contexts' => ['user.permissions'], ], 'user has access to group content (with access rules)' => [ 'policy' => 'group_with_rules', 'user' => [ 'permissions' => [ 'view group_with_rules content', 'edit group_with_rules content', 'delete group_with_rules content', 'view all group_with_rules content revisions', 'set entity access policy', 'assign group_with_rules access policy', ], 'fields' => [ 'field_text' => 'Foo', ], ], 'expected operations' => [ 'view' => TRUE, 'update' => TRUE, 'delete' => TRUE, 'manage access' => TRUE, 'view all revisions' => TRUE, 'view revision' => TRUE, 'delete revision' => TRUE, 'revert revision' => TRUE, ], 'expected contexts' => [ 'user.field_values', 'user.permissions', ], ], 'user does not have access to group content (with access rules)' => [ 'policy' => 'group_with_rules', 'user' => [ 'permissions' => [ 'view group_with_rules content', 'edit group_with_rules content', 'delete group_with_rules content', 'view all group_with_rules content revisions', 'set entity access policy', 'assign group_with_rules access policy', ], 'fields' => [ 'field_text' => 'Bar', ], ], 'expected operations' => [ 'view' => FALSE, 'update' => FALSE, 'delete' => FALSE, 'manage access' => FALSE, 'view all revisions' => FALSE, 'view revision' => FALSE, 'delete revision' => FALSE, 'revert revision' => FALSE, ], 'expected contexts' => [ 'user.field_values', 'user.permissions', ], ], 'user has access to private content' => [ 'policy' => 'private', 'user' => [ 'permissions' => [ 'set entity access policy', 'assign private access policy', ], 'fields' => ['uid' => 2], ], 'expected operations' => [ 'view' => TRUE, 'update' => TRUE, 'delete' => TRUE, 'manage access' => TRUE, 'view all revisions' => TRUE, 'view revision' => TRUE, 'delete revision' => TRUE, 'revert revision' => TRUE, ], 'expected contexts' => ['user', 'user.permissions'], ], 'user does not have access to private content' => [ 'policy' => 'private', 'user' => [ 'permissions' => [ 'set entity access policy', 'assign private access policy', ], 'fields' => ['uid' => 3], ], 'expected operations' => [ 'view' => FALSE, 'update' => FALSE, 'delete' => FALSE, 'manage access' => FALSE, 'view all revisions' => FALSE, 'view revision' => FALSE, 'delete revision' => FALSE, 'revert revision' => FALSE, ], 'expected contexts' => ['user', 'user.permissions'], ], ]; } /** * Testing Drupal default Access Policy operation access. * * This is mostly just testing drupal core access except for the assign * operation. This has slightly different behavior than the other operations * therefore it's not included in the data provider. */ public function testDefaultAccessPolicyOperations() { $policy = AccessPolicy::create([ 'id' => 'default_policy', 'label' => 'Default test policy.', 'target_entity_type_id' => 'node', 'operations' => [ 'view' => [], 'view_all_revisions' => [], 'update' => [], 'delete' => [], 'view_unpublished' => [], 'manage_access' => [], ], ]); $policy->save(); $this->createRole([ 'access content', 'edit any page content', 'delete any page content', 'view all revisions', 'set entity access policy', 'assign default_policy access policy', ], 'test_role'); $account = $this->createUser([], 'user1', FALSE, ['uid' => 2]); $account->addRole('test_role'); $account->save(); $node = $this->createNode(['type' => 'page', 'uid' => $account->id()]); $this->contentAccessPolicyManager->assign($node, $policy); // Create a new revision, this is necessary for revert/delete revisions. $node->setNewRevision(); $node->set('title', 'New revision'); $node->save(); $result = $node->access('view', $account, TRUE); $this->assertTrue($result->isAllowed(), 'The user should be able to view the content.'); $contexts = $result->getCacheContexts(); $this->assertEquals(['user.permissions'], $contexts, 'The cache contexts is incorrect.'); $result = $node->access('update', $account, TRUE); $this->assertTrue($result->isAllowed(), 'The user should be able to edit the content.'); $result = $node->access('delete', $account, TRUE); $this->assertTrue($result->isAllowed(), 'The user should be able to delete the content.'); $result = $node->access('manage access', $account, TRUE); $this->assertTrue($result->isAllowed(), 'The user should be able to view the content Access page.'); $result = $node->access('view all revisions', $account, TRUE); $this->assertTrue($result->isAllowed(), 'The user should be be able to view all revisions.'); $node_revision = $this->storage->loadRevision(1); $result = $node_revision->access('view revision', $account, TRUE); $this->assertTrue($result->isAllowed(), 'The user should be be able to view the revision.'); $account = $this->createUser([ 'access content', ]); $result = $node->access('view', $account, TRUE); $this->assertTrue($result->isAllowed(), 'The user should be able to view the content.'); $result = $node->access('update', $account, TRUE); $this->assertTrue($result->isNeutral(), 'The user should not able to edit the content.'); $result = $node->access('delete', $account, TRUE); $this->assertTrue($result->isNeutral(), 'The user should not be able to delete the content.'); $result = $node->access('manage access', $account, TRUE); $this->assertTrue($result->isForbidden(), 'The user should not be able to assign the policy.'); $result = $node->access('view all revisions', $account, TRUE); $this->assertTrue($result->isNeutral(), 'The user should not be able to see all revisions.'); $node_revision = $this->storage->loadRevision(1); $result = $node_revision->access('view revision', $account, TRUE); $this->assertTrue($result->isNeutral(), 'The user should not be able to see the revision.'); } /** * Test access policy group permissions with taxonomy terms. */ public function testTaxonomyTermGroupAccessPolicyOperations() { $policy = AccessPolicy::create([ 'id' => 'group_policy_with_terms', 'label' => 'Group test policy taxonomy terms', 'target_entity_type_id' => 'taxonomy_term', ]); $policy->save(); // Add a term to the vocabulary. $term = Term::create([ 'name' => 'Sometimes people are just jerks', 'vid' => 'tags', ]); $term->save(); $this->contentAccessPolicyManager->assign($term, $policy); $this->createRole([ 'access content', 'create terms in tags', 'delete terms in tags', 'edit terms in tags', 'view group_policy_with_terms taxonomy term', 'edit group_policy_with_terms taxonomy term', 'delete group_policy_with_terms taxonomy term', 'set entity access policy', 'assign group_policy_with_terms access policy', ], 'group_policy'); $account = new UserSession([ 'uid' => 2, 'roles' => ['group_policy'], ]); $result = $term->access('view', $account, TRUE); $this->assertTrue($result->isAllowed(), 'The user should be able to view the term.'); $result = $term->access('update', $account, TRUE); $this->assertTrue($result->isAllowed(), 'The user should be able to edit the term.'); $result = $term->access('delete', $account, TRUE); $this->assertTrue($result->isAllowed(), 'The user should be able to delete the term.'); $result = $term->access('manage access', $account, TRUE); $this->assertTrue($result->isAllowed(), 'The user should be able to view the term Access page.'); $this->createRole([ 'access content', 'create terms in tags', 'delete terms in tags', 'edit terms in tags', 'set entity access policy', ], 'authenticated'); $account = new UserSession([ 'roles' => ['authenticated'], ]); $result = $term->access('view', $account, TRUE); $this->assertTrue($result->isForbidden(), 'The user should not be able to view the term.'); $result = $term->access('update', $account, TRUE); $this->assertTrue($result->isForbidden(), 'The user should not able to edit the term.'); $result = $term->access('delete', $account, TRUE); $this->assertTrue($result->isForbidden(), 'The user should not be able to delete the term.'); $result = $term->access('manage access', $account, TRUE); $this->assertTrue($result->isForbidden(), 'The user should not be able to assign the policy.'); } }