From f7afedc8a53d3808f486ac76a55b085376192296 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Ivan=C4=8Di=C4=87?= Date: Mon, 10 Jun 2024 11:27:20 +0200 Subject: [PATCH] Make token endpoint available as Symfony route --- routing/routes/routes.php | 8 ++- src/Codebooks/RoutesEnum.php | 1 + src/Controller/AccessTokenController.php | 32 +++++++-- src/Controller/AuthorizationController.php | 4 +- src/Controller/Traits/RequestTrait.php | 23 +++---- src/Controller/UserInfoController.php | 8 ++- src/Services/OpMetadataService.php | 2 +- .../Controller/AccessTokenControllerTest.php | 60 +++++++++------- .../ConfigurationDiscoveryControllerTest.php | 4 +- .../Controller/Traits/RequestTraitTest.php | 68 ++++++++++++++----- .../src/Controller/UserInfoControllerTest.php | 18 ++--- tests/src/Services/OpMetadataServiceTest.php | 4 +- 12 files changed, 155 insertions(+), 77 deletions(-) diff --git a/routing/routes/routes.php b/routing/routes/routes.php index 00ddf0e9..93491862 100644 --- a/routing/routes/routes.php +++ b/routing/routes/routes.php @@ -8,6 +8,7 @@ use SimpleSAML\Module\oidc\Codebooks\HttpMethodsEnum; use SimpleSAML\Module\oidc\Codebooks\RoutesEnum; +use SimpleSAML\Module\oidc\Controller\AccessTokenController; use SimpleSAML\Module\oidc\Controller\AuthorizationController; use SimpleSAML\Module\oidc\Controller\ConfigurationDiscoveryController; use SimpleSAML\Module\oidc\Controller\Federation\EntityStatementController; @@ -18,8 +19,13 @@ $routes->add(RoutesEnum::OpenIdConfiguration->name, RoutesEnum::OpenIdConfiguration->value) ->controller(ConfigurationDiscoveryController::class); + /** + * OpenID Connect Core protocol routes. + */ $routes->add(RoutesEnum::OpenIdAuthorization->name, RoutesEnum::OpenIdAuthorization->value) - ->controller([AuthorizationController::class, 'authorize']); + ->controller([AuthorizationController::class, 'authorization']); + $routes->add(RoutesEnum::OpenIdToken->name, RoutesEnum::OpenIdToken->value) + ->controller([AccessTokenController::class, 'token']); /** * OpenID Federation related routes. diff --git a/src/Codebooks/RoutesEnum.php b/src/Codebooks/RoutesEnum.php index 8c0c424b..75e8f988 100644 --- a/src/Codebooks/RoutesEnum.php +++ b/src/Codebooks/RoutesEnum.php @@ -10,4 +10,5 @@ enum RoutesEnum: string case OpenIdConfiguration = '.well-known/openid-configuration'; case OpenIdFederationConfiguration = '.well-known/openid-federation'; case OpenIdFederationFetch = 'federation/fetch'; + case OpenIdToken = 'token'; } diff --git a/src/Controller/AccessTokenController.php b/src/Controller/AccessTokenController.php index 2e9fbe5c..ba2b7841 100644 --- a/src/Controller/AccessTokenController.php +++ b/src/Controller/AccessTokenController.php @@ -15,12 +15,16 @@ */ namespace SimpleSAML\Module\oidc\Controller; -use Laminas\Diactoros\Response; -use Laminas\Diactoros\ServerRequest; +use League\OAuth2\Server\Exception\OAuthServerException; use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; +use SimpleSAML\Module\oidc\Bridges\PsrHttpBridge; use SimpleSAML\Module\oidc\Controller\Traits\RequestTrait; use SimpleSAML\Module\oidc\Repositories\AllowedOriginRepository; use SimpleSAML\Module\oidc\Server\AuthorizationServer; +use SimpleSAML\Module\oidc\Services\ErrorResponder; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; class AccessTokenController { @@ -29,19 +33,39 @@ class AccessTokenController public function __construct( private readonly AuthorizationServer $authorizationServer, private readonly AllowedOriginRepository $allowedOriginRepository, + private readonly PsrHttpBridge $psrHttpBridge, + private readonly ErrorResponder $errorResponder, ) { } /** * @throws \League\OAuth2\Server\Exception\OAuthServerException */ - public function __invoke(ServerRequest $request): ResponseInterface + public function __invoke(ServerRequestInterface $request): ResponseInterface { // Check if this is actually a CORS preflight request... if (strtoupper($request->getMethod()) === 'OPTIONS') { return $this->handleCors($request); } - return $this->authorizationServer->respondToAccessTokenRequest($request, new Response()); + return $this->authorizationServer->respondToAccessTokenRequest( + $request, + $this->psrHttpBridge->getResponseFactory()->createResponse(), + ); + } + + public function token(Request $request): Response + { + try { + /** + * @psalm-suppress DeprecatedMethod Until we drop support for old public/*.php routes, we need to bridge + * between PSR and Symfony HTTP messages. + */ + return $this->psrHttpBridge->getHttpFoundationFactory()->createResponse( + $this->__invoke($this->psrHttpBridge->getPsrHttpFactory()->createRequest($request)), + ); + } catch (OAuthServerException $exception) { + return $this->errorResponder->forException($exception); + } } } diff --git a/src/Controller/AuthorizationController.php b/src/Controller/AuthorizationController.php index 5e1f9a14..ec576971 100644 --- a/src/Controller/AuthorizationController.php +++ b/src/Controller/AuthorizationController.php @@ -52,7 +52,7 @@ public function __construct( * @throws \Throwable * * @deprecated 7.0.0 Will be moved to Symfony controller method - * @see self::authorize() + * @see self::authorization() */ public function __invoke(ServerRequestInterface $request): ResponseInterface { @@ -77,7 +77,7 @@ public function __invoke(ServerRequestInterface $request): ResponseInterface ); } - public function authorize(Request $request): Response + public function authorization(Request $request): Response { try { /** diff --git a/src/Controller/Traits/RequestTrait.php b/src/Controller/Traits/RequestTrait.php index aae26eef..94aa907e 100644 --- a/src/Controller/Traits/RequestTrait.php +++ b/src/Controller/Traits/RequestTrait.php @@ -16,8 +16,8 @@ namespace SimpleSAML\Module\oidc\Controller\Traits; -use Laminas\Diactoros\Response; -use Laminas\Diactoros\ServerRequest; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; use SimpleSAML\Module\oidc\Server\Exceptions\OidcServerException; trait RequestTrait @@ -28,7 +28,7 @@ trait RequestTrait * * @throws \SimpleSAML\Module\oidc\Server\Exceptions\OidcServerException */ - protected function handleCors(ServerRequest $request): Response + protected function handleCors(ServerRequestInterface $request): ResponseInterface { $origin = $request->getHeaderLine('Origin'); @@ -40,15 +40,12 @@ protected function handleCors(ServerRequest $request): Response throw OidcServerException::accessDenied(sprintf('CORS error: origin %s is not allowed', $origin)); } - $headers = [ - 'Access-Control-Allow-Origin' => $origin, - 'Access-Control-Allow-Methods' => 'GET, POST, OPTIONS', - // Support AJAX requests for JS clients - // e.g. https://github.com/swagger-api/swagger-ui/commit/937c8f6208f3adf713b10a349a82a1b129bd0ffd - 'Access-Control-Allow-Headers' => 'Authorization, X-Requested-With', - 'Access-Control-Allow-Credentials' => 'true', - ]; - - return new Response('php://memory', 204, $headers); + return $this->psrHttpBridge->getResponseFactory()->createResponse(204) + ->withBody($this->psrHttpBridge->getStreamFactory()->createStream('php://memory')) + ->withHeader('Access-Control-Allow-Origin', $origin) + ->withHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS') + ->withHeader('Access-Control-Allow-Headers', 'Authorization, X-Requested-With') + ->withHeader('Access-Control-Allow-Credentials', 'true') + ; } } diff --git a/src/Controller/UserInfoController.php b/src/Controller/UserInfoController.php index 1d273fca..b13349e0 100644 --- a/src/Controller/UserInfoController.php +++ b/src/Controller/UserInfoController.php @@ -16,11 +16,12 @@ namespace SimpleSAML\Module\oidc\Controller; -use Laminas\Diactoros\Response; use Laminas\Diactoros\Response\JsonResponse; -use Laminas\Diactoros\ServerRequest; use League\OAuth2\Server\ResourceServer; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; use SimpleSAML\Error; +use SimpleSAML\Module\oidc\Bridges\PsrHttpBridge; use SimpleSAML\Module\oidc\Controller\Traits\RequestTrait; use SimpleSAML\Module\oidc\Entities\AccessTokenEntity; use SimpleSAML\Module\oidc\Entities\UserEntity; @@ -39,6 +40,7 @@ public function __construct( private readonly UserRepository $userRepository, private readonly AllowedOriginRepository $allowedOriginRepository, private readonly ClaimTranslatorExtractor $claimTranslatorExtractor, + private readonly PsrHttpBridge $psrHttpBridge, ) { } @@ -47,7 +49,7 @@ public function __construct( * @throws \SimpleSAML\Module\oidc\Server\Exceptions\OidcServerException * @throws \League\OAuth2\Server\Exception\OAuthServerException */ - public function __invoke(ServerRequest $request): Response + public function __invoke(ServerRequestInterface $request): ResponseInterface { // Check if this is actually a CORS preflight request... if (strtoupper($request->getMethod()) === 'OPTIONS') { diff --git a/src/Services/OpMetadataService.php b/src/Services/OpMetadataService.php index 4b02bc4a..d183c384 100644 --- a/src/Services/OpMetadataService.php +++ b/src/Services/OpMetadataService.php @@ -36,7 +36,7 @@ private function initMetadata(): void $this->metadata['issuer'] = $this->moduleConfig->getIssuer(); $this->metadata['authorization_endpoint'] = $this->moduleConfig->getModuleUrl(RoutesEnum::OpenIdAuthorization->value); - $this->metadata['token_endpoint'] = $this->moduleConfig->getModuleUrl('token.php'); + $this->metadata['token_endpoint'] = $this->moduleConfig->getModuleUrl(RoutesEnum::OpenIdToken->value); $this->metadata['userinfo_endpoint'] = $this->moduleConfig->getModuleUrl('userinfo.php'); $this->metadata['end_session_endpoint'] = $this->moduleConfig->getModuleUrl('logout.php'); $this->metadata['jwks_uri'] = $this->moduleConfig->getModuleUrl('jwks.php'); diff --git a/tests/src/Controller/AccessTokenControllerTest.php b/tests/src/Controller/AccessTokenControllerTest.php index b8e6c83d..d6818fd7 100644 --- a/tests/src/Controller/AccessTokenControllerTest.php +++ b/tests/src/Controller/AccessTokenControllerTest.php @@ -8,11 +8,14 @@ use Laminas\Diactoros\ServerRequest; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use Psr\Http\Message\ResponseFactoryInterface; +use Psr\Http\Message\ResponseInterface; +use SimpleSAML\Module\oidc\Bridges\PsrHttpBridge; use SimpleSAML\Module\oidc\Controller\AccessTokenController; use SimpleSAML\Module\oidc\Controller\Traits\RequestTrait; -use SimpleSAML\Module\oidc\Controller\UserInfoController; use SimpleSAML\Module\oidc\Repositories\AllowedOriginRepository; use SimpleSAML\Module\oidc\Server\AuthorizationServer; +use SimpleSAML\Module\oidc\Services\ErrorResponder; /** * @covers \SimpleSAML\Module\oidc\Controller\AccessTokenController @@ -23,6 +26,11 @@ class AccessTokenControllerTest extends TestCase protected MockObject $allowedOriginRepository; protected MockObject $serverRequestMock; protected MockObject $responseMock; + protected MockObject $psrHttpBridgeMock; + protected MockObject $errorResponderMock; + protected MockObject $requestFactoryMock; + protected MockObject $responseFactoryMock; + /** * @throws \Exception @@ -33,16 +41,29 @@ protected function setUp(): void $this->allowedOriginRepository = $this->createMock(AllowedOriginRepository::class); $this->serverRequestMock = $this->createMock(ServerRequest::class); $this->responseMock = $this->createMock(Response::class); + $this->errorResponderMock = $this->createMock(ErrorResponder::class); + + $this->psrHttpBridgeMock = $this->createMock(PsrHttpBridge::class); + $this->responseFactoryMock = $this->createMock(ResponseFactoryInterface::class); + $this->responseFactoryMock->method('createResponse')->willReturn($this->responseMock); + $this->psrHttpBridgeMock->method('getResponseFactory')->willReturn($this->responseFactoryMock); + } + + protected function mock(): AccessTokenController + { + return new AccessTokenController( + $this->authorizationServerMock, + $this->allowedOriginRepository, + $this->psrHttpBridgeMock, + $this->errorResponderMock, + ); } public function testItIsInitializable(): void { $this->assertInstanceOf( AccessTokenController::class, - new AccessTokenController( - $this->authorizationServerMock, - $this->allowedOriginRepository, - ), + $this->mock(), ); } @@ -54,36 +75,29 @@ public function testItRespondsToAccessTokenRequest(): void $this->authorizationServerMock ->expects($this->once()) ->method('respondToAccessTokenRequest') - ->with($this->serverRequestMock, $this->isInstanceOf(Response::class)) + ->with($this->serverRequestMock, $this->isInstanceOf(ResponseInterface::class)) ->willReturn($this->responseMock); $this->assertSame( $this->responseMock, - (new AccessTokenController( - $this->authorizationServerMock, - $this->allowedOriginRepository, - ))->__invoke($this->serverRequestMock), + $this->mock()->__invoke($this->serverRequestMock), ); } public function testItHandlesCorsRequest(): void { $this->serverRequestMock->expects($this->once())->method('getMethod')->willReturn('OPTIONS'); - $userInfoControllerMock = $this->getMockBuilder(UserInfoController::class) - ->disableOriginalConstructor() - ->onlyMethods(['handleCors']) - ->getMock(); - $userInfoControllerMock->expects($this->once())->method('handleCors'); + $this->serverRequestMock->expects($this->once())->method('getHeaderLine')->with('Origin') + ->willReturn('http://localhost'); + $this->allowedOriginRepository->expects($this->once())->method('has') + ->with('http://localhost') + ->willReturn(true); - $userInfoControllerMock->__invoke($this->serverRequestMock); - } + $this->responseMock->expects($this->atLeast(4))->method('withHeader') + ->willReturnSelf(); + $this->responseMock->method('withBody')->willReturnSelf(); - /** - * @return \SimpleSAML\Module\oidc\Controller\AccessTokenController - */ - protected function prepareMockedInstance(): AccessTokenController - { - return new AccessTokenController($this->authorizationServerMock, $this->allowedOriginRepository); + $this->mock()->__invoke($this->serverRequestMock); } public function testItUsesRequestTrait(): void diff --git a/tests/src/Controller/ConfigurationDiscoveryControllerTest.php b/tests/src/Controller/ConfigurationDiscoveryControllerTest.php index 7d099451..c37698ef 100644 --- a/tests/src/Controller/ConfigurationDiscoveryControllerTest.php +++ b/tests/src/Controller/ConfigurationDiscoveryControllerTest.php @@ -17,8 +17,8 @@ class ConfigurationDiscoveryControllerTest extends TestCase { final public const OIDC_OP_METADATA = [ 'issuer' => 'http://localhost', - 'authorization_endpoint' => 'http://localhost/authorize.php', - 'token_endpoint' => 'http://localhost/token.php', + 'authorization_endpoint' => 'http://localhost/authorization', + 'token_endpoint' => 'http://localhost/token', 'userinfo_endpoint' => 'http://localhost/userinfo.php', 'jwks_uri' => 'http://localhost/jwks.php', 'scopes_supported' => ['openid'], diff --git a/tests/src/Controller/Traits/RequestTraitTest.php b/tests/src/Controller/Traits/RequestTraitTest.php index df99572f..ef7fa5f4 100644 --- a/tests/src/Controller/Traits/RequestTraitTest.php +++ b/tests/src/Controller/Traits/RequestTraitTest.php @@ -4,10 +4,14 @@ namespace SimpleSAML\Test\Module\oidc\Controller\Traits; +use Exception; use Laminas\Diactoros\Response; use Laminas\Diactoros\ServerRequest; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use Psr\Http\Message\ResponseFactoryInterface; +use ReflectionMethod; +use SimpleSAML\Module\oidc\Bridges\PsrHttpBridge; use SimpleSAML\Module\oidc\Controller\Traits\RequestTrait; use SimpleSAML\Module\oidc\Repositories\AllowedOriginRepository; use SimpleSAML\Module\oidc\Server\Exceptions\OidcServerException; @@ -17,20 +21,34 @@ */ class RequestTraitTest extends TestCase { - protected $prepareMockedInstance; + protected $mock; protected MockObject $serverRequestMock; protected MockObject $allowedOriginRepositoryMock; protected ReflectionMethod $handleCors; + protected MockObject $psrHttpBridgeMock; + protected MockObject $responseMock; + protected MockObject $responseFactoryMock; public function setUp(): void { $this->allowedOriginRepositoryMock = $this->createMock(AllowedOriginRepository::class); - $this->prepareMockedInstance = new class ($this->allowedOriginRepositoryMock) { + $this->psrHttpBridgeMock = $this->createMock(PsrHttpBridge::class); + $this->responseMock = $this->createMock(Response::class); + $this->responseMock->method('withBody')->willReturnSelf(); + $this->responseFactoryMock = $this->createMock(ResponseFactoryInterface::class); + $this->responseFactoryMock->method('createResponse')->willReturn($this->responseMock); + $this->psrHttpBridgeMock->method('getResponseFactory')->willReturn($this->responseFactoryMock); + + $this->mock = new class ( + $this->allowedOriginRepositoryMock, + $this->psrHttpBridgeMock + ) { use RequestTrait; public function __construct( public AllowedOriginRepository $allowedOriginRepository, + public PsrHttpBridge $psrHttpBridge, ) { } @@ -51,7 +69,7 @@ public function testItThrowsIfOriginHeaderNotAvailable(): void $this->serverRequestMock->expects($this->once())->method('getHeaderLine')->willReturn(''); $this->expectException(OidcServerException::class); - $this->prepareMockedInstance->handleCorsWrapper($this->serverRequestMock); + $this->mock->handleCorsWrapper($this->serverRequestMock); } /** @@ -62,10 +80,10 @@ public function testItThrowsIfOriginHeaderNotAllowed(): void $origin = 'https://example.org'; $this->serverRequestMock->expects($this->once())->method('getHeaderLine')->willReturn($origin); - $this->prepareMockedInstance->allowedOriginRepository->expects($this->once())->method('has')->willReturn(false); + $this->mock->allowedOriginRepository->expects($this->once())->method('has')->willReturn(false); $this->expectException(OidcServerException::class); - $this->prepareMockedInstance->handleCorsWrapper($this->serverRequestMock); + $this->mock->handleCorsWrapper($this->serverRequestMock); } public function testItHandlesCorsRequest(): void @@ -73,18 +91,32 @@ public function testItHandlesCorsRequest(): void $origin = 'https://example.org'; $this->serverRequestMock->expects($this->once())->method('getHeaderLine')->willReturn($origin); - $this->prepareMockedInstance->allowedOriginRepository->expects($this->once())->method('has')->willReturn(true); - - $response = $this->prepareMockedInstance->handleCorsWrapper($this->serverRequestMock); - $this->assertEquals(204, $response->getStatusCode()); - $this->assertSame( - $response->getHeaders(), - [ - 'Access-Control-Allow-Origin' => [$origin], - 'Access-Control-Allow-Methods' => ['GET, POST, OPTIONS'], - 'Access-Control-Allow-Headers' => ['Authorization, X-Requested-With'], - 'Access-Control-Allow-Credentials' => ['true'], - ], - ); + $this->mock->allowedOriginRepository->expects($this->once())->method('has')->willReturn(true); + $this->responseFactoryMock->expects($this->once())->method('createResponse') + ->with(204) + ->willReturn($this->responseMock); + + $headers = [ + 'Access-Control-Allow-Origin' => [$origin], + 'Access-Control-Allow-Methods' => ['GET, POST, OPTIONS'], + 'Access-Control-Allow-Headers' => ['Authorization, X-Requested-With'], + 'Access-Control-Allow-Credentials' => ['true'], + ]; + + $this->responseMock->expects($this->atLeast(4))->method('withHeader') + ->with( + $this->callback( + // Check if parameter is one of the expected header keys. + fn($header): bool => array_key_exists($header, $headers) || + throw new Exception('Invalid header (' . $header . ')'), + ), + $this->callback( + // Check if parameter is one of the expected header values. + fn($value): bool => !empty(array_filter($headers, fn($values): bool => in_array($value, $values))) || + throw new Exception('Invalid header value (' . $value . ')'), + ), + )->willReturnSelf(); + + $this->mock->handleCorsWrapper($this->serverRequestMock); } } diff --git a/tests/src/Controller/UserInfoControllerTest.php b/tests/src/Controller/UserInfoControllerTest.php index c74cd084..a985f8e4 100644 --- a/tests/src/Controller/UserInfoControllerTest.php +++ b/tests/src/Controller/UserInfoControllerTest.php @@ -10,6 +10,7 @@ use PHPUnit\Framework\TestCase; use Psr\Http\Message\ServerRequestInterface; use SimpleSAML\Error\UserNotFound; +use SimpleSAML\Module\oidc\Bridges\PsrHttpBridge; use SimpleSAML\Module\oidc\Controller\Traits\RequestTrait; use SimpleSAML\Module\oidc\Controller\UserInfoController; use SimpleSAML\Module\oidc\Entities\AccessTokenEntity; @@ -33,10 +34,8 @@ class UserInfoControllerTest extends TestCase protected MockObject $authorizationServerRequestMock; protected MockObject $accessTokenEntityMock; protected MockObject $userEntityMock; + protected MockObject $psrHttpBridge; - /** - * @throws \Exception - */ protected function setUp(): void { $this->resourceServerMock = $this->createMock(ResourceServer::class); @@ -49,9 +48,11 @@ protected function setUp(): void $this->authorizationServerRequestMock = $this->createMock(ServerRequestInterface::class); $this->accessTokenEntityMock = $this->createMock(AccessTokenEntity::class); $this->userEntityMock = $this->createMock(UserEntity::class); + + $this->psrHttpBridge = $this->createMock(PsrHttpBridge::class); } - protected function prepareMockedInstance(): UserInfoController + protected function mock(): UserInfoController { return new UserInfoController( $this->resourceServerMock, @@ -59,6 +60,7 @@ protected function prepareMockedInstance(): UserInfoController $this->userRepositoryMock, $this->allowedOriginRepositoryMock, $this->claimTranslatorExtractorMock, + $this->psrHttpBridge, ); } @@ -66,7 +68,7 @@ public function testItIsInitializable(): void { $this->assertInstanceOf( UserInfoController::class, - $this->prepareMockedInstance(), + $this->mock(), ); } @@ -131,7 +133,7 @@ public function testItReturnsUserClaims(): void $this->assertSame( ['email' => 'userid@localhost.localdomain'], - $this->prepareMockedInstance()->__invoke($this->serverRequestMock)->getPayload(), + $this->mock()->__invoke($this->serverRequestMock)->getPayload(), ); } @@ -167,7 +169,7 @@ public function testItThrowsIfAccessTokenNotFound(): void ->willReturn(null); $this->expectException(UserNotFound::class); - $this->prepareMockedInstance()->__invoke($this->serverRequestMock); + $this->mock()->__invoke($this->serverRequestMock); } /** @@ -211,7 +213,7 @@ public function testItThrowsIfUserNotFound(): void ->willReturn(null); $this->expectException(UserNotFound::class); - $this->prepareMockedInstance()->__invoke($this->serverRequestMock); + $this->mock()->__invoke($this->serverRequestMock); } public function testItHandlesCorsRequest(): void diff --git a/tests/src/Services/OpMetadataServiceTest.php b/tests/src/Services/OpMetadataServiceTest.php index c04e953a..b496aa7a 100644 --- a/tests/src/Services/OpMetadataServiceTest.php +++ b/tests/src/Services/OpMetadataServiceTest.php @@ -33,7 +33,7 @@ public function setUp(): void ->willReturnCallback(function ($path) { $paths = [ RoutesEnum::OpenIdAuthorization->value => 'http://localhost/authorization', - 'token.php' => 'http://localhost/token.php', + RoutesEnum::OpenIdToken->value => 'http://localhost/token', 'userinfo.php' => 'http://localhost/userinfo.php', 'jwks.php' => 'http://localhost/jwks.php', 'logout.php' => 'http://localhost/logout.php', @@ -76,7 +76,7 @@ public function testItReturnsExpectedMetadata(): void [ 'issuer' => 'http://localhost', 'authorization_endpoint' => 'http://localhost/authorization', - 'token_endpoint' => 'http://localhost/token.php', + 'token_endpoint' => 'http://localhost/token', 'userinfo_endpoint' => 'http://localhost/userinfo.php', 'end_session_endpoint' => 'http://localhost/logout.php', 'jwks_uri' => 'http://localhost/jwks.php',