Drupal\flexible_permissions\CalculatedPermissionsScopeException: The calculator "Drupal\group\Access\IndividualGroupPermissionCalculator" returned permissions for scopes other than "individual".

Created on 11 August 2023, over 1 year ago
Updated 13 March 2024, 8 months ago

Problem/Motivation

Drupal\flexible_permissions\CalculatedPermissionsScopeException: The calculator "Drupal\group\Access\IndividualGroupPermissionCalculator" returned permissions for scopes other than "individual". in Drupal\flexible_permissions\ChainPermissionCalculator->calculatePermissions() (line 145 of modules/contrib/flexible_permissions/src/ChainPermissionCalculator.php).
Drupal\group\Access\GroupPermissionCalculator->calculateFullPermissions(Object) (Line: 111)
Drupal\group\Access\GroupPermissionsHashGenerator->getCacheableMetadata(Object) (Line: 64)
Drupal\group\Cache\Context\GroupPermissionsCacheContext->getCacheableMetadata(NULL) (Line: 184)
Drupal\Core\Cache\Context\CacheContextsManager->optimizeTokens(Array) (Line: 110)
Drupal\Core\Cache\Context\CacheContextsManager->convertTokensToKeys(Array) (Line: 317)
Drupal\Core\Render\RenderCache->createCacheID(Array) (Line: 66)
Drupal\Core\Render\RenderCache->get(Array) (Line: 109)
Drupal\Core\Render\PlaceholderingRenderCache->get(Array) (Line: 77)
Drupal\Core\Render\RenderCache->get(Array) (Line: 109)
Drupal\Core\Render\PlaceholderingRenderCache->get(Array) (Line: 273)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 449)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 474)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 43)
__TwigTemplate_90b274c18b5ed16271d37382bdfef1ad->doDisplay(Array, Array) (Line: 394)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 367)
Twig\Template->display(Array) (Line: 379)
Twig\Template->render(Array, Array) (Line: 40)
Twig\TemplateWrapper->render(Array) (Line: 53)
twig_render_template('core/themes/claro/templates/page.html.twig', Array) (Line: 372)
Drupal\Core\Theme\ThemeManager->render('page', Array) (Line: 436)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 474)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 86)
__TwigTemplate_fa304471f4e6dcd3005253b394dd2e80->doDisplay(Array, Array) (Line: 394)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 367)
Twig\Template->display(Array) (Line: 379)
Twig\Template->render(Array, Array) (Line: 40)
Twig\TemplateWrapper->render(Array) (Line: 53)
twig_render_template('core/themes/claro/templates/classy/layout/html.html.twig', Array) (Line: 372)
Drupal\Core\Theme\ThemeManager->render('html', Array) (Line: 436)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 158)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 583)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 159)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 111)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 171)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 74)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\StackedHttpKernel->handle(Object, 1, 1) (Line: 704)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

Steps to reproduce

1. Upgrade to Drupal 10.1.x
2. Install Group v2.1.x-dev@dev
3. Edit group roles and set to insider or outsider. /admin/group/types/manage/{group_type}/roles/{group_role}

💬 Support request
Status

Fixed

Version

3.2

Component

Code

Created by

🇵🇭Philippines _renify_ cebu

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @_renify_
  • 🇺🇸United States edward_nurelm

    I've also been having this issue for a number of weeks with very large Drupal site (running version 9) we build that is being upgraded from the group version 1 module to the version 2. It was originally built in Drupal 8 a few years ago. This issue is not specific to Drupal 10, but to Group 2 itself. Did you update your site from a previous group installation?

    I've narrowed down my problem to one role, we have a "Member" role that we had for a default member of a group. It has the role of "insider" with "authenticated user" as the global role. When I set it to "individual" rather than "insider", the site works. But I feel this isn't a solution; the roles page itself says "Insider: Assigned to all members who have the corresponding global role.". It would make sense to leave our "member" role as an insider.

    Basically, if any role in my group has the "insider" scope, it gets the error.

    I debugged the variables where the exception is happening:

    // Validate that only the requested scope was returned. An empty result
            // is allowed, however, as it might be that the calculator had nothing
            // to say for this scope.
            if (!empty($calculator_scopes) && (count($calculator_scopes) > 1 || reset($calculator_scopes) !== $scope)) {
              var_dump($scope); 
              var_dump($calculator_scopes); 
              exit;
              throw new CalculatedPermissionsScopeException(sprintf('The calculator "%s" returned permissions for scopes other than "%s".', get_class($calculator), $scope));
            }
    

    My site always seems to show $scope as having the value of individual. I'm not sure what's going on here, but it's difficult to work around. We have tons of custom code, but nothing that changes the scope of anything with flexible permissions. Can the devs please give suggestions for this? I feel like this exception is in place for a reason, but I'm not sure what is misconfigured on our website that cold be causing this.

  • 🇨🇦Canada bbombachini London, ON

    We were having the same issue and we figured out that the mapping of an insider role will not bypass an user that have the individual role assigned previously.

    As we've migrated from groups 1, we were used to have an Drupal user with a role "group_admin" for ex and we would assign the role to this user's membership as well. And here's comes the problem, if the Drupal user has the Drupal user role "group_admin" and also a role assigned "manually" (read individually) on its group membership.

    I think this could be resolved in a way to pass this check if the scope differs (in this case insider and individual) but the roles match.

  • First commit to issue fork.
  • Open in Jenkins → Open on Drupal.org →
    Core: 9.5.x + Environment: PHP 7.4 & MySQL 5.7
    last update about 1 year ago
    23 pass
  • @abhishek_virasat opened merge request.
  • Status changed to Needs review about 1 year ago
  • 🇮🇳India abhishek_virasat

    @_renify_ I have added changes that will fix the issue. please review the MR

  • 🇵🇭Philippines _renify_ cebu

    @abhishek_virasat sorry i'm not member for this module. I dont havee permission to merge.

    @mef @kristiaanvandeneynde
    Please review MR at #6. Thanks

  • 🇮🇳India abhishek_virasat

    @_renify_, thanks for response. but Im not saying to merge it. can you please take a pull from this branch and verify on your end. then move it to "Reviewed & tested by the community".

  • Status changed to RTBC about 1 year ago
  • 🇮🇳India naveenvalecha New Delhi

    This solved the above error for me.

  • Status changed to Needs work about 1 year ago
  • 🇧🇪Belgium kristiaanvandeneynde Antwerp, Belgium

    Closing the MR, why would we add Group-specific code in a module that Group depends on. This seems like a bug in Group, but all tests there go green and I haven't run into this problem myself, so I'd like you to double-check if any of your installed modules may affect the logic somehow.

  • 🇧🇪Belgium kristiaanvandeneynde Antwerp, Belgium

    FWIW, if you use XDebug on IndividualGroupPermissionCalculator and debug the roles retrieved from $group_membership->getRoles(FALSE), you should be able to figure out if any of them have a scope other than 'individual':

          foreach ($group_membership->getRoles(FALSE) as $group_role) {
            $item = new CalculatedPermissionsItem(
              $group_role->getScope(), // NOTE: This is likely where the bug happens, figure out why.
              $group_membership->getGroup()->id(),
              $group_role->getPermissions(),
              $group_role->isAdmin()
            );
            $calculated_permissions->addCacheableDependency($group_role);
            $calculated_permissions->addItem($item);
          }
    
  • 🇦🇺Australia thtas

    I've just run in to this and debugged as per your suggestion. the Role being returned in "group_membership->getRoles(FALSE)" above is the "[GROUP_TYPE]-member" role, and it has a scope of "insider". It has a number of permissions assigned to it.

    The site I'm working is in the process of moving from 1.5.0 to 2.2.1

  • 🇧🇪Belgium kristiaanvandeneynde Antwerp, Belgium

    Yeah that's your bug. You have an insider role assigned to someone, that should never happen as insider roles are dynamically applied based on your Drupal roles. Probably a relic from a failed migration or update hook.

    Make sure that no-one has any insider or outsider roles assigned to their membership and you should fix this bug.

  • 🇦🇺Australia thtas

    Indeed it was!

    My problem was occurring during integration tests, where for whatever reason we were adding the "member" role explicitly to group memberships during our test setup phase. There is no need to do this (there probably never was), and this caused the error here.

    Thank you for the quick response Kristian.

  • Status changed to Fixed about 1 year ago
  • 🇧🇪Belgium kristiaanvandeneynde Antwerp, Belgium

    Gonna go out on a limb here and assume that everyone is facing a similar issue. The top comment sure seems to point to that.

    Please do not assign insider/outsider roles to a membership via code. The UI does not allow it and it seems I need to throw an exception when someone tries to do so via code to prevent this type of situation.

  • Automatically closed - issue fixed for 2 weeks with no activity.

  • Status changed to Fixed 8 months ago
  • 🇺🇸United States RichardDavies Portland, Oregon

    I'm having a similar issue, but not sure if the problem is something on my end or a bug in Groups module. I'm upgrading a site which was using Groups 1.6 to 2.2. The site has the concept of an "public" group which any authenticated user can view without being a member. I've configured an Outsider scoped role that is synced with authenticated users to allow non members to view the group. There are also Outsider and Insider roles synced with the global administrator role so admins can manage all groups.

    If a user views a group and they're interested in it, they can "follow it" which means becoming a member and being assigned the "following" individual-scoped role. However, whenever a user tries to follow a group, they get the permission error mentioned in the original post. Group admins also get the error when they click the Add member button on a group and try to add themself with the "following" role. However, if they add any other user beside themself then they don't get the error.

    I've debugged the IndividualGroupPermissionCalculator as suggested and it is also returning an insider scoped role (either the "member" role synced with authenticated users or the administrator role synced with global admins). You said this means that "You have an insider role assigned to someone"... but I've looked at all of the groups that I'm a member of found one where I was assigned the "member" role and removed that role but I'm still getting the error. So does the error mean that the user being added to the group is assigned an insider role somewhere that I've missed somehow, or will I get the error if ANY user on the site is assigned an insider role (because it's possible we might have other others still assigned the "member" role)

  • 🇧🇪Belgium kristiaanvandeneynde Antwerp, Belgium

    If a user views a group and they're interested in it, they can "follow it" which means becoming a member and being assigned the "following" individual-scoped role.

    Don't do this merely for flagging, it's a significant performance hit once they join a large amount of groups. Insider roles are your best option here if you want to assign permissions.

    So does the error mean that the user being added to the group is assigned an insider role somewhere that I've missed somehow

    Most likely, yes.

    As this issue in particular was closed and the answer matched what you were seeing (role assigned incorrectly), I would suggest you try to track down why these roles are incorrectly assigned. If you find that it's Group doing this, then please open a new issue as a bug report and provide steps to reproduce. If it's custom code on your end, then there's nothing left to discuss here as you're basically confirming #15.

    I'm considering fixing this loophole in 3.3.0 even though, technically, it would be a BC break. But seeing how this breaks people's websites, I'm sure they wouldn't mind.

  • 🇺🇸United States RichardDavies Portland, Oregon

    Thank you, I finally got to the bottom of my issue. It was indeed caused by some of our custom code that maintains some automatic group memberships based on some data from the user's Active Directory profile. This code was calling Group::load($group_id)->getMember($account)->getRoles() which returns all roles, even our new insider/outsider roles, and then it was unintentionally assigning those roles to the user. Changing it to getRoles(FALSE) fixed the problem.

Production build 0.71.5 2024