access_policy-1.0.x-dev/tests/src/Functional/AccessPolicyEntityListingTest.php
tests/src/Functional/AccessPolicyEntityListingTest.php
<?php namespace Drupal\Tests\access_policy\Functional; use Drupal\access_policy\Entity\AccessPolicy; use Drupal\user\Entity\Role; /** * Ensures that listings only display entities that a user is allowed to view. * * @group access_policy */ class AccessPolicyEntityListingTest extends AccessPolicyTestBase { /** * Modules to enable. * * @var array */ protected static $modules = [ 'access_policy', 'access_policy_test', 'filter', 'node', 'field', 'user', 'datetime', 'views', ]; /** * {@inheritdoc} */ protected $defaultTheme = 'stark'; /** * {@inheritdoc} */ public function setUp(): void { parent::setUp(); // This is necessary to register the access rules. AccessPolicy::create([ 'id' => 'test_policy', 'label' => 'Test policy', 'access_rules' => [], 'target_entity_type_id' => 'node', ])->save(); } /** * Tests that a listing only displays entities that a user is allowed to view. */ public function testContentListing() { $policy = AccessPolicy::create([ 'id' => 'matching_text', 'label' => 'Matching Text Access Policy', 'target_entity_type_id' => 'node', ]); // You should audit the rules and see which ones are worth removing. $access_rule = $this->accessRuleManager->getHandler('node', 'field_text'); $access_rule->setSettings([ 'operator' => '=', 'value' => 'Foo', 'empty_behavior' => 'deny', ]); $policy->addHandler('access_rule', $access_rule); $policy->save(); $policy = AccessPolicy::create([ 'id' => 'basic_policy_no_rules', 'label' => 'Test Access Policy', 'target_entity_type_id' => 'node', ]); $policy->save(); $admin_user = $this->drupalCreateUser([ 'access administration pages', 'access content overview', 'administer nodes', 'bypass node access', 'view matching_text content', ]); $admin_user->save(); $this->drupalCreateNode([ 'title' => 'First', 'type' => 'page', 'status' => 1, 'field_text' => 'Foo', 'access_policy' => ['matching_text'], ]); $this->drupalCreateNode([ 'title' => 'Second', 'type' => 'page', 'status' => 1, 'field_text' => 'Restricted', 'access_policy' => ['matching_text'], ]); $this->drupalCreateNode([ 'title' => 'Third', 'type' => 'page', 'status' => 1, 'access_policy' => ['matching_text'], ]); $this->drupalCreateNode([ 'title' => 'Fourth', 'type' => 'page', 'status' => 1, 'access_policy' => ['basic_policy_no_rules'], ]); $this->drupalLogin($admin_user); // Verify that only the content that the user can access is listed. $this->drupalGet('admin/content'); $this->assertSession()->statusCodeEquals(200); $this->assertSession()->pageTextContains('First'); $this->assertSession()->pageTextNotContains('Second'); $this->assertSession()->pageTextNotContains('Third'); $this->assertSession()->pageTextNotContains('Fourth'); } /** * Tests that a policy is not applied to a query when disabled. */ public function testContentListingWithPolicyQueryDisabled() { $policy = AccessPolicy::create([ 'id' => 'policy_with_query_disabled', 'label' => 'Test Access Policy with query disabled.', 'query' => FALSE, 'target_entity_type_id' => 'node', ]); // You should audit the rules and see which ones are worth removing. $access_rule = $this->accessRuleManager->getHandler('node', 'field_text'); $access_rule->setSettings([ 'operator' => '=', 'value' => 'Foo', 'empty_behavior' => 'deny', ]); $policy->addHandler('access_rule', $access_rule); $policy->save(); $node_1 = $this->drupalCreateNode([ 'title' => 'Different text (visible)', 'type' => 'page', 'status' => 1, 'field_text' => 'Bar', 'access_policy' => ['policy_with_query_disabled'], ]); $node_2 = $this->drupalCreateNode([ 'title' => 'Matching text (visible)', 'type' => 'page', 'status' => 1, 'field_text' => 'Foo', 'access_policy' => ['policy_with_query_disabled'], ]); $rid = $this->createRole([ 'access administration pages', 'access content overview', 'administer nodes', ]); $role = Role::load($rid); $user = $this->drupalCreateUser(); $user->addRole($rid); $user->save(); $this->drupalLogin($user); // Verify that all the content is visible on listing pages even if the // user doesn't have the permission to view content with that access policy. $this->drupalGet('node/' . $node_1->id()); $this->assertSession()->statusCodeEquals(403); $this->drupalGet('node/' . $node_2->id()); $this->assertSession()->statusCodeEquals(403); $this->drupalGet('admin/content'); $this->assertSession()->statusCodeEquals(200); $this->assertSession()->pageTextContains('Matching text (visible)'); $this->assertSession()->pageTextContains('Different text (visible)'); // Verify that all the content is visible on listing pages even if some // rules wouldn't usually pass when viewed directly. $this->grantPermissions($role, [ 'view policy_with_query_disabled content', ]); $this->drupalGet('node/' . $node_1->id()); $this->assertSession()->statusCodeEquals(403); $this->drupalGet('node/' . $node_2->id()); $this->assertSession()->statusCodeEquals(200); $this->drupalGet('admin/content'); $this->assertSession()->statusCodeEquals(200); $this->assertSession()->pageTextContains('Matching text (visible)'); $this->assertSession()->pageTextContains('Different text (visible)'); } /** * Tests content listing with multiple AND access rules. * * Tests that a listing only displays entities that a user is allowed to view * when that policy has multiple rules using AND. */ public function testContentListingWithMultipleAndRules() { $policy = AccessPolicy::create([ 'id' => 'test_policy_with_and_rules', 'label' => 'Test Access Policy with AND rules', 'target_entity_type_id' => 'node', ]); $access_rule = $this->accessRuleManager->getHandler('node', 'field_text'); $access_rule->setSettings([ 'operator' => '=', 'value' => 'Foo', ]); $policy->addHandler('access_rule', $access_rule); $policy->addHandler('access_rule', $this->accessRuleManager->getHandler('node', 'is_own')); $policy->save(); $admin_user = $this->drupalCreateUser([ 'access administration pages', 'access content overview', 'administer nodes', 'bypass node access', 'view test_policy_with_and_rules content', ]); $this->drupalCreateNode([ 'title' => 'Matching text (visible)', 'type' => 'page', 'status' => 1, 'uid' => $admin_user->id(), 'field_text' => 'Foo', 'access_policy' => ['test_policy_with_and_rules'], ]); $this->drupalCreateNode([ 'title' => 'Different owner (hidden)', 'type' => 'page', 'status' => 1, 'uid' => 100, 'field_text' => 'Foo', 'access_policy' => ['test_policy_with_and_rules'], ]); $this->drupalCreateNode([ 'title' => 'Different text and owner (hidden)', 'type' => 'page', 'status' => 1, 'uid' => 100, 'field_text' => 'Bar', 'access_policy' => ['test_policy_with_and_rules'], ]); $this->drupalLogin($admin_user); // Verify that only the content that the user can access is listed. $this->drupalGet('admin/content'); $this->assertSession()->statusCodeEquals(200); $this->assertSession()->pageTextContains('Matching text (visible)'); $this->assertSession()->pageTextNotContains('Different owner (hidden)'); $this->assertSession()->pageTextNotContains('Different text and owner (hidden)'); } /** * Tests content listing with multiple OR access rules. * * Tests that a listing only displays entities that a user is allowed to view * when that policy has multiple rules using OR. */ public function testContentListingWithMultipleOrRules() { $policy = AccessPolicy::create([ 'id' => 'test_policy_with_or_rules', 'label' => 'Test Access Policy with OR rules', 'access_rule_operator' => 'OR', 'target_entity_type_id' => 'node', ]); $access_rule = $this->accessRuleManager->getHandler('node', 'field_text'); $access_rule->setSettings([ 'operator' => '=', 'value' => 'Foo', ]); $policy->addHandler('access_rule', $access_rule); $policy->addHandler('access_rule', $this->accessRuleManager->getHandler('node', 'is_own')); $policy->save(); $admin_user = $this->drupalCreateUser([ 'access administration pages', 'access content overview', 'administer nodes', 'bypass node access', 'view test_policy_with_or_rules content', ]); $admin_user->save(); $this->drupalCreateNode([ 'title' => 'Matching text and owner (visible)', 'type' => 'page', 'status' => 1, 'uid' => $admin_user->id(), 'field_text' => 'Foo', 'access_policy' => ['test_policy_with_or_rules'], ]); $this->drupalCreateNode([ 'title' => 'Different text (visible)', 'type' => 'page', 'status' => 1, 'uid' => $admin_user->id(), 'field_text' => 'Bar', 'access_policy' => ['test_policy_with_or_rules'], ]); $this->drupalCreateNode([ 'title' => 'Different owner (visible)', 'type' => 'page', 'status' => 1, 'uid' => 100, 'field_text' => 'Foo', 'access_policy' => ['test_policy_with_or_rules'], ]); $this->drupalCreateNode([ 'title' => 'Different text and owner (hidden)', 'type' => 'page', 'status' => 1, 'uid' => 100, 'field_text' => 'Bar', 'access_policy' => ['test_policy_with_or_rules'], ]); $this->drupalLogin($admin_user); // Verify that only the content that the user can access is listed. $this->drupalGet('admin/content'); $this->assertSession()->statusCodeEquals(200); $this->assertSession()->pageTextContains('Matching text and owner (visible)'); $this->assertSession()->pageTextContains('Different text (visible)'); $this->assertSession()->pageTextContains('Different owner (visible)'); $this->assertSession()->pageTextNotContains('Different text and owner (hidden)'); } /** * Tests that a listing displays entities with Access Rules a user can bypass. */ public function testContentListingWithBypassAccessRulesEnabled() { $policy = AccessPolicy::create([ 'id' => 'matching_text', 'label' => 'Matching Text Access Policy', 'target_entity_type_id' => 'node', ]); $access_rule = $this->accessRuleManager->getHandler('node', 'field_text'); $access_rule->setSettings([ 'operator' => '=', 'value' => 'Foo', ]); $policy->addHandler('access_rule', $access_rule); $policy->save(); $admin_user = $this->drupalCreateUser([ 'access administration pages', 'access content overview', 'administer nodes', 'bypass node access', 'view matching_text content', 'bypass matching_text access rules', ]); $admin_user->set('field_text', 'Matching text'); $admin_user->save(); $this->drupalCreateNode([ 'title' => 'First', 'type' => 'page', 'status' => 1, 'field_text' => 'Foo', 'access_policy' => ['matching_text'], ]); $this->drupalCreateNode([ 'title' => 'Second', 'type' => 'page', 'status' => 1, 'field_text' => 'Bar', 'access_policy' => ['matching_text'], ]); $this->drupalLogin($admin_user); // Verify that content for which a user can bypass Access Rules is listed. $this->drupalGet('admin/content'); $this->assertSession()->statusCodeEquals(200); $this->assertSession()->pageTextContains('First'); $this->assertSession()->pageTextContains('Second'); } /** * Tests that an access rule without a query doesn't break the query. */ public function testContentListingWithAccessRulesQueryMissing() { $policy = AccessPolicy::create([ 'id' => 'rules_with_no_query', 'label' => 'Test Access Policy with no query rules', 'target_entity_type_id' => 'node', ]); $policy->addHandler('access_rule', $this->accessRuleManager->getHandler('node', 'access_rule_test')); $policy->save(); $admin_user = $this->drupalCreateUser([ 'access administration pages', 'access content overview', 'administer nodes', 'bypass node access', 'view rules_with_no_query content', ]); $admin_user->set('field_text', 'Does not match'); $admin_user->save(); $this->drupalCreateNode([ 'title' => 'First', 'type' => 'page', 'status' => 1, 'field_text' => 'First', 'access_policy' => ['rules_with_no_query'], ]); $this->drupalCreateNode([ 'title' => 'Second', 'type' => 'page', 'status' => 1, 'field_text' => 'Second', 'access_policy' => ['rules_with_no_query'], ]); $this->drupalLogin($admin_user); // If query is enabled for the rules then these would not be visible. $this->drupalGet('admin/content'); $this->assertSession()->statusCodeEquals(200); $this->assertSession()->pageTextContains('First'); $this->assertSession()->pageTextContains('Second'); } /** * Tests that a listing displays entities when Access Rule query disabled. */ public function testContentListingWithAccessRulesQueryDisabled() { $policy = AccessPolicy::create([ 'id' => 'rules_with_disabled_query', 'label' => 'Test Access Policy with disabled rules', 'target_entity_type_id' => 'node', ]); $access_rule = $this->accessRuleManager->getHandler('node', 'field_text'); $access_rule->setSettings([ 'operator' => '=', 'value' => 'Does not match', 'query' => FALSE, ]); $policy->addHandler('access_rule', $access_rule); $policy->save(); $this->drupalCreateNode([ 'title' => 'First', 'type' => 'page', 'status' => 1, 'field_text' => 'Foo', 'access_policy' => ['rules_with_disabled_query'], ]); $this->drupalCreateNode([ 'title' => 'Second', 'type' => 'page', 'status' => 1, 'field_text' => 'Bar', 'access_policy' => ['rules_with_disabled_query'], ]); $admin_user = $this->drupalCreateUser([ 'access administration pages', 'access content overview', 'administer nodes', 'bypass node access', 'view rules_with_disabled_query content', ]); $this->drupalLogin($admin_user); // These are only visible because query is disabled, otherwise they would // be hidden. $this->drupalGet('admin/content'); $this->assertSession()->statusCodeEquals(200); $this->assertSession()->pageTextContains('First'); $this->assertSession()->pageTextContains('Second'); } /** * Test content listing for entities with multiple policies. */ public function testContentListingWithMultiplePolicies() { AccessPolicy::create([ 'id' => 'policy_1', 'label' => 'Policy 1', 'target_entity_type_id' => 'node', 'selection_set' => ['restricted'], ])->save(); AccessPolicy::create([ 'id' => 'policy_2', 'label' => 'Policy 2', 'target_entity_type_id' => 'node', 'selection_set' => ['restricted'], ])->save(); $admin_user = $this->drupalCreateUser([ 'access administration pages', 'access content overview', 'administer nodes', 'bypass node access', 'view policy_1 content', 'view policy_2 content', ]); $admin_user->save(); $this->drupalCreateNode([ 'title' => 'First', 'type' => 'page', 'status' => 1, 'access_policy' => ['policy_1', 'policy_2'], ]); $this->drupalLogin($admin_user); // If query is enabled for the rules then these would not be visible. $this->drupalGet('admin/content'); $this->assertSession()->statusCodeEquals(200); $this->assertSession()->pageTextContainsOnce('First'); } }