diff --git a/src/Exception/InvalidOriginValueException.php b/src/Exception/InvalidOriginValueException.php index fa59a3d..82f7a9a 100644 --- a/src/Exception/InvalidOriginValueException.php +++ b/src/Exception/InvalidOriginValueException.php @@ -11,13 +11,16 @@ final class InvalidOriginValueException extends RuntimeException implements ExceptionInterface { - private function __construct(string $message, ?Throwable $previous = null) - { + private function __construct( + string $message, + public readonly string $origin, + ?Throwable $previous = null + ) { parent::__construct($message, 0, $previous); } public static function fromThrowable(string $origin, Throwable $throwable): self { - return new self(sprintf('Provided Origin "%s" is invalid.', $origin), $throwable); + return new self(sprintf('Provided Origin "%s" is invalid.', $origin), $origin, $throwable); } } diff --git a/src/Middleware/CorsMiddleware.php b/src/Middleware/CorsMiddleware.php index aa4f93e..63fdf0c 100644 --- a/src/Middleware/CorsMiddleware.php +++ b/src/Middleware/CorsMiddleware.php @@ -4,6 +4,7 @@ namespace Mezzio\Cors\Middleware; +use Mezzio\Cors\Exception\InvalidOriginValueException; use Mezzio\Cors\Middleware\Exception\InvalidConfigurationException; use Mezzio\Cors\Service\ConfigurationLocatorInterface; use Mezzio\Cors\Service\CorsInterface; @@ -46,11 +47,18 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface throw InvalidConfigurationException::fromInvalidPipelineConfiguration(); } - if (! $this->cors->isCorsRequest($request)) { + try { + $isCorsRequest = $this->cors->isCorsRequest($request); + } catch (InvalidOriginValueException $exception) { + return $this->responseFactory->unauthorized($exception->origin); + } + + if (! $isCorsRequest) { return $this->vary($handler->handle($request)); } $metadata = $this->cors->metadata($request); + if ($this->cors->isPreflightRequest($request)) { return $this->preflight($metadata) ?? $handler->handle($request); } diff --git a/test/Middleware/CorsMiddlewareTest.php b/test/Middleware/CorsMiddlewareTest.php index 57113ac..a7926ba 100644 --- a/test/Middleware/CorsMiddlewareTest.php +++ b/test/Middleware/CorsMiddlewareTest.php @@ -5,8 +5,10 @@ namespace Mezzio\CorsTest\Middleware; use Fig\Http\Message\RequestMethodInterface; +use InvalidArgumentException; use Mezzio\Cors\Configuration\ConfigurationInterface; use Mezzio\Cors\Configuration\RouteConfigurationInterface; +use Mezzio\Cors\Exception\InvalidOriginValueException; use Mezzio\Cors\Middleware\CorsMiddleware; use Mezzio\Cors\Middleware\Exception\InvalidConfigurationException; use Mezzio\Cors\Service\ConfigurationLocatorInterface; @@ -486,4 +488,35 @@ public function testWillDelegateUnknownRouteForRequestToRequestHandler(): void $this->middleware->process($request, $handler); } + + public function testWillHandleRequestsWithInvalidOriginAsUnauthorized(): void + { + $request = $this->createMock(ServerRequestInterface::class); + $request + ->method('getHeaderLine') + ->willReturnMap([['Origin', 'foobarbaz://example.org']]); + + $this->cors + ->expects(self::once()) + ->method('isCorsRequest') + ->with($request) + ->willThrowException( + InvalidOriginValueException::fromThrowable( + 'foobarbaz://example.org', + new InvalidArgumentException('Some exception from PSR-17 factory.') + ), + ); + + $handler = $this->createMock(RequestHandlerInterface::class); + $handler + ->expects(self::never()) + ->method('handle'); + + $this->responseFactoryInterface + ->expects(self::once()) + ->method('unauthorized') + ->with('foobarbaz://example.org'); + + $this->middleware->process($request, $handler); + } }