Upgraded drupal core with security updates
[yaffs-website] / web / core / lib / Drupal / Core / Session / PermissionsHashGenerator.php
1 <?php
2
3 namespace Drupal\Core\Session;
4
5 use Drupal\Core\PrivateKey;
6 use Drupal\Core\Cache\Cache;
7 use Drupal\Core\Cache\CacheBackendInterface;
8 use Drupal\Core\Site\Settings;
9
10 /**
11  * Generates and caches the permissions hash for a user.
12  */
13 class PermissionsHashGenerator implements PermissionsHashGeneratorInterface {
14
15   /**
16    * The private key service.
17    *
18    * @var \Drupal\Core\PrivateKey
19    */
20   protected $privateKey;
21
22   /**
23    * The cache backend interface to use for the persistent cache.
24    *
25    * @var \Drupal\Core\Cache\CacheBackendInterface
26    */
27   protected $cache;
28
29   /**
30    * The cache backend interface to use for the static cache.
31    *
32    * @var \Drupal\Core\Cache\CacheBackendInterface
33    */
34   protected $static;
35
36   /**
37    * Constructs a PermissionsHashGenerator object.
38    *
39    * @param \Drupal\Core\PrivateKey $private_key
40    *   The private key service.
41    * @param \Drupal\Core\Cache\CacheBackendInterface $cache
42    *   The cache backend interface to use for the persistent cache.
43    * @param \Drupal\Core\Cache\CacheBackendInterface $static
44    *   The cache backend interface to use for the static cache.
45    */
46   public function __construct(PrivateKey $private_key, CacheBackendInterface $cache, CacheBackendInterface $static) {
47     $this->privateKey = $private_key;
48     $this->cache = $cache;
49     $this->static = $static;
50   }
51
52   /**
53    * {@inheritdoc}
54    *
55    * Cached by role, invalidated whenever permissions change.
56    */
57   public function generate(AccountInterface $account) {
58     // User 1 is the super user, and can always access all permissions. Use a
59     // different, unique identifier for the hash.
60     if ($account->id() == 1) {
61       return $this->hash('is-super-user');
62     }
63
64     $sorted_roles = $account->getRoles();
65     sort($sorted_roles);
66     $role_list = implode(',', $sorted_roles);
67     $cid = "user_permissions_hash:$role_list";
68     if ($static_cache = $this->static->get($cid)) {
69       return $static_cache->data;
70     }
71     else {
72       $tags = Cache::buildTags('config:user.role', $sorted_roles, '.');
73       if ($cache = $this->cache->get($cid)) {
74         $permissions_hash = $cache->data;
75       }
76       else {
77         $permissions_hash = $this->doGenerate($sorted_roles);
78         $this->cache->set($cid, $permissions_hash, Cache::PERMANENT, $tags);
79       }
80       $this->static->set($cid, $permissions_hash, Cache::PERMANENT, $tags);
81     }
82
83     return $permissions_hash;
84   }
85
86   /**
87    * Generates a hash that uniquely identifies the user's permissions.
88    *
89    * @param string[] $roles
90    *   The user's roles.
91    *
92    * @return string
93    *   The permissions hash.
94    */
95   protected function doGenerate(array $roles) {
96     // @todo Once Drupal gets rid of user_role_permissions(), we should be able
97     // to inject the user role controller and call a method on that instead.
98     $permissions_by_role = user_role_permissions($roles);
99     foreach ($permissions_by_role as $role => $permissions) {
100       sort($permissions);
101       // Note that for admin roles (\Drupal\user\RoleInterface::isAdmin()), the
102       // permissions returned will be empty ($permissions = []). Therefore the
103       // presence of the role ID as a key in $permissions_by_role is essential
104       // to ensure that the hash correctly recognizes admin roles. (If the hash
105       // was based solely on the union of $permissions, the admin roles would
106       // effectively be no-ops, allowing for hash collisions.)
107       $permissions_by_role[$role] = $permissions;
108     }
109     return $this->hash(serialize($permissions_by_role));
110   }
111
112   /**
113    * Hashes the given string.
114    *
115    * @param string $identifier
116    *   The string to be hashed.
117    *
118    * @return string
119    *   The hash.
120    */
121   protected function hash($identifier) {
122     return hash('sha256', $this->privateKey->get() . Settings::getHashSalt() . $identifier);
123   }
124
125 }