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.

BasicAuthMiddleware.php 4.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  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 BasicAuthMiddleware extends Middleware
  11. {
  12. private function hasCorrectPassword(string $username, string $password, array &$passwords): bool
  13. {
  14. $hash = isset($passwords[$username]) ? $passwords[$username] : false;
  15. if ($hash && password_verify($password, $hash)) {
  16. if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
  17. $passwords[$username] = password_hash($password, PASSWORD_DEFAULT);
  18. }
  19. return true;
  20. }
  21. return false;
  22. }
  23. private function getValidUsername(string $username, string $password, string $passwordFile): string
  24. {
  25. $passwords = $this->readPasswords($passwordFile);
  26. $valid = $this->hasCorrectPassword($username, $password, $passwords);
  27. $this->writePasswords($passwordFile, $passwords);
  28. return $valid ? $username : '';
  29. }
  30. private function readPasswords(string $passwordFile): array
  31. {
  32. $passwords = [];
  33. $passwordLines = file($passwordFile);
  34. foreach ($passwordLines as $passwordLine) {
  35. if (strpos($passwordLine, ':') !== false) {
  36. list($username, $hash) = explode(':', trim($passwordLine), 2);
  37. if (strlen($hash) > 0 && $hash[0] != '$') {
  38. $hash = password_hash($hash, PASSWORD_DEFAULT);
  39. }
  40. $passwords[$username] = $hash;
  41. }
  42. }
  43. return $passwords;
  44. }
  45. private function writePasswords(string $passwordFile, array $passwords): bool
  46. {
  47. $success = false;
  48. $passwordFileContents = '';
  49. foreach ($passwords as $username => $hash) {
  50. $passwordFileContents .= "$username:$hash\n";
  51. }
  52. if (file_get_contents($passwordFile) != $passwordFileContents) {
  53. $success = file_put_contents($passwordFile, $passwordFileContents) !== false;
  54. }
  55. return $success;
  56. }
  57. private function getAuthorizationCredentials(ServerRequestInterface $request): string
  58. {
  59. if (isset($_SERVER['PHP_AUTH_USER'])) {
  60. return $_SERVER['PHP_AUTH_USER'] . ':' . $_SERVER['PHP_AUTH_PW'];
  61. }
  62. $header = RequestUtils::getHeader($request, 'Authorization');
  63. $parts = explode(' ', trim($header), 2);
  64. if (count($parts) != 2) {
  65. return '';
  66. }
  67. if ($parts[0] != 'Basic') {
  68. return '';
  69. }
  70. return base64_decode(strtr($parts[1], '-_', '+/'));
  71. }
  72. public function process(ServerRequestInterface $request, RequestHandlerInterface $next): ResponseInterface
  73. {
  74. if (session_status() == PHP_SESSION_NONE) {
  75. if (!headers_sent()) {
  76. session_start();
  77. }
  78. }
  79. $credentials = $this->getAuthorizationCredentials($request);
  80. if ($credentials) {
  81. list($username, $password) = array('', '');
  82. if (strpos($credentials, ':') !== false) {
  83. list($username, $password) = explode(':', $credentials, 2);
  84. }
  85. $passwordFile = $this->getProperty('passwordFile', '.htpasswd');
  86. $validUser = $this->getValidUsername($username, $password, $passwordFile);
  87. $_SESSION['username'] = $validUser;
  88. if (!$validUser) {
  89. return $this->responder->error(ErrorCode::AUTHENTICATION_FAILED, $username);
  90. }
  91. if (!headers_sent()) {
  92. session_regenerate_id();
  93. }
  94. }
  95. if (!isset($_SESSION['username']) || !$_SESSION['username']) {
  96. $authenticationMode = $this->getProperty('mode', 'required');
  97. if ($authenticationMode == 'required') {
  98. $response = $this->responder->error(ErrorCode::AUTHENTICATION_REQUIRED, '');
  99. $realm = $this->getProperty('realm', 'Username and password required');
  100. $response = $response->withHeader('WWW-Authenticate', "Basic realm=\"$realm\"");
  101. return $response;
  102. }
  103. }
  104. return $next->handle($request);
  105. }
  106. }