diff --git a/apps/dav/appinfo/v1/webdav.php b/apps/dav/appinfo/v1/webdav.php index ed02b4c259ae9..50c3943651051 100644 --- a/apps/dav/appinfo/v1/webdav.php +++ b/apps/dav/appinfo/v1/webdav.php @@ -67,7 +67,8 @@ $bearerAuthPlugin = new \OCA\DAV\Connector\Sabre\BearerAuth( \OC::$server->getUserSession(), \OC::$server->getSession(), - \OC::$server->getRequest() + \OC::$server->getRequest(), + \OC::$server->getConfig(), ); $authPlugin->addBackend($bearerAuthPlugin); diff --git a/apps/dav/lib/Connector/Sabre/BearerAuth.php b/apps/dav/lib/Connector/Sabre/BearerAuth.php index 6fd61c44b3452..b05241c6c4423 100644 --- a/apps/dav/lib/Connector/Sabre/BearerAuth.php +++ b/apps/dav/lib/Connector/Sabre/BearerAuth.php @@ -23,6 +23,7 @@ */ namespace OCA\DAV\Connector\Sabre; +use OCP\IConfig; use OCP\IRequest; use OCP\ISession; use OCP\IUserSession; @@ -34,15 +35,18 @@ class BearerAuth extends AbstractBearer { private IUserSession $userSession; private ISession $session; private IRequest $request; + private IConfig $config; private string $principalPrefix; public function __construct(IUserSession $userSession, ISession $session, IRequest $request, + IConfig $config, $principalPrefix = 'principals/users/') { $this->userSession = $userSession; $this->session = $session; $this->request = $request; + $this->config = $config; $this->principalPrefix = $principalPrefix; // setup realm @@ -81,6 +85,14 @@ public function validateBearerToken($bearerToken) { * @param ResponseInterface $response */ public function challenge(RequestInterface $request, ResponseInterface $response): void { + // Legacy ownCloud clients still authenticate via OAuth2 + $enableOcClients = $this->config->getSystemValueBool('oauth2.enable_oc_clients', false); + $userAgent = $request->getHeader('User-Agent'); + if ($enableOcClients && $userAgent !== null && str_contains($userAgent, 'mirall')) { + parent::challenge($request, $response); + return; + } + $response->setStatus(401); } } diff --git a/apps/dav/lib/Server.php b/apps/dav/lib/Server.php index 459db0c66993e..9f68246583e3c 100644 --- a/apps/dav/lib/Server.php +++ b/apps/dav/lib/Server.php @@ -153,7 +153,8 @@ public function __construct(IRequest $request, string $baseUri) { $bearerAuthBackend = new BearerAuth( \OC::$server->getUserSession(), \OC::$server->getSession(), - \OC::$server->getRequest() + \OC::$server->getRequest(), + \OC::$server->getConfig(), ); $authPlugin->addBackend($bearerAuthBackend); // because we are throwing exceptions this plugin has to be the last one diff --git a/apps/dav/tests/unit/Connector/Sabre/BearerAuthTest.php b/apps/dav/tests/unit/Connector/Sabre/BearerAuthTest.php index bfc8d9f9c53c6..cf8b9a79574bb 100644 --- a/apps/dav/tests/unit/Connector/Sabre/BearerAuthTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/BearerAuthTest.php @@ -25,6 +25,7 @@ namespace OCA\DAV\Tests\unit\Connector\Sabre; use OCA\DAV\Connector\Sabre\BearerAuth; +use OCP\IConfig; use OCP\IRequest; use OCP\ISession; use OCP\IUser; @@ -45,6 +46,8 @@ class BearerAuthTest extends TestCase { private $request; /** @var BearerAuth */ private $bearerAuth; + /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ + private $config; protected function setUp(): void { parent::setUp(); @@ -52,11 +55,13 @@ protected function setUp(): void { $this->userSession = $this->createMock(\OC\User\Session::class); $this->session = $this->createMock(ISession::class); $this->request = $this->createMock(IRequest::class); + $this->config = $this->createMock(IConfig::class); $this->bearerAuth = new BearerAuth( $this->userSession, $this->session, - $this->request + $this->request, + $this->config, ); } diff --git a/apps/oauth2/appinfo/info.xml b/apps/oauth2/appinfo/info.xml index 30b32312a444d..40c816553a130 100644 --- a/apps/oauth2/appinfo/info.xml +++ b/apps/oauth2/appinfo/info.xml @@ -29,6 +29,10 @@ + + OCA\OAuth2\Command\ImportLegacyOcClient + + OCA\OAuth2\Settings\Admin diff --git a/apps/oauth2/composer/composer/autoload_classmap.php b/apps/oauth2/composer/composer/autoload_classmap.php index cba0ef43dfc2a..f5fc5bfe2519b 100644 --- a/apps/oauth2/composer/composer/autoload_classmap.php +++ b/apps/oauth2/composer/composer/autoload_classmap.php @@ -8,6 +8,7 @@ return array( 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', 'OCA\\OAuth2\\BackgroundJob\\CleanupExpiredAuthorizationCode' => $baseDir . '/../lib/BackgroundJob/CleanupExpiredAuthorizationCode.php', + 'OCA\\OAuth2\\Command\\ImportLegacyOcClient' => $baseDir . '/../lib/Command/ImportLegacyOcClient.php', 'OCA\\OAuth2\\Controller\\LoginRedirectorController' => $baseDir . '/../lib/Controller/LoginRedirectorController.php', 'OCA\\OAuth2\\Controller\\OauthApiController' => $baseDir . '/../lib/Controller/OauthApiController.php', 'OCA\\OAuth2\\Controller\\SettingsController' => $baseDir . '/../lib/Controller/SettingsController.php', diff --git a/apps/oauth2/composer/composer/autoload_static.php b/apps/oauth2/composer/composer/autoload_static.php index c4905bc96c477..c4843fa1990f0 100644 --- a/apps/oauth2/composer/composer/autoload_static.php +++ b/apps/oauth2/composer/composer/autoload_static.php @@ -23,6 +23,7 @@ class ComposerStaticInitOAuth2 public static $classMap = array ( 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', 'OCA\\OAuth2\\BackgroundJob\\CleanupExpiredAuthorizationCode' => __DIR__ . '/..' . '/../lib/BackgroundJob/CleanupExpiredAuthorizationCode.php', + 'OCA\\OAuth2\\Command\\ImportLegacyOcClient' => __DIR__ . '/..' . '/../lib/Command/ImportLegacyOcClient.php', 'OCA\\OAuth2\\Controller\\LoginRedirectorController' => __DIR__ . '/..' . '/../lib/Controller/LoginRedirectorController.php', 'OCA\\OAuth2\\Controller\\OauthApiController' => __DIR__ . '/..' . '/../lib/Controller/OauthApiController.php', 'OCA\\OAuth2\\Controller\\SettingsController' => __DIR__ . '/..' . '/../lib/Controller/SettingsController.php', diff --git a/apps/oauth2/lib/Command/ImportLegacyOcClient.php b/apps/oauth2/lib/Command/ImportLegacyOcClient.php new file mode 100644 index 0000000000000..ee95c556c4f72 --- /dev/null +++ b/apps/oauth2/lib/Command/ImportLegacyOcClient.php @@ -0,0 +1,76 @@ +setName('oauth2:import-legacy-oc-client'); + $this->setDescription('This command is only required to be run on instances which were migrated from ownCloud without the oauth2.enable_oc_clients system config! Import a legacy Oauth2 client from an ownCloud instance and migrate it. The data is expected to be straight out of the database table oc_oauth2_clients.'); + $this->addArgument( + self::ARGUMENT_CLIENT_ID, + InputArgument::REQUIRED, + 'Value of the "identifier" column', + ); + $this->addArgument( + self::ARGUMENT_CLIENT_SECRET, + InputArgument::REQUIRED, + 'Value of the "secret" column', + ); + } + + public function isEnabled(): bool { + return $this->config->getSystemValueBool('oauth2.enable_oc_clients', false); + } + + protected function execute(InputInterface $input, OutputInterface $output): int { + /** @var string $clientId */ + $clientId = $input->getArgument(self::ARGUMENT_CLIENT_ID); + + /** @var string $clientSecret */ + $clientSecret = $input->getArgument(self::ARGUMENT_CLIENT_SECRET); + + // Should not happen but just to be sure + if (empty($clientId) || empty($clientSecret)) { + return 1; + } + + $hashedClientSecret = bin2hex($this->crypto->calculateHMAC($clientSecret)); + + $client = new Client(); + $client->setName('ownCloud Desktop Client'); + $client->setRedirectUri('http://localhost:*'); + $client->setClientIdentifier($clientId); + $client->setSecret($hashedClientSecret); + $this->clientMapper->insert($client); + + $output->writeln('Client imported successfully'); + return 0; + } +} diff --git a/apps/oauth2/lib/Controller/LoginRedirectorController.php b/apps/oauth2/lib/Controller/LoginRedirectorController.php index 4c5b905a1ee0b..7a85ad1b73a96 100644 --- a/apps/oauth2/lib/Controller/LoginRedirectorController.php +++ b/apps/oauth2/lib/Controller/LoginRedirectorController.php @@ -34,6 +34,7 @@ use OCP\AppFramework\Http; use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Http\TemplateResponse; +use OCP\IConfig; use OCP\IL10N; use OCP\IRequest; use OCP\ISession; @@ -48,6 +49,7 @@ class LoginRedirectorController extends Controller { private $session; /** @var IL10N */ private $l; + private IConfig $config; /** * @param string $appName @@ -56,18 +58,21 @@ class LoginRedirectorController extends Controller { * @param ClientMapper $clientMapper * @param ISession $session * @param IL10N $l + * @param IConfig $config */ public function __construct(string $appName, IRequest $request, IURLGenerator $urlGenerator, ClientMapper $clientMapper, ISession $session, - IL10N $l) { + IL10N $l, + IConfig $config) { parent::__construct($appName, $request); $this->urlGenerator = $urlGenerator; $this->clientMapper = $clientMapper; $this->session = $session; $this->l = $l; + $this->config = $config; } /** @@ -80,6 +85,7 @@ public function __construct(string $appName, * @param string $client_id Client ID * @param string $state State of the flow * @param string $response_type Response type for the flow + * @param string $redirect_uri URI to redirect to after the flow (is only used for legacy ownCloud clients) * @return TemplateResponse|RedirectResponse * * 200: Client not found @@ -87,7 +93,8 @@ public function __construct(string $appName, */ public function authorize($client_id, $state, - $response_type): TemplateResponse|RedirectResponse { + $response_type, + string $redirect_uri = ''): TemplateResponse|RedirectResponse { try { $client = $this->clientMapper->getByIdentifier($client_id); } catch (ClientNotFoundException $e) { @@ -103,12 +110,20 @@ public function authorize($client_id, return new RedirectResponse($url); } + $enableOcClients = $this->config->getSystemValueBool('oauth2.enable_oc_clients', false); + + $providedRedirectUri = ''; + if ($enableOcClients && $client->getRedirectUri() === 'http://localhost:*') { + $providedRedirectUri = $redirect_uri; + } + $this->session->set('oauth.state', $state); $targetUrl = $this->urlGenerator->linkToRouteAbsolute( 'core.ClientFlowLogin.showAuthPickerPage', [ 'clientIdentifier' => $client->getClientIdentifier(), + 'providedRedirectUri' => $providedRedirectUri, ] ); return new RedirectResponse($targetUrl); diff --git a/apps/oauth2/openapi.json b/apps/oauth2/openapi.json index c745e73bf7938..4cfba5985809a 100644 --- a/apps/oauth2/openapi.json +++ b/apps/oauth2/openapi.json @@ -65,6 +65,15 @@ "schema": { "type": "string" } + }, + { + "name": "redirect_uri", + "in": "query", + "description": "URI to redirect to after the flow (is only used for legacy ownCloud clients)", + "schema": { + "type": "string", + "default": "" + } } ], "responses": { diff --git a/apps/oauth2/tests/Controller/LoginRedirectorControllerTest.php b/apps/oauth2/tests/Controller/LoginRedirectorControllerTest.php index 7f45f9c5b4bc0..f53d23f567f90 100644 --- a/apps/oauth2/tests/Controller/LoginRedirectorControllerTest.php +++ b/apps/oauth2/tests/Controller/LoginRedirectorControllerTest.php @@ -31,6 +31,7 @@ use OCA\OAuth2\Exceptions\ClientNotFoundException; use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Http\TemplateResponse; +use OCP\IConfig; use OCP\IL10N; use OCP\IRequest; use OCP\ISession; @@ -53,6 +54,8 @@ class LoginRedirectorControllerTest extends TestCase { private $loginRedirectorController; /** @var IL10N */ private $l; + /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ + private $config; protected function setUp(): void { parent::setUp(); @@ -62,6 +65,7 @@ protected function setUp(): void { $this->clientMapper = $this->createMock(ClientMapper::class); $this->session = $this->createMock(ISession::class); $this->l = $this->createMock(IL10N::class); + $this->config = $this->createMock(IConfig::class); $this->loginRedirectorController = new LoginRedirectorController( 'oauth2', @@ -69,7 +73,8 @@ protected function setUp(): void { $this->urlGenerator, $this->clientMapper, $this->session, - $this->l + $this->l, + $this->config, ); } @@ -92,9 +97,15 @@ public function testAuthorize() { 'core.ClientFlowLogin.showAuthPickerPage', [ 'clientIdentifier' => 'MyClientIdentifier', + 'providedRedirectUri' => '', ] ) ->willReturn('https://example.com/?clientIdentifier=foo'); + $this->config + ->expects($this->once()) + ->method('getSystemValueBool') + ->with('oauth2.enable_oc_clients', false) + ->willReturn(false); $expected = new RedirectResponse('https://example.com/?clientIdentifier=foo'); $this->assertEquals($expected, $this->loginRedirectorController->authorize('MyClientId', 'MyState', 'code')); @@ -118,6 +129,73 @@ public function testAuthorizeWrongResponseType() { $this->assertEquals($expected, $this->loginRedirectorController->authorize('MyClientId', 'MyState', 'wrongcode')); } + public function testAuthorizeWithLegacyOcClient(): void { + $client = new Client(); + $client->setClientIdentifier('MyClientIdentifier'); + $client->setRedirectUri('http://localhost:*'); + $this->clientMapper + ->expects($this->once()) + ->method('getByIdentifier') + ->with('MyClientId') + ->willReturn($client); + $this->session + ->expects($this->once()) + ->method('set') + ->with('oauth.state', 'MyState'); + $this->urlGenerator + ->expects($this->once()) + ->method('linkToRouteAbsolute') + ->with( + 'core.ClientFlowLogin.showAuthPickerPage', + [ + 'clientIdentifier' => 'MyClientIdentifier', + 'providedRedirectUri' => 'http://localhost:30000', + ] + ) + ->willReturn('https://example.com/?clientIdentifier=foo&providedRedirectUri=http://localhost:30000'); + $this->config + ->expects($this->once()) + ->method('getSystemValueBool') + ->with('oauth2.enable_oc_clients', false) + ->willReturn(true); + + $expected = new RedirectResponse('https://example.com/?clientIdentifier=foo&providedRedirectUri=http://localhost:30000'); + $this->assertEquals($expected, $this->loginRedirectorController->authorize('MyClientId', 'MyState', 'code', 'http://localhost:30000')); + } + + public function testAuthorizeNotForwardingUntrustedURIs(): void { + $client = new Client(); + $client->setClientIdentifier('MyClientIdentifier'); + $this->clientMapper + ->expects($this->once()) + ->method('getByIdentifier') + ->with('MyClientId') + ->willReturn($client); + $this->session + ->expects($this->once()) + ->method('set') + ->with('oauth.state', 'MyState'); + $this->urlGenerator + ->expects($this->once()) + ->method('linkToRouteAbsolute') + ->with( + 'core.ClientFlowLogin.showAuthPickerPage', + [ + 'clientIdentifier' => 'MyClientIdentifier', + 'providedRedirectUri' => '', + ] + ) + ->willReturn('https://example.com/?clientIdentifier=foo'); + $this->config + ->expects($this->once()) + ->method('getSystemValueBool') + ->with('oauth2.enable_oc_clients', false) + ->willReturn(false); + + $expected = new RedirectResponse('https://example.com/?clientIdentifier=foo'); + $this->assertEquals($expected, $this->loginRedirectorController->authorize('MyClientId', 'MyState', 'code', 'http://untrusted-uri.com')); + } + public function testClientNotFound() { $clientNotFound = new ClientNotFoundException('could not find client test123', 0); $this->clientMapper diff --git a/core/Controller/ClientFlowLoginController.php b/core/Controller/ClientFlowLoginController.php index 76079e710e3ae..7c89618b40176 100644 --- a/core/Controller/ClientFlowLoginController.php +++ b/core/Controller/ClientFlowLoginController.php @@ -50,6 +50,7 @@ use OCP\Authentication\Exceptions\InvalidTokenException; use OCP\Defaults; use OCP\EventDispatcher\IEventDispatcher; +use OCP\IConfig; use OCP\IL10N; use OCP\IRequest; use OCP\ISession; @@ -79,6 +80,7 @@ public function __construct( private ICrypto $crypto, private IEventDispatcher $eventDispatcher, private ITimeFactory $timeFactory, + private IConfig $config, ) { parent::__construct($appName, $request); } @@ -115,7 +117,7 @@ private function stateTokenForbiddenResponse(): StandaloneTemplateResponse { */ #[UseSession] #[FrontpageRoute(verb: 'GET', url: '/login/flow')] - public function showAuthPickerPage(string $clientIdentifier = '', string $user = '', int $direct = 0): StandaloneTemplateResponse { + public function showAuthPickerPage(string $clientIdentifier = '', string $user = '', int $direct = 0, string $providedRedirectUri = ''): StandaloneTemplateResponse { $clientName = $this->getClientName(); $client = null; if ($clientIdentifier !== '') { @@ -168,6 +170,7 @@ public function showAuthPickerPage(string $clientIdentifier = '', string $user = 'oauthState' => $this->session->get('oauth.state'), 'user' => $user, 'direct' => $direct, + 'providedRedirectUri' => $providedRedirectUri, ], 'guest' ); @@ -185,6 +188,7 @@ public function showAuthPickerPage(string $clientIdentifier = '', string $user = #[FrontpageRoute(verb: 'GET', url: '/login/flow/grant')] public function grantPage(string $stateToken = '', string $clientIdentifier = '', + string $providedRedirectUri = '', int $direct = 0): StandaloneTemplateResponse { if (!$this->isValidToken($stateToken)) { return $this->stateTokenForbiddenResponse(); @@ -221,6 +225,7 @@ public function grantPage(string $stateToken = '', 'serverHost' => $this->getServerPath(), 'oauthState' => $this->session->get('oauth.state'), 'direct' => $direct, + 'providedRedirectUri' => $providedRedirectUri, ], 'guest' ); @@ -237,7 +242,8 @@ public function grantPage(string $stateToken = '', #[UseSession] #[FrontpageRoute(verb: 'POST', url: '/login/flow')] public function generateAppPassword(string $stateToken, - string $clientIdentifier = '') { + string $clientIdentifier = '', + string $providedRedirectUri = '') { if (!$this->isValidToken($stateToken)) { $this->session->remove(self::STATE_NAME); return $this->stateTokenForbiddenResponse(); @@ -296,7 +302,19 @@ public function generateAppPassword(string $stateToken, $accessToken->setCodeCreatedAt($this->timeFactory->now()->getTimestamp()); $this->accessTokenMapper->insert($accessToken); + $enableOcClients = $this->config->getSystemValueBool('oauth2.enable_oc_clients', false); + $redirectUri = $client->getRedirectUri(); + if ($enableOcClients && $redirectUri === 'http://localhost:*') { + // Sanity check untrusted redirect URI provided by the client first + if (!preg_match('/^http:\/\/localhost:[0-9]+$/', $providedRedirectUri)) { + $response = new Response(); + $response->setStatus(Http::STATUS_FORBIDDEN); + return $response; + } + + $redirectUri = $providedRedirectUri; + } if (parse_url($redirectUri, PHP_URL_QUERY)) { $redirectUri .= '&'; diff --git a/core/templates/loginflow/authpicker.php b/core/templates/loginflow/authpicker.php index b0a2efe32bd2b..eb32b0254017d 100644 --- a/core/templates/loginflow/authpicker.php +++ b/core/templates/loginflow/authpicker.php @@ -46,7 +46,7 @@
+

diff --git a/core/templates/loginflow/grant.php b/core/templates/loginflow/grant.php index 6e09be17eeb9b..b595b788636fa 100644 --- a/core/templates/loginflow/grant.php +++ b/core/templates/loginflow/grant.php @@ -50,6 +50,7 @@ + diff --git a/lib/private/Repair/Owncloud/MigrateOauthTables.php b/lib/private/Repair/Owncloud/MigrateOauthTables.php index 01b8e38683321..db36694165389 100644 --- a/lib/private/Repair/Owncloud/MigrateOauthTables.php +++ b/lib/private/Repair/Owncloud/MigrateOauthTables.php @@ -30,6 +30,7 @@ use OCP\AppFramework\Utility\ITimeFactory; use OCP\Authentication\Token\IToken; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IConfig; use OCP\Migration\IOutput; use OCP\Migration\IRepairStep; use OCP\Security\ICrypto; @@ -44,6 +45,7 @@ public function __construct( private ISecureRandom $random, private ITimeFactory $timeFactory, private ICrypto $crypto, + private IConfig $config, ) { } @@ -184,7 +186,12 @@ public function run(IOutput $output) { $schema = new SchemaWrapper($this->db); } - $output->info('Delete clients (and their related access tokens) with the redirect_uri starting with oc:// or ending with *'); + $enableOcClients = $this->config->getSystemValueBool('oauth2.enable_oc_clients', false); + if ($enableOcClients) { + $output->info('Delete clients (and their related access tokens) with the redirect_uri starting with oc://'); + } else { + $output->info('Delete clients (and their related access tokens) with the redirect_uri starting with oc:// or ending with *'); + } // delete the access tokens $qbDeleteAccessTokens = $this->db->getQueryBuilder(); @@ -193,10 +200,12 @@ public function run(IOutput $output) { ->from('oauth2_clients') ->where( $qbSelectClientId->expr()->iLike('redirect_uri', $qbDeleteAccessTokens->createNamedParameter('oc://%', IQueryBuilder::PARAM_STR)) - ) - ->orWhere( + ); + if (!$enableOcClients) { + $qbSelectClientId->orWhere( $qbSelectClientId->expr()->iLike('redirect_uri', $qbDeleteAccessTokens->createNamedParameter('%*', IQueryBuilder::PARAM_STR)) ); + } $qbDeleteAccessTokens->delete('oauth2_access_tokens') ->where( @@ -209,10 +218,12 @@ public function run(IOutput $output) { $qbDeleteClients->delete('oauth2_clients') ->where( $qbDeleteClients->expr()->iLike('redirect_uri', $qbDeleteClients->createNamedParameter('oc://%', IQueryBuilder::PARAM_STR)) - ) - ->orWhere( + ); + if (!$enableOcClients) { + $qbDeleteClients->orWhere( $qbDeleteClients->expr()->iLike('redirect_uri', $qbDeleteClients->createNamedParameter('%*', IQueryBuilder::PARAM_STR)) ); + } $qbDeleteClients->executeStatement(); // Migrate legacy refresh tokens from oc diff --git a/tests/Core/Controller/ClientFlowLoginControllerTest.php b/tests/Core/Controller/ClientFlowLoginControllerTest.php index 1a3d6ba109a2b..f2c06dbf07375 100644 --- a/tests/Core/Controller/ClientFlowLoginControllerTest.php +++ b/tests/Core/Controller/ClientFlowLoginControllerTest.php @@ -34,6 +34,7 @@ use OCP\AppFramework\Utility\ITimeFactory; use OCP\Defaults; use OCP\EventDispatcher\IEventDispatcher; +use OCP\IConfig; use OCP\IL10N; use OCP\IRequest; use OCP\ISession; @@ -72,6 +73,8 @@ class ClientFlowLoginControllerTest extends TestCase { private $eventDispatcher; /** @var ITimeFactory|\PHPUnit\Framework\MockObject\MockObject */ private $timeFactory; + /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ + private $config; /** @var ClientFlowLoginController */ private $clientFlowLoginController; @@ -98,6 +101,7 @@ protected function setUp(): void { $this->crypto = $this->createMock(ICrypto::class); $this->eventDispatcher = $this->createMock(IEventDispatcher::class); $this->timeFactory = $this->createMock(ITimeFactory::class); + $this->config = $this->createMock(IConfig::class); $this->clientFlowLoginController = new ClientFlowLoginController( 'core', @@ -113,7 +117,8 @@ protected function setUp(): void { $this->accessTokenMapper, $this->crypto, $this->eventDispatcher, - $this->timeFactory + $this->timeFactory, + $this->config, ); } @@ -188,7 +193,8 @@ public function testShowAuthPickerPageWithOcsHeader() { 'serverHost' => 'https://example.com', 'oauthState' => 'OauthStateToken', 'user' => '', - 'direct' => 0 + 'direct' => 0, + 'providedRedirectUri' => '', ], 'guest' ); @@ -258,7 +264,8 @@ public function testShowAuthPickerPageWithOauth() { 'serverHost' => 'https://example.com', 'oauthState' => 'OauthStateToken', 'user' => '', - 'direct' => 0 + 'direct' => 0, + 'providedRedirectUri' => '', ], 'guest' );