Initial Version
This commit is contained in:
38
core/lib/Http/Middleware/AuthenticationMiddleware.php
Normal file
38
core/lib/Http/Middleware/AuthenticationMiddleware.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace KTXC\Http\Middleware;
|
||||
|
||||
use KTXC\Http\Request\Request;
|
||||
use KTXC\Http\Response\Response;
|
||||
use KTXC\Service\SecurityService;
|
||||
use KTXC\SessionIdentity;
|
||||
|
||||
/**
|
||||
* Authentication middleware
|
||||
* Authenticates the request and initializes session identity
|
||||
*
|
||||
* Note: This middleware does NOT enforce authentication.
|
||||
* It only attempts to authenticate if credentials are present.
|
||||
* Route-level authentication is enforced by RouterMiddleware.
|
||||
*/
|
||||
class AuthenticationMiddleware implements MiddlewareInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly SecurityService $securityService,
|
||||
private readonly SessionIdentity $sessionIdentity
|
||||
) {}
|
||||
|
||||
public function process(Request $request, RequestHandlerInterface $handler): Response
|
||||
{
|
||||
// Attempt to authenticate the request
|
||||
$identity = $this->securityService->authenticate($request);
|
||||
|
||||
// Initialize session identity if authentication succeeded
|
||||
if ($identity) {
|
||||
$this->sessionIdentity->initialize($identity, true);
|
||||
}
|
||||
|
||||
// Continue to next middleware (authentication is optional at this stage)
|
||||
return $handler->handle($request);
|
||||
}
|
||||
}
|
||||
32
core/lib/Http/Middleware/FirewallMiddleware.php
Normal file
32
core/lib/Http/Middleware/FirewallMiddleware.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace KTXC\Http\Middleware;
|
||||
|
||||
use KTXC\Http\Request\Request;
|
||||
use KTXC\Http\Response\Response;
|
||||
use KTXC\Service\FirewallService;
|
||||
|
||||
/**
|
||||
* Firewall middleware
|
||||
* Checks if the request is authorized to proceed
|
||||
*/
|
||||
class FirewallMiddleware implements MiddlewareInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly FirewallService $firewall
|
||||
) {}
|
||||
|
||||
public function process(Request $request, RequestHandlerInterface $handler): Response
|
||||
{
|
||||
// Check firewall authorization
|
||||
if (!$this->firewall->authorized($request)) {
|
||||
return new Response(
|
||||
Response::$statusTexts[Response::HTTP_FORBIDDEN],
|
||||
Response::HTTP_FORBIDDEN
|
||||
);
|
||||
}
|
||||
|
||||
// Continue to next middleware
|
||||
return $handler->handle($request);
|
||||
}
|
||||
}
|
||||
21
core/lib/Http/Middleware/MiddlewareInterface.php
Normal file
21
core/lib/Http/Middleware/MiddlewareInterface.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace KTXC\Http\Middleware;
|
||||
|
||||
use KTXC\Http\Request\Request;
|
||||
use KTXC\Http\Response\Response;
|
||||
|
||||
/**
|
||||
* PSR-15 style middleware interface
|
||||
*/
|
||||
interface MiddlewareInterface
|
||||
{
|
||||
/**
|
||||
* Process an incoming server request.
|
||||
*
|
||||
* @param Request $request The request to process
|
||||
* @param RequestHandlerInterface $handler The next handler in the pipeline
|
||||
* @return Response The response from processing
|
||||
*/
|
||||
public function process(Request $request, RequestHandlerInterface $handler): Response;
|
||||
}
|
||||
112
core/lib/Http/Middleware/MiddlewarePipeline.php
Normal file
112
core/lib/Http/Middleware/MiddlewarePipeline.php
Normal file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace KTXC\Http\Middleware;
|
||||
|
||||
use KTXC\Http\Request\Request;
|
||||
use KTXC\Http\Response\Response;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Middleware pipeline - processes request through a stack of middleware
|
||||
*/
|
||||
class MiddlewarePipeline implements RequestHandlerInterface
|
||||
{
|
||||
/** @var array<string|MiddlewareInterface> */
|
||||
private array $middleware = [];
|
||||
|
||||
private ?ContainerInterface $container = null;
|
||||
|
||||
public function __construct(?ContainerInterface $container = null)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add middleware to the pipeline
|
||||
*
|
||||
* @param string|MiddlewareInterface $middleware Middleware class name or instance
|
||||
* @return self
|
||||
*/
|
||||
public function pipe(string|MiddlewareInterface $middleware): self
|
||||
{
|
||||
$this->middleware[] = $middleware;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request through the middleware pipeline
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function handle(Request $request): Response
|
||||
{
|
||||
// Create a handler for the pipeline
|
||||
$handler = $this->createHandler(0);
|
||||
|
||||
return $handler->handle($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a handler for a specific position in the pipeline
|
||||
*
|
||||
* @param int $index Current position in the middleware stack
|
||||
* @return RequestHandlerInterface
|
||||
*/
|
||||
public function createHandler(int $index): RequestHandlerInterface
|
||||
{
|
||||
// If we've reached the end of the pipeline, return a default handler
|
||||
if (!isset($this->middleware[$index])) {
|
||||
return new class implements RequestHandlerInterface {
|
||||
public function handle(Request $request): Response {
|
||||
return new Response(Response::$statusTexts[Response::HTTP_NOT_FOUND], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return new class($this->middleware[$index], $this, $index, $this->container) implements RequestHandlerInterface {
|
||||
private string|MiddlewareInterface $middleware;
|
||||
private MiddlewarePipeline $pipeline;
|
||||
private int $index;
|
||||
private ?ContainerInterface $container;
|
||||
|
||||
public function __construct(
|
||||
string|MiddlewareInterface $middleware,
|
||||
MiddlewarePipeline $pipeline,
|
||||
int $index,
|
||||
?ContainerInterface $container
|
||||
) {
|
||||
$this->middleware = $middleware;
|
||||
$this->pipeline = $pipeline;
|
||||
$this->index = $index;
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
public function handle(Request $request): Response
|
||||
{
|
||||
// Resolve middleware instance if it's a class name
|
||||
$middleware = $this->middleware;
|
||||
|
||||
if (is_string($middleware)) {
|
||||
if ($this->container && $this->container->has($middleware)) {
|
||||
$middleware = $this->container->get($middleware);
|
||||
} else {
|
||||
$middleware = new $middleware();
|
||||
}
|
||||
}
|
||||
|
||||
if (!$middleware instanceof MiddlewareInterface) {
|
||||
throw new \RuntimeException(
|
||||
sprintf('Middleware must implement %s', MiddlewareInterface::class)
|
||||
);
|
||||
}
|
||||
|
||||
// Create the next handler in the chain
|
||||
$next = $this->pipeline->createHandler($this->index + 1);
|
||||
|
||||
// Process this middleware
|
||||
return $middleware->process($request, $next);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
20
core/lib/Http/Middleware/RequestHandlerInterface.php
Normal file
20
core/lib/Http/Middleware/RequestHandlerInterface.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace KTXC\Http\Middleware;
|
||||
|
||||
use KTXC\Http\Request\Request;
|
||||
use KTXC\Http\Response\Response;
|
||||
|
||||
/**
|
||||
* PSR-15 style request handler interface
|
||||
*/
|
||||
interface RequestHandlerInterface
|
||||
{
|
||||
/**
|
||||
* Handle the request and return a response.
|
||||
*
|
||||
* @param Request $request The request to handle
|
||||
* @return Response The response from handling the request
|
||||
*/
|
||||
public function handle(Request $request): Response;
|
||||
}
|
||||
62
core/lib/Http/Middleware/RouterMiddleware.php
Normal file
62
core/lib/Http/Middleware/RouterMiddleware.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace KTXC\Http\Middleware;
|
||||
|
||||
use KTXC\Http\Request\Request;
|
||||
use KTXC\Http\Response\Response;
|
||||
use KTXC\Routing\Router;
|
||||
use KTXC\Routing\Route;
|
||||
use KTXC\SessionIdentity;
|
||||
use KTXC\Security\Authorization\PermissionChecker;
|
||||
|
||||
/**
|
||||
* Router middleware
|
||||
* Matches routes and dispatches to controllers
|
||||
*/
|
||||
class RouterMiddleware implements MiddlewareInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Router $router,
|
||||
private readonly SessionIdentity $sessionIdentity,
|
||||
private readonly PermissionChecker $permissionChecker
|
||||
) {}
|
||||
|
||||
public function process(Request $request, RequestHandlerInterface $handler): Response
|
||||
{
|
||||
// Attempt to match the route
|
||||
$match = $this->router->match($request);
|
||||
|
||||
if (!$match instanceof Route) {
|
||||
// No route matched, continue to next handler (will return 404)
|
||||
return $handler->handle($request);
|
||||
}
|
||||
|
||||
// Check if route requires authentication
|
||||
if ($match->authenticated && $this->sessionIdentity->identity() === null) {
|
||||
return new Response(
|
||||
Response::$statusTexts[Response::HTTP_UNAUTHORIZED],
|
||||
Response::HTTP_UNAUTHORIZED
|
||||
);
|
||||
}
|
||||
|
||||
// Check permissions (if any specified)
|
||||
if ($match->authenticated && !empty($match->permissions)) {
|
||||
if (!$this->permissionChecker->canAny($match->permissions)) {
|
||||
return new Response(
|
||||
Response::$statusTexts[Response::HTTP_FORBIDDEN],
|
||||
Response::HTTP_FORBIDDEN
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Dispatch to the controller
|
||||
$response = $this->router->dispatch($match, $request);
|
||||
|
||||
if ($response instanceof Response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
// If dispatch didn't return a response, continue to next handler
|
||||
return $handler->handle($request);
|
||||
}
|
||||
}
|
||||
35
core/lib/Http/Middleware/TenantMiddleware.php
Normal file
35
core/lib/Http/Middleware/TenantMiddleware.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace KTXC\Http\Middleware;
|
||||
|
||||
use KTXC\Http\Request\Request;
|
||||
use KTXC\Http\Response\Response;
|
||||
use KTXC\SessionTenant;
|
||||
|
||||
/**
|
||||
* Tenant resolution middleware
|
||||
* Configures the tenant based on the request host
|
||||
*/
|
||||
class TenantMiddleware implements MiddlewareInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly SessionTenant $sessionTenant
|
||||
) {}
|
||||
|
||||
public function process(Request $request, RequestHandlerInterface $handler): Response
|
||||
{
|
||||
// Configure tenant from request host
|
||||
$this->sessionTenant->configure($request->getHost());
|
||||
|
||||
// Check if tenant is configured and enabled
|
||||
if (!$this->sessionTenant->configured() || !$this->sessionTenant->enabled()) {
|
||||
return new Response(
|
||||
Response::$statusTexts[Response::HTTP_UNAUTHORIZED],
|
||||
Response::HTTP_UNAUTHORIZED
|
||||
);
|
||||
}
|
||||
|
||||
// Continue to next middleware
|
||||
return $handler->handle($request);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user