123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- <?php
-
- namespace Tqdev\PhpCrudApi\Middleware;
-
- use Psr\Http\Message\ResponseInterface;
- use Psr\Http\Message\ServerRequestInterface;
- use Psr\Http\Server\RequestHandlerInterface;
- use Tqdev\PhpCrudApi\Controller\Responder;
- use Tqdev\PhpCrudApi\Middleware\Base\Middleware;
- use Tqdev\PhpCrudApi\Record\ErrorCode;
- use Tqdev\PhpCrudApi\RequestUtils;
-
- class BasicAuthMiddleware extends Middleware
- {
- private function hasCorrectPassword(string $username, string $password, array &$passwords): bool
- {
- $hash = isset($passwords[$username]) ? $passwords[$username] : false;
- if ($hash && password_verify($password, $hash)) {
- if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
- $passwords[$username] = password_hash($password, PASSWORD_DEFAULT);
- }
- return true;
- }
- return false;
- }
-
- private function getValidUsername(string $username, string $password, string $passwordFile): string
- {
- $passwords = $this->readPasswords($passwordFile);
- $valid = $this->hasCorrectPassword($username, $password, $passwords);
- $this->writePasswords($passwordFile, $passwords);
- return $valid ? $username : '';
- }
-
- private function readPasswords(string $passwordFile): array
- {
- $passwords = [];
- $passwordLines = file($passwordFile);
- foreach ($passwordLines as $passwordLine) {
- if (strpos($passwordLine, ':') !== false) {
- list($username, $hash) = explode(':', trim($passwordLine), 2);
- if (strlen($hash) > 0 && $hash[0] != '$') {
- $hash = password_hash($hash, PASSWORD_DEFAULT);
- }
- $passwords[$username] = $hash;
- }
- }
- return $passwords;
- }
-
- private function writePasswords(string $passwordFile, array $passwords): bool
- {
- $success = false;
- $passwordFileContents = '';
- foreach ($passwords as $username => $hash) {
- $passwordFileContents .= "$username:$hash\n";
- }
- if (file_get_contents($passwordFile) != $passwordFileContents) {
- $success = file_put_contents($passwordFile, $passwordFileContents) !== false;
- }
- return $success;
- }
-
- private function getAuthorizationCredentials(ServerRequestInterface $request): string
- {
- if (isset($_SERVER['PHP_AUTH_USER'])) {
- return $_SERVER['PHP_AUTH_USER'] . ':' . $_SERVER['PHP_AUTH_PW'];
- }
- $header = RequestUtils::getHeader($request, 'Authorization');
- $parts = explode(' ', trim($header), 2);
- if (count($parts) != 2) {
- return '';
- }
- if ($parts[0] != 'Basic') {
- return '';
- }
- return base64_decode(strtr($parts[1], '-_', '+/'));
- }
-
- public function process(ServerRequestInterface $request, RequestHandlerInterface $next): ResponseInterface
- {
- if (session_status() == PHP_SESSION_NONE) {
- if (!headers_sent()) {
- session_start();
- }
- }
- $credentials = $this->getAuthorizationCredentials($request);
- if ($credentials) {
- list($username, $password) = array('', '');
- if (strpos($credentials, ':') !== false) {
- list($username, $password) = explode(':', $credentials, 2);
- }
- $passwordFile = $this->getProperty('passwordFile', '.htpasswd');
- $validUser = $this->getValidUsername($username, $password, $passwordFile);
- $_SESSION['username'] = $validUser;
- if (!$validUser) {
- return $this->responder->error(ErrorCode::AUTHENTICATION_FAILED, $username);
- }
- if (!headers_sent()) {
- session_regenerate_id();
- }
- }
- if (!isset($_SESSION['username']) || !$_SESSION['username']) {
- $authenticationMode = $this->getProperty('mode', 'required');
- if ($authenticationMode == 'required') {
- $response = $this->responder->error(ErrorCode::AUTHENTICATION_REQUIRED, '');
- $realm = $this->getProperty('realm', 'Username and password required');
- $response = $response->withHeader('WWW-Authenticate', "Basic realm=\"$realm\"");
- return $response;
- }
- }
- return $next->handle($request);
- }
- }
|