You are here

class PermissionsHashGenerator in Drupal 9

Same name and namespace in other branches
  1. 8 core/lib/Drupal/Core/Session/PermissionsHashGenerator.php \Drupal\Core\Session\PermissionsHashGenerator

Generates and caches the permissions hash for a user.

Hierarchy

Expanded class hierarchy of PermissionsHashGenerator

1 file declares its use of PermissionsHashGenerator
PermissionsHashGeneratorTest.php in core/tests/Drupal/Tests/Core/Session/PermissionsHashGeneratorTest.php
1 string reference to 'PermissionsHashGenerator'
core.services.yml in core/core.services.yml
core/core.services.yml
1 service uses PermissionsHashGenerator
user_permissions_hash_generator in core/core.services.yml
Drupal\Core\Session\PermissionsHashGenerator

File

core/lib/Drupal/Core/Session/PermissionsHashGenerator.php, line 13

Namespace

Drupal\Core\Session
View source
class PermissionsHashGenerator implements PermissionsHashGeneratorInterface {

  /**
   * The private key service.
   *
   * @var \Drupal\Core\PrivateKey
   */
  protected $privateKey;

  /**
   * The cache backend interface to use for the persistent cache.
   *
   * @var \Drupal\Core\Cache\CacheBackendInterface
   */
  protected $cache;

  /**
   * The cache backend interface to use for the static cache.
   *
   * @var \Drupal\Core\Cache\CacheBackendInterface
   */
  protected $static;

  /**
   * Constructs a PermissionsHashGenerator object.
   *
   * @param \Drupal\Core\PrivateKey $private_key
   *   The private key service.
   * @param \Drupal\Core\Cache\CacheBackendInterface $cache
   *   The cache backend interface to use for the persistent cache.
   * @param \Drupal\Core\Cache\CacheBackendInterface $static
   *   The cache backend interface to use for the static cache.
   */
  public function __construct(PrivateKey $private_key, CacheBackendInterface $cache, CacheBackendInterface $static) {
    $this->privateKey = $private_key;
    $this->cache = $cache;
    $this->static = $static;
  }

  /**
   * {@inheritdoc}
   *
   * Cached by role, invalidated whenever permissions change.
   */
  public function generate(AccountInterface $account) {

    // User 1 is the super user, and can always access all permissions. Use a
    // different, unique identifier for the hash.
    if ($account
      ->id() == 1) {
      return $this
        ->hash('is-super-user');
    }
    $sorted_roles = $account
      ->getRoles();
    sort($sorted_roles);
    $role_list = implode(',', $sorted_roles);
    $cid = "user_permissions_hash:{$role_list}";
    if ($static_cache = $this->static
      ->get($cid)) {
      return $static_cache->data;
    }
    else {
      $tags = Cache::buildTags('config:user.role', $sorted_roles, '.');
      if ($cache = $this->cache
        ->get($cid)) {
        $permissions_hash = $cache->data;
      }
      else {
        $permissions_hash = $this
          ->doGenerate($sorted_roles);
        $this->cache
          ->set($cid, $permissions_hash, Cache::PERMANENT, $tags);
      }
      $this->static
        ->set($cid, $permissions_hash, Cache::PERMANENT, $tags);
    }
    return $permissions_hash;
  }

  /**
   * Generates a hash that uniquely identifies the user's permissions.
   *
   * @param string[] $roles
   *   The user's roles.
   *
   * @return string
   *   The permissions hash.
   */
  protected function doGenerate(array $roles) {

    // @todo Once Drupal gets rid of user_role_permissions(), we should be able
    // to inject the user role controller and call a method on that instead.
    $permissions_by_role = user_role_permissions($roles);
    foreach ($permissions_by_role as $role => $permissions) {
      sort($permissions);

      // Note that for admin roles (\Drupal\user\RoleInterface::isAdmin()), the
      // permissions returned will be empty ($permissions = []). Therefore the
      // presence of the role ID as a key in $permissions_by_role is essential
      // to ensure that the hash correctly recognizes admin roles. (If the hash
      // was based solely on the union of $permissions, the admin roles would
      // effectively be no-ops, allowing for hash collisions.)
      $permissions_by_role[$role] = $permissions;
    }
    return $this
      ->hash(serialize($permissions_by_role));
  }

  /**
   * Hashes the given string.
   *
   * @param string $identifier
   *   The string to be hashed.
   *
   * @return string
   *   The hash.
   */
  protected function hash($identifier) {
    return hash('sha256', $this->privateKey
      ->get() . Settings::getHashSalt() . $identifier);
  }

}

Members

Namesort descending Modifiers Type Description Overrides
PermissionsHashGenerator::$cache protected property The cache backend interface to use for the persistent cache.
PermissionsHashGenerator::$privateKey protected property The private key service.
PermissionsHashGenerator::$static protected property The cache backend interface to use for the static cache.
PermissionsHashGenerator::doGenerate protected function Generates a hash that uniquely identifies the user's permissions.
PermissionsHashGenerator::generate public function Cached by role, invalidated whenever permissions change. Overrides PermissionsHashGeneratorInterface::generate
PermissionsHashGenerator::hash protected function Hashes the given string.
PermissionsHashGenerator::__construct public function Constructs a PermissionsHashGenerator object.