Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More intellegent access control #470

Merged
merged 40 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
5adabcd
Start on #464: enabling and disabling modules and access to their con…
ekes May 26, 2024
e730977
Add logging out to trait.
ekes May 26, 2024
c0d5d8b
Switch to use group_sites access providers to supply permissions.
ekes May 28, 2024
ea512a0
Test broke in 10.3 because of new logout route option for CSRF.
ekes May 28, 2024
9558a4b
Merge branch 'feature/group_context_domain_1_0_0' into feature/464-ac…
ekes May 28, 2024
2fe816e
Remove unnecessary (wrong type) translation.
ekes May 28, 2024
dc0b1d3
Who knows maybe this works with 10.2 otherwise it's 10.3 only.
ekes May 28, 2024
6fa126e
Move shared relationship into optional.
ekes May 30, 2024
12ce439
Fuller check of permissions paths.
ekes May 30, 2024
7fdc512
Merge branch 'feature/464-access-tests-enable-disable-modules' into f…
ekes May 30, 2024
f4daa51
Add "all" (not quite see comment) admin paths checks.
ekes May 30, 2024
c431e8d
See if we can test on github against 10.3
ekes May 30, 2024
458a902
Test now covers all access by content type options.
ekes Jun 1, 2024
56192c1
Upgrade configuration for existing sites.
ekes Jun 1, 2024
2ac7b31
Add "all" (not quite see comment) admin paths checks.
ekes May 30, 2024
f990bda
See if we can test on github against 10.3
ekes May 30, 2024
f79fcd3
Test now covers all access by content type options.
ekes Jun 1, 2024
54bf8bf
Add blogs tests (and remove permissions not available from module).
ekes Jun 1, 2024
02bad63
Add blogs tests (and remove permissions not available from module).
ekes Jun 1, 2024
31ec617
Merge branch 'feature/tests-microsite-blogs' into feature/464-access-…
ekes Jun 1, 2024
4d2f3ee
Merge branch 'feature/464-access-tests-enable-disable-modules' into f…
ekes Jun 1, 2024
10de358
Switch branch used for installing microsites to one that installs 10.3
ekes Jun 5, 2024
8154fc5
It's a composer require string?
ekes Jun 5, 2024
424427c
Oops, pay attention to the branch names.
ekes Jun 5, 2024
5ca117f
Script is adding -dev, but it didn't seem to work before. Maybe just …
ekes Jun 5, 2024
45feacd
Fixing Github Actions
stephen-cox Jun 6, 2024
9a6a367
Merge branch 'feature/464-access-tests-enable-disable-modules' into f…
ekes Jun 7, 2024
fc8ca78
Merged 4.x
stephen-cox Jun 11, 2024
f40252e
Merged 4.x
stephen-cox Jun 11, 2024
2f804ae
Coding standards fixes
stephen-cox Jul 12, 2024
443a80f
Merge branch 'feature/464-access-tests-enable-disable-modules' into f…
FinnERLewis Jul 16, 2024
5850c57
Fix some coding standards.
FinnERLewis Jul 16, 2024
1d561fc
Rework attempt for rendering and listing of themes to remove deprecat…
FinnERLewis Jul 17, 2024
2c2f2cf
Move to using constructor property promotion, advised by ru and ekes.
FinnERLewis Jul 18, 2024
f195c90
Refactor to use dependency injection.
FinnERLewis Jul 18, 2024
d9317fa
Fix naming of variables / properties.
FinnERLewis Jul 18, 2024
9aa9e0a
Merge pull request #488 from localgovdrupal/feature/464-access-disabl…
finnlewis Jul 18, 2024
cf255f1
Fix missing argument for localgov_microsites_group.microsite_content_…
FinnERLewis Jul 18, 2024
df7e6e9
Add missing extension.list.theme to create method.
FinnERLewis Jul 18, 2024
7ca79d7
Fix typos in call to moduleHandler.
FinnERLewis Jul 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions localgov_microsites_group.install
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ function localgov_microsites_group_install($is_syncing) {
// can't, but must update its default config.
$group_sites = \Drupal::configFactory()->getEditable('group_sites.settings');
$group_sites->set('context_provider', '@group_context_domain.group_from_domain_context:group');
$group_sites->set('no_site_access_policy', 'localgov_microsites_group.control_site_access_policy');
$group_sites->set('site_access_policy', 'localgov_microsites_group.microsite_content_types_access_policy');
$group_sites->save();

// Add domain access to exclude other sites results.
Expand Down Expand Up @@ -96,3 +98,13 @@ function localgov_microsites_group_update_9008() {
$group_sites->set('context_provider', '@group_context_domain.group_from_domain_context:group');
$group_sites->save();
}

/**
* Switch to new custom group sites access handlers.
*/
function localgov_microsites_group_update_9009() {
$group_sites = \Drupal::configFactory()->getEditable('group_sites.settings');
$group_sites->set('no_site_access_policy', 'localgov_microsites_group.control_site_access_policy');
$group_sites->set('site_access_policy', 'localgov_microsites_group.microsite_content_types_access_policy');
$group_sites->save();
}
10 changes: 10 additions & 0 deletions localgov_microsites_group.module
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,16 @@ function localgov_microsites_group_toolbar() {
];
}

/**
* Implements hook_toolbar_alter().
*/
function localgov_microsites_group_toolbar_alter(&$items) {
// The control site access provider gives admin mode there.
// Decide to also hide from microsites, so the control site is the admin site
// with our custom permissions.
unset($items['group_sites']);
}

/**
* Implements hook_localgov_microsites_roles_default().
*/
Expand Down
23 changes: 9 additions & 14 deletions localgov_microsites_group.services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,16 @@ services:
tags:
- { name: event_subscriber }

localgov_microsites_group.site_admin_mode:
class: Drupal\localgov_microsites_group\EventSubscriber\SiteAdminMode
arguments: ['@domain.negotiator', '@group_sites.admin_mode']
localgov_microsites_group.microsite_content_types_access_policy:
class: 'Drupal\localgov_microsites_group\Access\MicrositeContentTypesAccessPolicy'
arguments: ['@group_sites.admin_mode', '@flexible_permissions.chain_calculator', '@module_handler']
tags:
- { name: event_subscriber }
- { name: group_sites_site_access_policy, priority: 10 }

localgov_microsites_group.control_site_access_policy:
class: 'Drupal\localgov_microsites_group\Access\ControlSiteAccessPolicy'
tags:
- { name: group_sites_no_site_access_policy, priority: 10 }

domain_group_resolver:
class: Drupal\localgov_microsites_group\DomainGroupResolver
Expand All @@ -68,13 +73,3 @@ services:
tags:
- { name: 'context_provider' }
deprecated: 'The "%service_id%" service is deprecated. You should use the group sites context directly instead.'

group.relation_handler.access_control.group_node:
class: 'Drupal\localgov_microsites_group\Plugin\Group\RelationHandler\ContentTypeAccessControl'
arguments: ['@group.relation_handler.access_control', '@localgov_microsites_group.content_type_helper']
shared: false

group.relation_handler.access_control.group_term:
class: 'Drupal\localgov_microsites_group\Plugin\Group\RelationHandler\ContentTypeAccessControl'
arguments: ['@group.relation_handler.access_control', '@localgov_microsites_group.content_type_helper']
shared: false
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,6 @@ function localgov_microsites_blogs_modules_installed($modules) {
*/
function localgov_microsites_blogs_localgov_microsites_roles_default() {
return [
'global' => [
RolesHelper::MICROSITES_CONTROLLER_ROLE => [
'view directory facets',
],
RolesHelper::MICROSITES_EDITOR_ROLE => [
'view directory facets',
],
],
'group' => [
RolesHelper::GROUP_ADMIN_ROLE => [
'access group_term overview',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
<?php

namespace Drupal\Tests\localgov_microsites_blogs\Functional;

use Drupal\group\Entity\GroupInterface;
use Drupal\localgov_microsites_group\DomainFromGroupTrait;
use Drupal\node\NodeInterface;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\localgov_microsites_group\Traits\GroupCreationTrait;
use Drupal\Tests\localgov_microsites_group\Traits\InitializeGroupsTrait;
use Drupal\Tests\node\Traits\NodeCreationTrait;

/**
* Tests channel content in a group.
*
* @group localgov_microsites_group
*/
class MicrositeBlogsContentTest extends BrowserTestBase {

use InitializeGroupsTrait;
use NodeCreationTrait;
use GroupCreationTrait, DomainFromGroupTrait {
GroupCreationTrait::getEntityTypeManager insteadof DomainFromGroupTrait;
}

/**
* Will be removed when issue #3204455 on Domain Site Settings gets merged.
*
* See https://www.drupal.org/project/domain_site_settings/issues/3204455.
*
* @var bool
*
* @see \Drupal\Core\Config\Development\ConfigSchemaChecker
* phpcs:disable DrupalPractice.Objects.StrictSchemaDisabled.StrictConfigSchema
*/
protected $strictConfigSchema = FALSE;

/**
* {@inheritdoc}
*/
protected $profile = 'testing';

/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';

/**
* {@inheritdoc}
*/
protected static $modules = [
'localgov_microsites_blogs',
];

/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();

$this->createMicrositeGroups([], 2);
$this->createMicrositeGroupsDomains($this->groups);
$this->domain1 = $this->getDomainFromGroup($this->groups[1]);
$this->domain2 = $this->getDomainFromGroup($this->groups[2]);

// Create some channel content.
$this->blog_channel1 = $this->createBlogChannel($this->groups[1]);
$this->post1 = $this->createBlogPosts($this->blog_channel1, $this->groups[1], 2);
$this->blog_channel2 = $this->createBlogChannel($this->groups[2]);
$this->post2 = $this->createBlogPosts($this->blog_channel2, $this->groups[2], 2);
}

/**
* Test content appears on the correct site.
*/
public function testMicrositeblogContent() {

// Check content appears on the correct sites.
$this->drupalGet($this->domain1->getUrl() . $this->blog_channel1->toUrl()->toString());
$this->assertSession()->pageTextContains($this->post1[0]->label());
$this->assertSession()->pageTextContains($this->post1[1]->label());
$this->assertSession()->pageTextNotContains($this->post2[0]->label());
$this->assertSession()->pageTextNotContains($this->post2[1]->label());

$this->drupalGet($this->domain2->getUrl() . $this->blog_channel2->toUrl()->toString());
$this->assertSession()->pageTextContains($this->post2[0]->label());
$this->assertSession()->pageTextContains($this->post2[1]->label());
$this->assertSession()->pageTextNotContains($this->post1[0]->label());
$this->assertSession()->pageTextNotContains($this->post1[1]->label());
}

/**
* Create blog channel in group.
*
* @param \Drupal\group\Entity\GroupInterface $group
* Group to create blog_channel in.
*
* @return \Drupal\node\NodeInterface
* The blog_channel.
*/
protected function createBlogChannel(GroupInterface $group) {

$channel = $this->createNode([
'type' => 'localgov_blog_channel',
'title' => $this->randomMachineName(12),
'status' => NodeInterface::PUBLISHED,
]);
$channel->save();
$group->addRelationship($channel, 'group_node:localgov_blog_channel');

return $channel;
}

/**
* Create count blog posts in blog channel and group.
*
* @param \Drupal\node\NodeInterface $channel
* Blog channel to create posts in.
* @param \Drupal\group\Entity\GroupInterface $group
* Group to create post in.
* @param int $count
* Number of blog post to create.
*
* @return \Drupal\node\NodeInterface[]
* Array of blog posts.
*/
protected function createBlogPosts(NodeInterface $channel, GroupInterface $group, int $count) {
$posts = [];

for ($i = 0; $i < $count; $i++) {
$post = $this->createNode([
'type' => 'localgov_blog_post',
'title' => $this->randomMachineName(12),
'localgov_blog_channel' => [
'target_id' => $channel->id(),
],
'status' => NodeInterface::PUBLISHED,
]);
$post->save();
$group->addRelationship($post, 'group_node:localgov_blog_post');
$posts[] = $post;
}

return $posts;
}

}
77 changes: 77 additions & 0 deletions src/Access/ControlSiteAccessPolicy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

namespace Drupal\localgov_microsites_group\Access;

use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\flexible_permissions\CalculatedPermissionsItem;
use Drupal\flexible_permissions\RefinableCalculatedPermissionsInterface;
use Drupal\group\PermissionScopeInterface;
use Drupal\group_sites\Access\GroupSitesNoSiteAccessPolicyInterface;

/**
* Access policy for control site.
*/
class ControlSiteAccessPolicy implements GroupSitesNoSiteAccessPolicyInterface {

use StringTranslationTrait;

/**
* {@inheritdoc}
*/
public function getLabel(): string {
return $this->t('Localgov Microsites Control Site');
}

/**
* {@inheritdoc}
*/
public function getDescription(): string {
return $this->t('Prevent most content: nodes, media, etc being created on the control site.');
}

/**
* {@inheritdoc}
*/
public function alterPermissions(AccountInterface $account, string $scope, RefinableCalculatedPermissionsInterface $calculated_permissions) {
// User will probably have permissions for groups.
// Eg. as Outsider with Controller role.
// We might even want to switch off admin and replace with specific
// permissions to prevent doing group content on control.
if ($scope === PermissionScopeInterface::INDIVIDUAL_ID) {
$items = $calculated_permissions->getItemsByScope($scope);
foreach ($items as $item) {
$permissions = $item->getPermissions();
// Permissions to maintain on the control site.
// @todo add control site specific permissions.
$keep = [
'administer group domain site settings',
'administer members',
'edit group',
'invite users to group',
'manage microsite enabled module permissions',
'set localgov microsite theme override',
'view any unpublished group',
'view group',
'view group invitations',
'view latest group version',
'view own unpublished group',
];
$permissions = array_intersect($permissions, $keep);

$control_site_item = new CalculatedPermissionsItem(
$scope,
$item->getIdentifier(),
$permissions,
$item->isAdmin()
);
$calculated_permissions->addItem($control_site_item, TRUE);
}
}
else {
// Neither standard insider nor outside permissions should be required.
$calculated_permissions->removeItemsByScope($scope);
}
}

}
Loading
Loading