ConfigFactoryOverrideInterface::loadOverrides not invoked after content type creation in Drupal 10.3.0+

Created on 25 July 2024, about 1 month ago
Updated 18 August 2024, 21 days ago

Problem/Motivation

In our Drupal site, we are extending ConfigFactoryOverrideInterface and overriding the loadOverrides function to assign permissions to a user role dynamically. This functionality works as expected in Drupal version 10.2.7. However, starting from Drupal version 10.3.0, the loadOverrides method is no longer invoked after creating a new content type, which causes our dynamic permission assignment to fail.

Steps to reproduce

Implement ConfigFactoryOverrideInterface and override the loadOverrides function to assign permissions to a user role dynamically.
Create a new content type, e.g., 'test_content'.

Observe that in Drupal 10.2.7, the loadOverrides method is invoked, and permissions are assigned correctly.
Upgrade to Drupal 10.3.0 or later.
Create the same content type 'test_content'.
Observe that the loadOverrides method is not invoked, and permissions are not assigned.

Starting from Drupal 10.3.0, the loadOverrides method is not invoked after creating a new content type, causing dynamic permission assignments to fail.

Code snippets demonstrating the ConfigFactoryOverrideInterface implementation.

 class PermissionOverrides implements ConfigFactoryOverrideInterface {

/**
  * {@inheritdoc}
  */
public function loadOverrides($names) {
  $overrides = [];
  $role = 'user.role.test_role';
  if (in_array($role, $names)) {
    $types = $this->entityTypeManager()->getStorage('node_type')->loadMultiple();
    foreach ($types as $type) {
      $permission = 'Test permission ' . $type->id();
      $overrides[$role]['permissions'][$permission] = $permission;
    }
  }

  return $overrides;
}

/**
 * @return string
 */
public function getCacheSuffix() {
  return static::class;
}

/**
 * @param string $name
 *
 * @return \Drupal\Core\Cache\CacheableMetadata
 */
public function getCacheableMetadata($name) {
  return new CacheableMetadata();
}

/**
 * @param mixed $name
 * @param string $collection
 *
 * @return \Drupal\Core\Config\StorableConfigBase|null
 */
public function createConfigObject($name, $collection = StorageInterface::DEFAULT_COLLECTION) {
  return NULL;
}

}

Code snippets for Content type creation.

$this->drupalCreateContentType(['type' => 'test_content', 'name' => 'test_content']);

Proposed resolution

The loadOverrides method should be invoked after creating a new content type, as it does in Drupal 10.2.7, to ensure dynamic permission assignments work correctly.

🐛 Bug report
Status

Active

Version

11.0 🔥

Component
Configuration 

Last updated 1 day ago

Created by

🇮🇳India ananthakrishnan.kr

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

Comments & Activities

  • Issue created by @ananthakrishnan.kr
  • public function getCacheSuffix() {
    return 'key_config_override';
    }

    Try changing return value of getCacheSuffix function and test it again.

  • 🇮🇳India ananthakrishnan.kr

    I tried changing return value of getCacheSuffix function. But still we have the issue.

  • 🇳🇿New Zealand quietone New Zealand

    Changes are made on on 11.x (our main development branch) first, and are then back ported as needed according to our policies.

  • 🇺🇸United States cilefen

    Can you execute a git bisect on a Git working copy of Drupal Core between 10.2.7 and 10.3.0 to quickly find the commit that changed this behavior?

  • 🇮🇳India nitesh624 Ranchi, India

    will git bisect show the code difference between these two versions?

  • 🇮🇳India nitesh624 Ranchi, India

    I ran the bisect between tags 10.2.7 and 10.3.1 by running below command
    git bisect start
    git bisect good tags/10.2.7
    git bisect bad tags/10.3.1

    then the commit which I get is setting the drupal core to 11.0-dev which leads to break testing.

  • 🇮🇳India nitesh624 Ranchi, India

    This https://git.drupalcode.org/project/drupal/-/commit/9bb46296cee3aa33a9750... is the commit on Mar 27, 2024 which causing our test to failure.

  • 🇧🇪Belgium kristiaanvandeneynde Antwerp, Belgium

    We never touched config overrides in that issue. The only thing that has changed is that we cache the outcome of your permission calculations, including the ones coming from roles, because that's the only way to safely do so.

    Altering permissions live is a security risk, the code in the IS is unsafe. I specifically designed the Access Policy API because I too needed alterable permissions but found out that dynamically changing what permissions a role has is an attack vector. I shall not go into further detail on that matter because you apparently have such code in your system.

    My advice would be to introduce an access policy to take care of whatever logic you had in your config overrides. Then it will work and be safe.

  • I'm actually having a similar problem in my project...

    We have some functionality that allows an anonymous user to view an unpublished page via a URL hash. We have an existing functional test that basically visits an unpublished page (say node/1) and we check for a 403. Then we visit the page again with the hash as part of the URL node/1?hash=validHashHere and check for a 200. We are now receiving a 403 after the 10.3.1 update.

    It seems that the above commit in question definitely has something to do with it (especially with the addition of permissionsHashGenerator in AccountPermissionsCacheContext.php). Still debugging though...

  • 🇮🇳India nitesh624 Ranchi, India

    I have update my custom code to assign permission through access policy but facing same issue

  • 🇮🇳India nitesh624 Ranchi, India

    Here is my code snippet
    -> custom_access/src/Access/AccessUnpublishedPermission.php

    <?php
    
    namespace Drupal\custom_access\Access;
    
    use Drupal\Core\Session\AccessPolicyBase;
    use Drupal\Core\Session\AccountInterface;
    use Drupal\Core\Session\CalculatedPermissionsItem;
    use Drupal\Core\Session\RefinableCalculatedPermissionsInterface;
    
    /**
     * Using the access policy API to allow  users to view unpublished content.
     */
    class AccessUnpublishedPermission extends AccessPolicyBase {
    
      /**
       * {@inheritdoc}
       */
      public function calculatePermissions(AccountInterface $account, string $scope): RefinableCalculatedPermissionsInterface {
        $calculated_permissions = parent::calculatePermissions($account, $scope);
        $types = \Drupal::entityTypeManager()->getStorage('node_type')->loadMultiple();
        $permission = [];
        foreach ($types as $type) {
          $permission[] = 'access_unpublished node ' . $type->id();
        }
    
        // If we aren't an anonymous user, return early.
        if (!in_array('anonymous', $account->getRoles())) {
          return $calculated_permissions;
        }
    
        return $calculated_permissions->addItem(new CalculatedPermissionsItem($permission));
      }
    
      public function getPersistentCacheContexts(): array {
        return ['user.roles:anonymous'];
      }
    
    }
    

    -> custom_access.services.yml

    services:
      custom_access.access_policy.access_unpublished_permission:
        class: Drupal\custom_access\Access\AccessUnpublishedPermission
        tags:
          - { name: access_policy }
    

    Then in Functional Test I am creating a test content type like below
    $this->drupalCreateContentType(['type' => 'test_content', 'name' => 'test_content']);

    The problem is after creating the content type like this in test, \Drupal::entityTypeManager()->getStorage('node_type')->loadMultiple();
    service in AccessUnpublishedPermission.php file does not include the test_content content type

Production build 0.71.5 2024