[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/vendor/web-token/jwt-core/ -> JWKSet.php (source)

   1  <?php
   2  
   3  declare(strict_types=1);
   4  
   5  /*
   6   * The MIT License (MIT)
   7   *
   8   * Copyright (c) 2014-2020 Spomky-Labs
   9   *
  10   * This software may be modified and distributed under the terms
  11   * of the MIT license.  See the LICENSE file for details.
  12   */
  13  
  14  namespace Jose\Component\Core;
  15  
  16  use function array_key_exists;
  17  use ArrayIterator;
  18  use function count;
  19  use Countable;
  20  use function in_array;
  21  use InvalidArgumentException;
  22  use function is_array;
  23  use IteratorAggregate;
  24  use JsonSerializable;
  25  use Traversable;
  26  
  27  class JWKSet implements Countable, IteratorAggregate, JsonSerializable
  28  {
  29      /**
  30       * @var array
  31       */
  32      private $keys = [];
  33  
  34      /**
  35       * @param JWK[] $keys
  36       *
  37       * @throws InvalidArgumentException if the list is invalid
  38       */
  39      public function __construct(array $keys)
  40      {
  41          foreach ($keys as $k => $key) {
  42              if (!$key instanceof JWK) {
  43                  throw new InvalidArgumentException('Invalid list. Should only contains JWK objects');
  44              }
  45  
  46              if ($key->has('kid')) {
  47                  unset($keys[$k]);
  48                  $this->keys[$key->get('kid')] = $key;
  49              } else {
  50                  $this->keys[] = $key;
  51              }
  52          }
  53      }
  54  
  55      /**
  56       * Creates a JWKSet object using the given values.
  57       *
  58       * @throws InvalidArgumentException if the keyset is not valid
  59       *
  60       * @return JWKSet
  61       */
  62      public static function createFromKeyData(array $data): self
  63      {
  64          if (!isset($data['keys'])) {
  65              throw new InvalidArgumentException('Invalid data.');
  66          }
  67          if (!is_array($data['keys'])) {
  68              throw new InvalidArgumentException('Invalid data.');
  69          }
  70  
  71          $jwkset = new self([]);
  72          foreach ($data['keys'] as $key) {
  73              $jwk = new JWK($key);
  74              if ($jwk->has('kid')) {
  75                  $jwkset->keys[$jwk->get('kid')] = $jwk;
  76              } else {
  77                  $jwkset->keys[] = $jwk;
  78              }
  79          }
  80  
  81          return $jwkset;
  82      }
  83  
  84      /**
  85       * Creates a JWKSet object using the given Json string.
  86       *
  87       * @throws InvalidArgumentException if the data is not valid
  88       *
  89       * @return JWKSet
  90       */
  91      public static function createFromJson(string $json): self
  92      {
  93          $data = json_decode($json, true);
  94          if (!is_array($data)) {
  95              throw new InvalidArgumentException('Invalid argument.');
  96          }
  97  
  98          return self::createFromKeyData($data);
  99      }
 100  
 101      /**
 102       * Returns an array of keys stored in the key set.
 103       *
 104       * @return JWK[]
 105       */
 106      public function all(): array
 107      {
 108          return $this->keys;
 109      }
 110  
 111      /**
 112       * Add key to store in the key set.
 113       * This method is immutable and will return a new object.
 114       *
 115       * @return JWKSet
 116       */
 117      public function with(JWK $jwk): self
 118      {
 119          $clone = clone $this;
 120  
 121          if ($jwk->has('kid')) {
 122              $clone->keys[$jwk->get('kid')] = $jwk;
 123          } else {
 124              $clone->keys[] = $jwk;
 125          }
 126  
 127          return $clone;
 128      }
 129  
 130      /**
 131       * Remove key from the key set.
 132       * This method is immutable and will return a new object.
 133       *
 134       * @param int|string $key Key to remove from the key set
 135       *
 136       * @return JWKSet
 137       */
 138      public function without($key): self
 139      {
 140          if (!$this->has($key)) {
 141              return $this;
 142          }
 143  
 144          $clone = clone $this;
 145          unset($clone->keys[$key]);
 146  
 147          return $clone;
 148      }
 149  
 150      /**
 151       * Returns true if the key set contains a key with the given index.
 152       *
 153       * @param int|string $index
 154       */
 155      public function has($index): bool
 156      {
 157          return array_key_exists($index, $this->keys);
 158      }
 159  
 160      /**
 161       * Returns the key with the given index. Throws an exception if the index is not present in the key store.
 162       *
 163       * @param int|string $index
 164       *
 165       * @throws InvalidArgumentException if the index is not defined
 166       */
 167      public function get($index): JWK
 168      {
 169          if (!$this->has($index)) {
 170              throw new InvalidArgumentException('Undefined index.');
 171          }
 172  
 173          return $this->keys[$index];
 174      }
 175  
 176      /**
 177       * Returns the values to be serialized.
 178       */
 179      public function jsonSerialize(): array
 180      {
 181          return ['keys' => array_values($this->keys)];
 182      }
 183  
 184      /**
 185       * Returns the number of keys in the key set.
 186       *
 187       * @param int $mode
 188       */
 189      public function count($mode = COUNT_NORMAL): int
 190      {
 191          return count($this->keys, $mode);
 192      }
 193  
 194      /**
 195       * Try to find a key that fits on the selected requirements.
 196       * Returns null if not found.
 197       *
 198       * @param string         $type         Must be 'sig' (signature) or 'enc' (encryption)
 199       * @param null|Algorithm $algorithm    Specifies the algorithm to be used
 200       * @param array          $restrictions More restrictions such as 'kid' or 'kty'
 201       *
 202       * @throws InvalidArgumentException if the key type is not valid (must be "sig" or "enc")
 203       */
 204      public function selectKey(string $type, ?Algorithm $algorithm = null, array $restrictions = []): ?JWK
 205      {
 206          if (!in_array($type, ['enc', 'sig'], true)) {
 207              throw new InvalidArgumentException('Allowed key types are "sig" or "enc".');
 208          }
 209  
 210          $result = [];
 211          foreach ($this->keys as $key) {
 212              $ind = 0;
 213  
 214              $can_use = $this->canKeyBeUsedFor($type, $key);
 215              if (false === $can_use) {
 216                  continue;
 217              }
 218              $ind += $can_use;
 219  
 220              $alg = $this->canKeyBeUsedWithAlgorithm($algorithm, $key);
 221              if (false === $alg) {
 222                  continue;
 223              }
 224              $ind += $alg;
 225  
 226              if (false === $this->doesKeySatisfyRestrictions($restrictions, $key)) {
 227                  continue;
 228              }
 229  
 230              $result[] = ['key' => $key, 'ind' => $ind];
 231          }
 232  
 233          if (0 === count($result)) {
 234              return null;
 235          }
 236  
 237          usort($result, [$this, 'sortKeys']);
 238  
 239          return $result[0]['key'];
 240      }
 241  
 242      /**
 243       * Internal method only. Should not be used.
 244       *
 245       * @internal
 246       * @internal
 247       */
 248      public static function sortKeys(array $a, array $b): int
 249      {
 250          if ($a['ind'] === $b['ind']) {
 251              return 0;
 252          }
 253  
 254          return ($a['ind'] > $b['ind']) ? -1 : 1;
 255      }
 256  
 257      /**
 258       * Internal method only. Should not be used.
 259       *
 260       * @internal
 261       */
 262      public function getIterator(): Traversable
 263      {
 264          return new ArrayIterator($this->keys);
 265      }
 266  
 267      /**
 268       * @throws InvalidArgumentException if the key does not fulfill with the "key_ops" constraint
 269       *
 270       * @return bool|int
 271       */
 272      private function canKeyBeUsedFor(string $type, JWK $key)
 273      {
 274          if ($key->has('use')) {
 275              return $type === $key->get('use') ? 1 : false;
 276          }
 277          if ($key->has('key_ops')) {
 278              $key_ops = $key->get('key_ops');
 279              if (!is_array($key_ops)) {
 280                  throw new InvalidArgumentException('Invalid key parameter "key_ops". Should be a list of key operations');
 281              }
 282  
 283              return $type === self::convertKeyOpsToKeyUse($key_ops) ? 1 : false;
 284          }
 285  
 286          return 0;
 287      }
 288  
 289      /**
 290       * @return bool|int
 291       */
 292      private function canKeyBeUsedWithAlgorithm(?Algorithm $algorithm, JWK $key)
 293      {
 294          if (null === $algorithm) {
 295              return 0;
 296          }
 297          if (!in_array($key->get('kty'), $algorithm->allowedKeyTypes(), true)) {
 298              return false;
 299          }
 300          if ($key->has('alg')) {
 301              return $algorithm->name() === $key->get('alg') ? 2 : false;
 302          }
 303  
 304          return 1;
 305      }
 306  
 307      private function doesKeySatisfyRestrictions(array $restrictions, JWK $key): bool
 308      {
 309          foreach ($restrictions as $k => $v) {
 310              if (!$key->has($k) || $v !== $key->get($k)) {
 311                  return false;
 312              }
 313          }
 314  
 315          return true;
 316      }
 317  
 318      /**
 319       * @throws InvalidArgumentException if the key operation is not supported
 320       */
 321      private static function convertKeyOpsToKeyUse(array $key_ops): string
 322      {
 323          switch (true) {
 324              case in_array('verify', $key_ops, true):
 325              case in_array('sign', $key_ops, true):
 326                  return 'sig';
 327  
 328              case in_array('encrypt', $key_ops, true):
 329              case in_array('decrypt', $key_ops, true):
 330              case in_array('wrapKey', $key_ops, true):
 331              case in_array('unwrapKey', $key_ops, true):
 332              case in_array('deriveKey', $key_ops, true):
 333              case in_array('deriveBits', $key_ops, true):
 334                  return 'enc';
 335  
 336              default:
 337                  throw new InvalidArgumentException(sprintf('Unsupported key operation value "%s"', implode(', ', $key_ops)));
 338          }
 339      }
 340  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer