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.2KB

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