From ebfa7206727f23d3e45785f5dd6b0daf006780f6 Mon Sep 17 00:00:00 2001 From: Antoine ROUGEOT Date: Sun, 1 Mar 2026 20:30:23 +0000 Subject: [PATCH 1/3] fix(BasicAuthBackend): accept 32-64 char client credentials Co-Authored-By: Oz --- lib/BasicAuthBackend.php | 4 +- tests/Unit/BasicAuthBackendTest.php | 254 ++++++++++++++++++++++++++++ 2 files changed, 256 insertions(+), 2 deletions(-) create mode 100644 tests/Unit/BasicAuthBackendTest.php diff --git a/lib/BasicAuthBackend.php b/lib/BasicAuthBackend.php index a4fb2e67..aa6c63a6 100644 --- a/lib/BasicAuthBackend.php +++ b/lib/BasicAuthBackend.php @@ -84,7 +84,7 @@ public function implementsActions($actions) { * Check if the password is correct without logging in the user */ public function checkPassword($uid, $password) { - if (strlen($uid) !== 64 || strlen($password) !== 64) { + if (strlen($uid) < 32 || strlen($uid) > 64 || strlen($password) < 32 || strlen($password) > 64) { return false; } @@ -187,7 +187,7 @@ public function toggleLock($uid) { * @return boolean */ public function userExists($uid) { - if (strlen($uid) !== 64) { + if (strlen($uid) < 32 || strlen($uid) > 64) { return false; } diff --git a/tests/Unit/BasicAuthBackendTest.php b/tests/Unit/BasicAuthBackendTest.php new file mode 100644 index 00000000..8271e8ff --- /dev/null +++ b/tests/Unit/BasicAuthBackendTest.php @@ -0,0 +1,254 @@ +request = $this->getMockBuilder(IRequest::class)->getMock(); + $this->urlGenerator = $this->getMockBuilder(IURLGenerator::class)->getMock(); + $this->logger = $this->getMockBuilder(LoggerInterface::class)->getMock(); + $this->appConfig = $this->getMockBuilder(IAppConfig::class)->getMock(); + $this->secureRandom = $this->getMockBuilder(ISecureRandom::class)->getMock(); + $this->time = $this->getMockBuilder(ITimeFactory::class)->getMock(); + $this->db = $this->getMockBuilder(IDBConnection::class)->getMock(); + $this->redirectUriMapper = $this->getMockBuilder(RedirectUriMapper::class)->setConstructorArgs([ + $this->db, + $this->time, + $this->appConfig])->getMock(); + $this->customClaimMapper = $this->getMockBuilder(CustomClaimMapper::class) + ->disableOriginalConstructor() + ->getMock(); + $this->clientMapper = $this->getMockBuilder(ClientMapper::class)->setConstructorArgs([ + $this->db, + $this->time, + $this->appConfig, + $this->redirectUriMapper, + $this->customClaimMapper, + $this->secureRandom, + $this->logger])->getMock(); + + $this->backend = new BasicAuthBackend( + $this->request, + $this->urlGenerator, + $this->clientMapper, + $this->logger + ); + } + + // --- checkPassword: length validation --- + + public function testCheckPasswordRejectsTooShort() { + $this->assertFalse($this->backend->checkPassword('short', 'short')); + } + + public function testCheckPasswordRejectsTooLong() { + $uid = str_repeat('a', 65); + $secret = str_repeat('b', 65); + $this->assertFalse($this->backend->checkPassword($uid, $secret)); + } + + public function testCheckPasswordRejectsEmpty() { + $this->assertFalse($this->backend->checkPassword('', '')); + } + + // --- checkPassword: accepts valid lengths on token endpoint --- + + private function setupValidClient(string $uid, string $secret): void { + $this->request->method('getRequestUri') + ->willReturn('/apps/oidc/token'); + + $client = $this->getMockBuilder(Client::class) + ->disableOriginalConstructor() + ->getMock(); + $client->method('getClientIdentifier')->willReturn($uid); + $client->method('getSecret')->willReturn($secret); + $client->method('getType')->willReturn('confidential'); + + $this->clientMapper->method('getByIdentifier') + ->with($uid) + ->willReturn($client); + } + + public function testCheckPasswordAccepts64CharCredentials() { + $this->setupValidClient($this->uid64, $this->secret64); + $this->assertTrue($this->backend->checkPassword($this->uid64, $this->secret64)); + } + + public function testCheckPasswordAccepts48CharCredentials() { + $this->setupValidClient($this->uid48, $this->secret48); + $this->assertTrue($this->backend->checkPassword($this->uid48, $this->secret48)); + } + + public function testCheckPasswordAccepts32CharCredentials() { + $this->setupValidClient($this->uid32, $this->secret32); + $this->assertTrue($this->backend->checkPassword($this->uid32, $this->secret32)); + } + + // --- checkPassword: endpoint restriction --- + + public function testCheckPasswordRejectsNonTokenEndpoint() { + $this->request->method('getRequestUri') + ->willReturn('/apps/files/index.php'); + + $this->assertFalse($this->backend->checkPassword($this->uid64, $this->secret64)); + } + + public function testCheckPasswordAcceptsIntrospectEndpoint() { + $this->request->method('getRequestUri') + ->willReturn('/apps/oidc/introspect'); + + $client = $this->getMockBuilder(Client::class) + ->disableOriginalConstructor() + ->getMock(); + $client->method('getClientIdentifier')->willReturn($this->uid64); + $client->method('getSecret')->willReturn($this->secret64); + $client->method('getType')->willReturn('confidential'); + + $this->clientMapper->method('getByIdentifier') + ->with($this->uid64) + ->willReturn($client); + + $this->assertTrue($this->backend->checkPassword($this->uid64, $this->secret64)); + } + + // --- checkPassword: wrong secret --- + + public function testCheckPasswordRejectsWrongSecret() { + $this->request->method('getRequestUri') + ->willReturn('/apps/oidc/token'); + + $client = $this->getMockBuilder(Client::class) + ->disableOriginalConstructor() + ->getMock(); + $client->method('getClientIdentifier')->willReturn($this->uid64); + $client->method('getSecret')->willReturn('WrongSecretThatIsExactlySixtyFourCharactersLongForTestingPurpose1'); + $client->method('getType')->willReturn('confidential'); + + $this->clientMapper->method('getByIdentifier') + ->with($this->uid64) + ->willReturn($client); + + $this->assertFalse($this->backend->checkPassword($this->uid64, $this->secret64)); + } + + // --- checkPassword: unknown client --- + + public function testCheckPasswordRejectsUnknownClient() { + $this->request->method('getRequestUri') + ->willReturn('/apps/oidc/token'); + + $this->clientMapper->method('getByIdentifier') + ->willThrowException(new ClientNotFoundException()); + + $this->assertFalse($this->backend->checkPassword($this->uid64, $this->secret64)); + } + + // --- userExists: length validation --- + + public function testUserExistsRejectsTooShort() { + $this->assertFalse($this->backend->userExists('short')); + } + + public function testUserExistsRejectsTooLong() { + $this->assertFalse($this->backend->userExists(str_repeat('a', 65))); + } + + public function testUserExistsAccepts64Char() { + $client = $this->getMockBuilder(Client::class) + ->disableOriginalConstructor() + ->getMock(); + $client->method('getClientIdentifier')->willReturn($this->uid64); + + $this->clientMapper->method('getByIdentifier') + ->with($this->uid64) + ->willReturn($client); + + $this->assertTrue($this->backend->userExists($this->uid64)); + } + + public function testUserExistsAccepts48Char() { + $client = $this->getMockBuilder(Client::class) + ->disableOriginalConstructor() + ->getMock(); + $client->method('getClientIdentifier')->willReturn($this->uid48); + + $this->clientMapper->method('getByIdentifier') + ->with($this->uid48) + ->willReturn($client); + + $this->assertTrue($this->backend->userExists($this->uid48)); + } + + public function testUserExistsAccepts32Char() { + $client = $this->getMockBuilder(Client::class) + ->disableOriginalConstructor() + ->getMock(); + $client->method('getClientIdentifier')->willReturn($this->uid32); + + $this->clientMapper->method('getByIdentifier') + ->with($this->uid32) + ->willReturn($client); + + $this->assertTrue($this->backend->userExists($this->uid32)); + } + + public function testUserExistsReturnsFalseForUnknownClient() { + $this->clientMapper->method('getByIdentifier') + ->willThrowException(new ClientNotFoundException()); + + $this->assertFalse($this->backend->userExists($this->uid64)); + } +} From 9eb9981d1042c2ea3ab5e18d2d76c5d34c903ed6 Mon Sep 17 00:00:00 2001 From: Antoine ROUGEOT Date: Sun, 5 Apr 2026 21:44:18 +0100 Subject: [PATCH 2/3] fix(validation): allow RFC 6749 VSCHAR characters in client_id and client_secret --- lib/Command/Clients/OIDCCreate.php | 12 +- lib/Controller/SettingsController.php | 8 +- tests/Unit/Command/Clients/OIDCCreateTest.php | 110 ++++++++++++++++++ .../Controller/SettingsControllerTest.php | 96 +++++++++++++++ 4 files changed, 216 insertions(+), 10 deletions(-) create mode 100644 tests/Unit/Command/Clients/OIDCCreateTest.php diff --git a/lib/Command/Clients/OIDCCreate.php b/lib/Command/Clients/OIDCCreate.php index d512b2df..3a76443e 100644 --- a/lib/Command/Clients/OIDCCreate.php +++ b/lib/Command/Clients/OIDCCreate.php @@ -105,14 +105,14 @@ protected function configure(): void 'client_id', null, InputOption::VALUE_OPTIONAL, - 'The client id to be used. If not provided the client id will be generated internally. Requirements: chars A-Za-z0-9 & min length 32 & max length 64', + 'The client id to be used. If not provided the client id will be generated internally. Requirements: printable ASCII except : and length 32-64', '' ) ->addOption( 'client_secret', null, InputOption::VALUE_OPTIONAL, - 'The client secret to be used. If not provided the client secret will be generated internally. Requirements: chars A-Za-z0-9 & min length 32 & max length 64', + 'The client secret to be used. If not provided the client secret will be generated internally. Requirements: printable ASCII except : and length 32-64', '' ) ->addOption( @@ -157,15 +157,15 @@ protected function execute(InputInterface $input, OutputInterface $output): int $clientId = $input->getOption('client_id'); $clientSecret = $input->getOption('client_secret'); if (isset($clientId) && trim($clientId) !== '') { - if (filter_var($clientId, FILTER_VALIDATE_REGEXP, array("options" => array("regexp" => "/^[A-Za-z0-9]{32,64}$/"))) === false) { - throw new CliException("Your clientId must comply with the following rules: chars A-Za-z0-9 & min length 32 & max length 64"); + if (filter_var($clientId, FILTER_VALIDATE_REGEXP, array("options" => array("regexp" => "/^[\x21-\x39\x3B-\x7E]{32,64}$/"))) === false) { + throw new CliException("Your clientId must comply with the following rules: printable ASCII except : and length 32-64"); } $client->setClientIdentifier($clientId); } if (isset($clientSecret) && trim($clientSecret) !== '') { - if (filter_var($clientSecret, FILTER_VALIDATE_REGEXP, array("options" => array("regexp" => "/^[A-Za-z0-9]{32,64}$/"))) === false) { - throw new CliException("Your clientSecret must comply with the following rules: chars A-Za-z0-9 & min length 32 & max length 64"); + if (filter_var($clientSecret, FILTER_VALIDATE_REGEXP, array("options" => array("regexp" => "/^[\x21-\x39\x3B-\x7E]{32,64}$/"))) === false) { + throw new CliException("Your clientSecret must comply with the following rules: printable ASCII except : and length 32-64"); } $client->setSecret($clientSecret); } diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php index 3f3448c2..6cc650e5 100644 --- a/lib/Controller/SettingsController.php +++ b/lib/Controller/SettingsController.php @@ -134,15 +134,15 @@ public function addClient( ); if (isset($clientId) && trim($clientId) !== '') { - if (filter_var($clientId, FILTER_VALIDATE_REGEXP, array("options" => array("regexp" => "/^[A-Za-z0-9]{32,64}$/"))) === false) { - return new JSONResponse(['message' => $this->l->t('Your client ID must comply with the following rules: chars A-Za-z0-9 & min length 32 & max length 64')], Http::STATUS_BAD_REQUEST); + if (filter_var($clientId, FILTER_VALIDATE_REGEXP, array("options" => array("regexp" => "/^[\x21-\x39\x3B-\x7E]{32,64}$/"))) === false) { + return new JSONResponse(['message' => $this->l->t('Your client ID must comply with the following rules: printable ASCII except : and length 32-64')], Http::STATUS_BAD_REQUEST); } $client->setClientIdentifier($clientId); } if (isset($clientSecret) && trim($clientSecret) !== '') { - if (filter_var($clientSecret, FILTER_VALIDATE_REGEXP, array("options" => array("regexp" => "/^[A-Za-z0-9]{32,64}$/"))) === false) { - return new JSONResponse(['message' => $this->l->t('Your client secret must comply with the following rules: chars A-Za-z0-9 & min length 32 & max length 64')], Http::STATUS_BAD_REQUEST); + if (filter_var($clientSecret, FILTER_VALIDATE_REGEXP, array("options" => array("regexp" => "/^[\x21-\x39\x3B-\x7E]{32,64}$/"))) === false) { + return new JSONResponse(['message' => $this->l->t('Your client secret must comply with the following rules: printable ASCII except : and length 32-64')], Http::STATUS_BAD_REQUEST); } $client->setSecret($clientSecret); } diff --git a/tests/Unit/Command/Clients/OIDCCreateTest.php b/tests/Unit/Command/Clients/OIDCCreateTest.php new file mode 100644 index 00000000..37ccdcad --- /dev/null +++ b/tests/Unit/Command/Clients/OIDCCreateTest.php @@ -0,0 +1,110 @@ +appConfig = $this->createMock(IAppConfig::class); + $this->clientMapper = $this->createMock(ClientMapper::class); + $this->redirectUriService = $this->createMock(RedirectUriService::class); + + $this->appConfig + ->method('getAppValueString') + ->willReturnMap([ + [Application::APP_CONFIG_DEFAULT_TOKEN_TYPE, Application::DEFAULT_TOKEN_TYPE, Application::DEFAULT_TOKEN_TYPE], + [Application::APP_CONFIG_ALLOW_SUBDOMAIN_WILDCARDS, Application::DEFAULT_ALLOW_SUBDOMAIN_WILDCARDS, Application::DEFAULT_ALLOW_SUBDOMAIN_WILDCARDS], + ]); + + $this->redirectUriService + ->method('isValidRedirectUri') + ->willReturn(true); + + $this->clientMapper + ->method('insert') + ->willReturnCallback(static fn (Client $client) => $client); + + $this->command = new OIDCCreate( + $this->appConfig, + $this->clientMapper, + $this->redirectUriService + ); + } + + #[DataProvider('validCredentialProvider')] + public function testExecuteAcceptsValidCredentials(string $clientId, string $clientSecret): void + { + $tester = new CommandTester($this->command); + + $statusCode = $tester->execute([ + 'name' => 'Test Client', + 'redirect_uris' => ['https://local.lo/callback'], + '--client_id' => $clientId, + '--client_secret' => $clientSecret, + ]); + + $this->assertSame(Command::SUCCESS, $statusCode); + $display = $tester->getDisplay(); + $this->assertStringContainsString($clientId, $display); + $this->assertStringContainsString($clientSecret, $display); + } + + public function testExecuteRejectsColonInClientId(): void + { + $tester = new CommandTester($this->command); + + $statusCode = $tester->execute([ + 'name' => 'Test Client', + 'redirect_uris' => ['https://local.lo/callback'], + '--client_id' => 'client:id-with-colon-01234567890123', + '--client_secret' => '0582bb51ac974f318c4fe11779c439a0', + ]); + + $this->assertSame(Command::FAILURE, $statusCode); + $this->assertStringContainsString( + 'Your clientId must comply with the following rules: printable ASCII except : and length 32-64', + $tester->getDisplay() + ); + } + + public static function validCredentialProvider(): array + { + return [ + 'alphanumeric credentials' => [ + '0582bb51ac974f318c4fe11779c439a0', + '0582bb51ac974f318c4fe11779c439a0', + ], + 'hyphen in client id' => [ + 'client-id-with-hyphen-012345678901', + '0582bb51ac974f318c4fe11779c439a0', + ], + 'underscore in client id' => [ + 'client_id_with_underscores_0123456', + '0582bb51ac974f318c4fe11779c439a0', + ], + 'dot in client id' => [ + 'client.id.with.dots.01234567890123', + '0582bb51ac974f318c4fe11779c439a0', + ], + ]; + } +} diff --git a/tests/Unit/Controller/SettingsControllerTest.php b/tests/Unit/Controller/SettingsControllerTest.php index ef2c65ac..3e53c392 100644 --- a/tests/Unit/Controller/SettingsControllerTest.php +++ b/tests/Unit/Controller/SettingsControllerTest.php @@ -224,6 +224,74 @@ function ($arg) { $this->assertEquals($clientSecret, $result->getData()['clientSecret']); } + #[DataProvider('validCredentialProvider')] + public function testAddClientAcceptsValidCredentials(string $clientId, string $clientSecret): void { + $name = 'TEST'; + $redirectUri = 'https://local.lo'; + $signingAlg = 'RS256'; + $type = 'confidential'; + $flowType = 'code'; + $tokenType = 'opaque'; + + $this->clientMapper + ->method('insert') + ->willReturnCallback( + function ($arg) { + $client = $arg; + $client->setId(1); + return $client; + } + ); + + $this->redirectUriMapper + ->method('getByClientId') + ->willReturnCallback( + function ($arg) { + $redirectUri = new RedirectUri(); + $redirectUri->setId(1); + $redirectUri->setClientId(1); + $redirectUri->setRedirectUri('https://local.lo'); + return [$redirectUri]; + } + ); + + $result = $this->controller->addClient( + $name, + $redirectUri, + $signingAlg, + $type, + $flowType, + $tokenType, + $clientId, + $clientSecret + ); + + $this->assertEquals(Http::STATUS_OK, $result->getStatus(), 'Status Code does not match!'); + $this->assertEquals($clientId, $result->getData()['clientId']); + $this->assertEquals($clientSecret, $result->getData()['clientSecret']); + } + + public static function validCredentialProvider(): array { + return [ + 'alphanumeric credentials' => [ + '0582bb51ac974f318c4fe11779c439a0', + '0582bb51ac974f318c4fe11779c439a0', + ], + 'hyphen in client id' => [ + 'client-id-with-hyphen-012345678901', + '0582bb51ac974f318c4fe11779c439a0', + ], + 'underscore in client id' => [ + 'client_id_with_underscores_0123456', + '0582bb51ac974f318c4fe11779c439a0', + ], + 'dot in client id' => [ + 'client.id.with.dots.01234567890123', + '0582bb51ac974f318c4fe11779c439a0', + ], + ]; + } + public function testAddClientwWrongCreds1() { $name = 'TEST'; $redirectUri = 'https://local.lo'; @@ -365,6 +433,34 @@ function ($arg) { $this->assertEquals(Http::STATUS_BAD_REQUEST, $result->getStatus(), 'Status Code does not match!'); } + public function testAddClientRejectsColonInClientId(): void { + $name = 'TEST'; + $redirectUri = 'https://local.lo'; + $signingAlg = 'RS256'; + $type = 'confidential'; + $flowType = 'code'; + $tokenType = 'opaque'; + $clientId = 'client:id-with-colon-01234567890123'; + $clientSecret = '0582bb51ac974f318c4fe11779c439a0'; + + $result = $this->controller->addClient( + $name, + $redirectUri, + $signingAlg, + $type, + $flowType, + $tokenType, + $clientId, + $clientSecret + ); + + $this->assertEquals(Http::STATUS_BAD_REQUEST, $result->getStatus(), 'Status Code does not match!'); + $this->assertEquals( + 'Your client ID must comply with the following rules: printable ASCII except : and length 32-64', + $result->getData()['message'] + ); + } + public function testAddClientBadRedirectUri() { $name = 'TEST'; $redirectUri = 'bad-uri'; From d9a4784ead74dfa055cc026f652af3b6b398d540 Mon Sep 17 00:00:00 2001 From: Antoine ROUGEOT Date: Thu, 9 Apr 2026 13:21:29 +0100 Subject: [PATCH 3/3] test: fix CI unit tests for manual client credentials --- tests/Unit/BasicAuthBackendTest.php | 48 +++++++------------ .../Controller/SettingsControllerTest.php | 1 + 2 files changed, 19 insertions(+), 30 deletions(-) diff --git a/tests/Unit/BasicAuthBackendTest.php b/tests/Unit/BasicAuthBackendTest.php index 8271e8ff..dbcfd4be 100644 --- a/tests/Unit/BasicAuthBackendTest.php +++ b/tests/Unit/BasicAuthBackendTest.php @@ -110,12 +110,10 @@ private function setupValidClient(string $uid, string $secret): void { $this->request->method('getRequestUri') ->willReturn('/apps/oidc/token'); - $client = $this->getMockBuilder(Client::class) - ->disableOriginalConstructor() - ->getMock(); - $client->method('getClientIdentifier')->willReturn($uid); - $client->method('getSecret')->willReturn($secret); - $client->method('getType')->willReturn('confidential'); + $client = new Client(); + $client->setClientIdentifier($uid); + $client->setSecret($secret); + $client->setType('confidential'); $this->clientMapper->method('getByIdentifier') ->with($uid) @@ -150,12 +148,10 @@ public function testCheckPasswordAcceptsIntrospectEndpoint() { $this->request->method('getRequestUri') ->willReturn('/apps/oidc/introspect'); - $client = $this->getMockBuilder(Client::class) - ->disableOriginalConstructor() - ->getMock(); - $client->method('getClientIdentifier')->willReturn($this->uid64); - $client->method('getSecret')->willReturn($this->secret64); - $client->method('getType')->willReturn('confidential'); + $client = new Client(); + $client->setClientIdentifier($this->uid64); + $client->setSecret($this->secret64); + $client->setType('confidential'); $this->clientMapper->method('getByIdentifier') ->with($this->uid64) @@ -170,12 +166,10 @@ public function testCheckPasswordRejectsWrongSecret() { $this->request->method('getRequestUri') ->willReturn('/apps/oidc/token'); - $client = $this->getMockBuilder(Client::class) - ->disableOriginalConstructor() - ->getMock(); - $client->method('getClientIdentifier')->willReturn($this->uid64); - $client->method('getSecret')->willReturn('WrongSecretThatIsExactlySixtyFourCharactersLongForTestingPurpose1'); - $client->method('getType')->willReturn('confidential'); + $client = new Client(); + $client->setClientIdentifier($this->uid64); + $client->setSecret('WrongSecretThatIsExactlySixtyFourCharactersLongForTestingPurpose1'); + $client->setType('confidential'); $this->clientMapper->method('getByIdentifier') ->with($this->uid64) @@ -207,10 +201,8 @@ public function testUserExistsRejectsTooLong() { } public function testUserExistsAccepts64Char() { - $client = $this->getMockBuilder(Client::class) - ->disableOriginalConstructor() - ->getMock(); - $client->method('getClientIdentifier')->willReturn($this->uid64); + $client = new Client(); + $client->setClientIdentifier($this->uid64); $this->clientMapper->method('getByIdentifier') ->with($this->uid64) @@ -220,10 +212,8 @@ public function testUserExistsAccepts64Char() { } public function testUserExistsAccepts48Char() { - $client = $this->getMockBuilder(Client::class) - ->disableOriginalConstructor() - ->getMock(); - $client->method('getClientIdentifier')->willReturn($this->uid48); + $client = new Client(); + $client->setClientIdentifier($this->uid48); $this->clientMapper->method('getByIdentifier') ->with($this->uid48) @@ -233,10 +223,8 @@ public function testUserExistsAccepts48Char() { } public function testUserExistsAccepts32Char() { - $client = $this->getMockBuilder(Client::class) - ->disableOriginalConstructor() - ->getMock(); - $client->method('getClientIdentifier')->willReturn($this->uid32); + $client = new Client(); + $client->setClientIdentifier($this->uid32); $this->clientMapper->method('getByIdentifier') ->with($this->uid32) diff --git a/tests/Unit/Controller/SettingsControllerTest.php b/tests/Unit/Controller/SettingsControllerTest.php index 3e53c392..b94ca80e 100644 --- a/tests/Unit/Controller/SettingsControllerTest.php +++ b/tests/Unit/Controller/SettingsControllerTest.php @@ -105,6 +105,7 @@ public function setUp(): void { $this->db, $this->groupManager])->getMock(); $this->l = $this->getMockBuilder(IL10N::class)->getMock(); + $this->l->method('t')->willReturnCallback(static fn (string $text): string => $text); $this->redirectUriService = new RedirectUriService( $this->logger );