فهرست منبع

refactor HttpBasicAuthHandler into a static security firewall

michelphp 1 ماه پیش
والد
کامیت
84dbf30edf
3فایلهای تغییر یافته به همراه31 افزوده شده و 22 حذف شده
  1. 22 20
      src/Handler/HttpBasicAuthHandler.php
  2. 5 2
      src/MichelPackage/MichelAuthPackage.php
  3. 4 0
      src/Middlewares/AuthMiddleware.php

+ 22 - 20
src/Handler/HttpBasicAuthHandler.php

@@ -15,22 +15,25 @@ use Psr\Http\Message\ServerRequestInterface;
 
 class HttpBasicAuthHandler implements AuthHandlerInterface
 {
-    private UserProviderInterface $userProvider;
-
+    private string $user;
+    private string $password;
     private string $realm;
     /**
      * @var callable|null
      */
     private $onFailure;
+
     public function __construct(
-        UserProviderInterface $userProvider,
-         string $realm = "Restricted Area",
+        string $user,
+        string $password,
+        string                $realm = "Restricted Area",
         callable              $onFailure = null
     )
     {
-        $this->userProvider = $userProvider;
-        $this->onFailure = $onFailure;
+        $this->user = $user;
+        $this->password = $password;
         $this->realm = $realm;
+        $this->onFailure = $onFailure;
     }
 
 
@@ -42,31 +45,28 @@ class HttpBasicAuthHandler implements AuthHandlerInterface
     public function authenticate(ServerRequestInterface $request): ?AuthIdentity
     {
         $authHeader = $request->getHeaderLine('Authorization');
+        if (empty($authHeader)) {
+            throw new AuthenticationException("Authentication required.");
+        }
+
         if (0 !== strpos(strtolower($authHeader), 'basic ')) {
-            return null;
+            throw new AuthenticationException("Only Basic authentication is allowed.");
         }
 
         $base64Credentials = substr($authHeader, 6);
         $credentials = base64_decode($base64Credentials);
         if (false === $credentials || false === strpos($credentials, ':')) {
-            throw new InvalidCredentialsException("Invalid Basic Auth format.");
+            throw new InvalidCredentialsException("Malformed credentials.");
         }
 
         [$login, $password] = explode(':', $credentials, 2);
         $login = trim($login);
-        /**
-         * @var PasswordAuthenticatedUserInterface|UserInterface $user
-         */
-        $user = $this->userProvider->findByIdentifier($login);
-        if (!$user instanceof UserInterface) {
-            throw new UserNotFoundException("User not found.");
-        }
 
-        if (!$user instanceof PasswordAuthenticatedUserInterface || !$this->userProvider->isPasswordValid($user, $password)) {
-            throw new InvalidCredentialsException("Invalid username or password.");
+        if ($login !== $this->user || $password !== $this->password) {
+            throw new InvalidCredentialsException("Access denied.");
         }
 
-        return new AuthIdentity($user, false);
+        return null;
     }
 
     public function onFailure(ServerRequestInterface $request, ResponseFactoryInterface $responseFactory, ?AuthenticationException $exception = null): ResponseInterface
@@ -75,8 +75,10 @@ class HttpBasicAuthHandler implements AuthHandlerInterface
             return ($this->onFailure)($request, $responseFactory, $exception);
         }
 
-        return $responseFactory->createResponse(401)
-            ->withHeader('WWW-Authenticate', sprintf('Basic realm="%s"', $this->realm))
+        $response = $responseFactory->createResponse(401);
+        return $response
+            ->withHeader('WWW-Authenticate', sprintf('Basic realm="%s", charset="UTF-8"', $this->realm))
+            ->withHeader('Content-Type', 'text/plain')
             ->withHeader('Cache-Control', 'no-store, no-cache, must-revalidate');
     }
 }

+ 5 - 2
src/MichelPackage/MichelAuthPackage.php

@@ -65,7 +65,8 @@ class MichelAuthPackage implements PackageInterface
             },
             HttpBasicAuthHandler::class => static function (ContainerInterface $container) {
                 return new HttpBasicAuthHandler(
-                    $container->get(UserProviderInterface::class),
+                    $container->get('auth.basic.user'),
+                    $container->get('auth.basic.password'),
                     $container->get('auth.http.basic.realm'),
                     $container->get('auth.http.basic.on_failure')
                 );
@@ -85,8 +86,10 @@ class MichelAuthPackage implements PackageInterface
             'auth.token.header_name' => 'X-Api-Key',
             'auth.token.on_failure' => null,
 
+            'auth.basic.user' => '',
+            'auth.basic.password' => '',
             'auth.http.basic.realm' => 'Restricted Area',
-            'auth.http_basic.on_failure' => null
+            'auth.http.basic.on_failure' => null
         ];
     }
 

+ 4 - 0
src/Middlewares/AuthMiddleware.php

@@ -7,6 +7,7 @@ use Michel\Auth\Exception\AuthenticationException;
 use Michel\Auth\Handler\AuthHandlerInterface;
 use Michel\Auth\Handler\StatefulAuthHandlerInterface;
 use Michel\Auth\Helper\IpHelper;
+use Michel\Auth\UserInterface;
 use Psr\Http\Message\ResponseFactoryInterface;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
@@ -34,6 +35,9 @@ abstract class AuthMiddleware implements MiddlewareInterface
     public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
     {
         $handlerName = get_class($this->authHandler);
+        if ($request->getAttribute('user') instanceof UserInterface) {
+            return $handler->handle($request);
+        }
 
         try {
             $authIdentity = $this->authHandler->authenticate($request);