api de gestion de ticket, basé sur php-crud-api. Le but est de décorrélé les outils de gestion des données, afin
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

JwtAuthMiddleware.php 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. <?php
  2. namespace Tqdev\PhpCrudApi\Middleware;
  3. use Psr\Http\Message\ResponseInterface;
  4. use Psr\Http\Message\ServerRequestInterface;
  5. use Tqdev\PhpCrudApi\Controller\Responder;
  6. use Tqdev\PhpCrudApi\Middleware\Base\Middleware;
  7. use Tqdev\PhpCrudApi\Record\ErrorCode;
  8. use Tqdev\PhpCrudApi\RequestUtils;
  9. class JwtAuthMiddleware extends Middleware
  10. {
  11. private function getVerifiedClaims(string $token, int $time, int $leeway, int $ttl, string $secret, array $requirements): array
  12. {
  13. $algorithms = array(
  14. 'HS256' => 'sha256',
  15. 'HS384' => 'sha384',
  16. 'HS512' => 'sha512',
  17. 'RS256' => 'sha256',
  18. 'RS384' => 'sha384',
  19. 'RS512' => 'sha512',
  20. );
  21. $token = explode('.', $token);
  22. if (count($token) < 3) {
  23. return array();
  24. }
  25. $header = json_decode(base64_decode(strtr($token[0], '-_', '+/')), true);
  26. if (!$secret) {
  27. return array();
  28. }
  29. if ($header['typ'] != 'JWT') {
  30. return array();
  31. }
  32. $algorithm = $header['alg'];
  33. if (!isset($algorithms[$algorithm])) {
  34. return array();
  35. }
  36. if (!empty($requirements['alg']) && !in_array($algorithm, $requirements['alg'])) {
  37. return array();
  38. }
  39. $hmac = $algorithms[$algorithm];
  40. $signature = base64_decode(strtr($token[2], '-_', '+/'));
  41. $data = "$token[0].$token[1]";
  42. switch ($algorithm[0]) {
  43. case 'H':
  44. $hash = hash_hmac($hmac, $data, $secret, true);
  45. if (function_exists('hash_equals')) {
  46. $equals = hash_equals($signature, $hash);
  47. } else {
  48. $equals = $signature == $hash;
  49. }
  50. if (!$equals) {
  51. return array();
  52. }
  53. break;
  54. case 'R':
  55. $equals = openssl_verify($data, $signature, $secret, $hmac) == 1;
  56. if (!$equals) {
  57. return array();
  58. }
  59. break;
  60. }
  61. $claims = json_decode(base64_decode(strtr($token[1], '-_', '+/')), true);
  62. if (!$claims) {
  63. return array();
  64. }
  65. foreach ($requirements as $field => $values) {
  66. if (!empty($values)) {
  67. if ($field != 'alg') {
  68. if (!isset($claims[$field]) || !in_array($claims[$field], $values)) {
  69. return array();
  70. }
  71. }
  72. }
  73. }
  74. if (isset($claims['nbf']) && $time + $leeway < $claims['nbf']) {
  75. return array();
  76. }
  77. if (isset($claims['iat']) && $time + $leeway < $claims['iat']) {
  78. return array();
  79. }
  80. if (isset($claims['exp']) && $time - $leeway > $claims['exp']) {
  81. return array();
  82. }
  83. if (isset($claims['iat']) && !isset($claims['exp'])) {
  84. if ($time - $leeway > $claims['iat'] + $ttl) {
  85. return array();
  86. }
  87. }
  88. return $claims;
  89. }
  90. private function getClaims(string $token): array
  91. {
  92. $time = (int) $this->getProperty('time', time());
  93. $leeway = (int) $this->getProperty('leeway', '5');
  94. $ttl = (int) $this->getProperty('ttl', '30');
  95. $secret = $this->getProperty('secret', '');
  96. $requirements = array(
  97. 'alg' => $this->getArrayProperty('algorithms', ''),
  98. 'aud' => $this->getArrayProperty('audiences', ''),
  99. 'iss' => $this->getArrayProperty('issuers', ''),
  100. );
  101. if (!$secret) {
  102. return array();
  103. }
  104. return $this->getVerifiedClaims($token, $time, $leeway, $ttl, $secret, $requirements);
  105. }
  106. private function getAuthorizationToken(ServerRequestInterface $request): string
  107. {
  108. $headerName = $this->getProperty('header', 'X-Authorization');
  109. $headerValue = RequestUtils::getHeader($request, $headerName);
  110. $parts = explode(' ', trim($headerValue), 2);
  111. if (count($parts) != 2) {
  112. return '';
  113. }
  114. if ($parts[0] != 'Bearer') {
  115. return '';
  116. }
  117. return $parts[1];
  118. }
  119. public function handle(ServerRequestInterface $request): ResponseInterface
  120. {
  121. if (session_status() == PHP_SESSION_NONE) {
  122. session_start();
  123. }
  124. $token = $this->getAuthorizationToken($request);
  125. if ($token) {
  126. $claims = $this->getClaims($token);
  127. $_SESSION['claims'] = $claims;
  128. if (empty($claims)) {
  129. return $this->responder->error(ErrorCode::AUTHENTICATION_FAILED, 'JWT');
  130. }
  131. if (!headers_sent()) {
  132. session_regenerate_id();
  133. }
  134. }
  135. if (empty($_SESSION['claims'])) {
  136. $authenticationMode = $this->getProperty('mode', 'required');
  137. if ($authenticationMode == 'required') {
  138. return $this->responder->error(ErrorCode::AUTHENTICATION_REQUIRED, '');
  139. }
  140. }
  141. return $this->next->handle($request);
  142. }
  143. }