diff --git a/README.md b/README.md index 8570cf16..05fe6224 100644 --- a/README.md +++ b/README.md @@ -296,6 +296,16 @@ This app can stop matching users (when a user search is performed in Nextcloud) ], ``` +### Disable SSL certificates verification + +If your IdP is using self-signed certificates or if you have any other reason to disable SSL certificates verification +when making requests to the IdP, set this in config.php : +``` php +'user_oidc' => [ + 'disable_certificate_verification' => true, +], +``` + ## Building the app Requirements for building: diff --git a/lib/Controller/Id4meController.php b/lib/Controller/Id4meController.php index 9552cd70..f260fd48 100644 --- a/lib/Controller/Id4meController.php +++ b/lib/Controller/Id4meController.php @@ -17,6 +17,7 @@ use OCA\UserOIDC\Db\UserMapper; use OCA\UserOIDC\Helper\HttpClientHelper; use OCA\UserOIDC\Service\ID4MeService; +use OCA\UserOIDC\Service\NetworkService; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\MultipleObjectsReturnedException; use OCP\AppFramework\Http; @@ -24,7 +25,6 @@ use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Utility\ITimeFactory; -use OCP\Http\Client\IClientService; use OCP\IConfig; use OCP\IL10N; use OCP\IRequest; @@ -55,7 +55,7 @@ public function __construct( IConfig $config, private IL10N $l10n, private ITimeFactory $timeFactory, - private IClientService $clientService, + private NetworkService $networkService, private IURLGenerator $urlGenerator, private UserMapper $userMapper, private IUserSession $userSession, @@ -221,7 +221,7 @@ public function code(string $state = '', string $code = '', string $scope = '') return $this->buildErrorTemplateResponse($message, Http::STATUS_BAD_REQUEST, [], false); } - $client = $this->clientService->newClient(); + $client = $this->networkService->newClient(); $result = $client->post( $openIdConfig->getTokenEndpoint(), [ diff --git a/lib/Controller/LoginController.php b/lib/Controller/LoginController.php index 4aff4bd0..012bab2d 100644 --- a/lib/Controller/LoginController.php +++ b/lib/Controller/LoginController.php @@ -22,6 +22,7 @@ use OCA\UserOIDC\Event\TokenObtainedEvent; use OCA\UserOIDC\Service\DiscoveryService; use OCA\UserOIDC\Service\LdapService; +use OCA\UserOIDC\Service\NetworkService; use OCA\UserOIDC\Service\ProviderService; use OCA\UserOIDC\Service\ProvisioningService; use OCA\UserOIDC\Service\TokenService; @@ -38,7 +39,6 @@ use OCP\AppFramework\Utility\ITimeFactory; use OCP\DB\Exception; use OCP\EventDispatcher\IEventDispatcher; -use OCP\Http\Client\IClientService; use OCP\IConfig; use OCP\IL10N; use OCP\IRequest; @@ -69,7 +69,7 @@ public function __construct( private LdapService $ldapService, private ISecureRandom $random, private ISession $session, - private IClientService $clientService, + private NetworkService $networkService, private IURLGenerator $urlGenerator, private IUserSession $userSession, private IUserManager $userManager, @@ -329,7 +329,7 @@ public function code(string $state = '', string $code = '', string $scope = '', $isPkceSupported = in_array('S256', $discovery['code_challenge_methods_supported'] ?? [], true); $isPkceEnabled = $isPkceSupported && ($oidcSystemConfig['use_pkce'] ?? true); - $client = $this->clientService->newClient(); + $client = $this->networkService->newClient(); try { $requestBody = [ 'code' => $code, diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php index fbce96a6..b404b772 100644 --- a/lib/Controller/SettingsController.php +++ b/lib/Controller/SettingsController.php @@ -13,12 +13,12 @@ use OCA\UserOIDC\Db\Provider; use OCA\UserOIDC\Db\ProviderMapper; use OCA\UserOIDC\Service\ID4MeService; +use OCA\UserOIDC\Service\NetworkService; use OCA\UserOIDC\Service\ProviderService; use OCP\AppFramework\Controller; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Http; use OCP\AppFramework\Http\JSONResponse; -use OCP\Http\Client\IClientService; use OCP\IRequest; use OCP\Security\ICrypto; use Psr\Log\LoggerInterface; @@ -31,7 +31,7 @@ public function __construct( private ID4MeService $id4meService, private ProviderService $providerService, private ICrypto $crypto, - private IClientService $clientService, + private NetworkService $networkService, private LoggerInterface $logger, ) { parent::__construct(Application::APP_ID, $request); @@ -44,7 +44,7 @@ public function isDiscoveryEndpointValid($url) { ]; try { - $client = $this->clientService->newClient(); + $client = $this->networkService->newClient(); $response = $client->get($url); $httpCode = $response->getStatusCode(); $body = $response->getBody(); diff --git a/lib/Helper/HttpClientHelper.php b/lib/Helper/HttpClientHelper.php index d1b2cfb6..97702fd2 100644 --- a/lib/Helper/HttpClientHelper.php +++ b/lib/Helper/HttpClientHelper.php @@ -8,7 +8,7 @@ namespace OCA\UserOIDC\Helper; -use OCP\Http\Client\IClientService; +use OCA\UserOIDC\Service\NetworkService; require_once __DIR__ . '/../../vendor/autoload.php'; use Id4me\RP\HttpClient; @@ -16,12 +16,12 @@ class HttpClientHelper implements HttpClient { public function __construct( - private IClientService $clientService, + private NetworkService $networkService, ) { } public function get($url, array $headers = []) { - $client = $this->clientService->newClient(); + $client = $this->networkService->newClient(); return $client->get($url, [ 'headers' => $headers, @@ -29,7 +29,7 @@ public function get($url, array $headers = []) { } public function post($url, $body, array $headers = []) { - $client = $this->clientService->newClient(); + $client = $this->networkService->newClient(); return $client->post($url, [ 'headers' => $headers, diff --git a/lib/Service/DiscoveryService.php b/lib/Service/DiscoveryService.php index d1be8eb1..7326473f 100644 --- a/lib/Service/DiscoveryService.php +++ b/lib/Service/DiscoveryService.php @@ -11,7 +11,6 @@ use OCA\UserOIDC\Db\Provider; use OCA\UserOIDC\Vendor\Firebase\JWT\JWK; use OCA\UserOIDC\Vendor\Firebase\JWT\JWT; -use OCP\Http\Client\IClientService; use OCP\ICache; use OCP\ICacheFactory; use Psr\Log\LoggerInterface; @@ -38,7 +37,7 @@ class DiscoveryService { public function __construct( private LoggerInterface $logger, - private IClientService $clientService, + private NetworkService $networkService, private ProviderService $providerService, ICacheFactory $cacheFactory, ) { @@ -52,7 +51,7 @@ public function obtainDiscovery(Provider $provider): array { $url = $provider->getDiscoveryEndpoint(); $this->logger->debug('Obtaining discovery endpoint: ' . $url); - $client = $this->clientService->newClient(); + $client = $this->networkService->newClient(); $response = $client->get($url); $cachedDiscovery = $response->getBody(); @@ -75,7 +74,7 @@ public function obtainJWK(Provider $provider, string $tokenToDecode): array { $rawJwks = json_decode($rawJwks, true); } else { $discovery = $this->obtainDiscovery($provider); - $client = $this->clientService->newClient(); + $client = $this->networkService->newClient(); $responseBody = $client->get($discovery['jwks_uri'])->getBody(); $rawJwks = json_decode($responseBody, true); // cache jwks diff --git a/lib/Service/NetworkClient.php b/lib/Service/NetworkClient.php new file mode 100644 index 00000000..1b46fc63 --- /dev/null +++ b/lib/Service/NetworkClient.php @@ -0,0 +1,42 @@ +client = $clientService->newClient(); + } + + private function processOptions(array $options): array { + $oidcSystemConfig = $this->config->getSystemValue('user_oidc', []); + if (isset($oidcSystemConfig['disable_certificate_verification']) && $oidcSystemConfig['disable_certificate_verification'] === true) { + $options['verify'] = false; + } + return $options; + } + + public function get(string $uri, array $options = []): IResponse { + return $this->client->get($uri, $this->processOptions($options)); + } + + public function post(string $uri, array $options = []): IResponse { + return $this->client->post($uri, $this->processOptions($options)); + } +} diff --git a/lib/Service/NetworkService.php b/lib/Service/NetworkService.php new file mode 100644 index 00000000..6f7541a4 --- /dev/null +++ b/lib/Service/NetworkService.php @@ -0,0 +1,25 @@ +clientService, $this->config); + } +} diff --git a/lib/Service/OIDCService.php b/lib/Service/OIDCService.php index 3b73be64..7f967153 100644 --- a/lib/Service/OIDCService.php +++ b/lib/Service/OIDCService.php @@ -9,7 +9,7 @@ namespace OCA\UserOIDC\Service; use OCA\UserOIDC\Db\Provider; -use OCP\Http\Client\IClientService; +use OCP\IConfig; use OCP\Security\ICrypto; use Psr\Log\LoggerInterface; use Throwable; @@ -19,8 +19,9 @@ class OIDCService { public function __construct( private DiscoveryService $discoveryService, private LoggerInterface $logger, - private IClientService $clientService, + private NetworkService $networkService, private ICrypto $crypto, + private IConfig $config, ) { } @@ -30,7 +31,7 @@ public function userinfo(Provider $provider, string $accessToken): array { return []; } - $client = $this->clientService->newClient(); + $client = $this->networkService->newClient(); $this->logger->debug('Fetching user info endpoint'); $options = [ 'headers' => [ @@ -56,7 +57,7 @@ public function introspection(Provider $provider, string $accessToken): array { return []; } - $client = $this->clientService->newClient(); + $client = $this->networkService->newClient(); $this->logger->debug('Fetching user info endpoint'); $options = [ 'headers' => [ diff --git a/lib/Service/ProvisioningService.php b/lib/Service/ProvisioningService.php index 0e028ecd..fa919a2a 100644 --- a/lib/Service/ProvisioningService.php +++ b/lib/Service/ProvisioningService.php @@ -15,7 +15,6 @@ use OCP\AppFramework\Db\MultipleObjectsReturnedException; use OCP\DB\Exception; use OCP\EventDispatcher\IEventDispatcher; -use OCP\Http\Client\IClientService; use OCP\IAvatarManager; use OCP\IConfig; use OCP\IGroupManager; @@ -38,7 +37,7 @@ public function __construct( private IEventDispatcher $eventDispatcher, private LoggerInterface $logger, private IAccountManager $accountManager, - private IClientService $clientService, + private NetworkService $networkService, private IAvatarManager $avatarManager, private IConfig $config, private ISession $session, @@ -355,7 +354,7 @@ public function provisionUser(string $tokenUserId, int $providerId, object $idTo private function setUserAvatar(string $userId, string $avatarAttribute): void { $avatarContent = null; if (filter_var($avatarAttribute, FILTER_VALIDATE_URL)) { - $client = $this->clientService->newClient(); + $client = $this->networkService->newClient(); try { $avatarContent = $client->get($avatarAttribute)->getBody(); if (is_resource($avatarContent)) { diff --git a/lib/Service/TokenService.php b/lib/Service/TokenService.php index f6164202..87e7a41e 100644 --- a/lib/Service/TokenService.php +++ b/lib/Service/TokenService.php @@ -17,8 +17,6 @@ use OCA\UserOIDC\Vendor\Firebase\JWT\JWT; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\MultipleObjectsReturnedException; -use OCP\Http\Client\IClient; -use OCP\Http\Client\IClientService; use OCP\IConfig; use OCP\IRequest; use OCP\ISession; @@ -37,10 +35,10 @@ class TokenService { private const SESSION_TOKEN_KEY = Application::APP_ID . '-user-token'; - private IClient $client; + private NetworkClient $client; public function __construct( - IClientService $clientService, + NetworkService $networkService, private ISession $session, private IUserSession $userSession, private IConfig $config, @@ -51,7 +49,7 @@ public function __construct( private DiscoveryService $discoveryService, private ProviderMapper $providerMapper, ) { - $this->client = $clientService->newClient(); + $this->client = $networkService->newClient(); } public function storeToken(array $tokenData): Token { diff --git a/tests/unit/Service/DiscoveryServiceTest.php b/tests/unit/Service/DiscoveryServiceTest.php index 59b62d50..7b29b1f5 100644 --- a/tests/unit/Service/DiscoveryServiceTest.php +++ b/tests/unit/Service/DiscoveryServiceTest.php @@ -8,8 +8,8 @@ use OCA\UserOIDC\Service\DiscoveryService; +use OCA\UserOIDC\Service\NetworkService; use OCA\UserOIDC\Service\ProviderService; -use OCP\Http\Client\IClientService; use OCP\ICacheFactory; use PHPUnit\Framework\Assert; use PHPUnit\Framework\MockObject\MockObject; @@ -23,9 +23,9 @@ class DiscoveryServiceTest extends TestCase { */ private $logger; /** - * @var IClientService|MockObject + * @var NetworkService|MockObject */ - private $clientService; + private $networkService; /** * @var ProviderService|MockObject */ @@ -42,10 +42,10 @@ class DiscoveryServiceTest extends TestCase { public function setUp(): void { parent::setUp(); $this->logger = $this->createMock(LoggerInterface::class); - $this->clientService = $this->createMock(IClientService::class); + $this->networkService = $this->createMock(NetworkService::class); $this->providerService = $this->createMock(ProviderService::class); $this->cacheFactory = $this->createMock(ICacheFactory::class); - $this->discoveryService = new DiscoveryService($this->logger, $this->clientService, $this->providerService, $this->cacheFactory); + $this->discoveryService = new DiscoveryService($this->logger, $this->networkService, $this->providerService, $this->cacheFactory); } public function testBuildAuthorizationUrl() { diff --git a/tests/unit/Service/ProvisioningServiceTest.php b/tests/unit/Service/ProvisioningServiceTest.php index b4db605b..6d07848a 100644 --- a/tests/unit/Service/ProvisioningServiceTest.php +++ b/tests/unit/Service/ProvisioningServiceTest.php @@ -9,11 +9,11 @@ use OCA\UserOIDC\Db\UserMapper; use OCA\UserOIDC\Service\LdapService; use OCA\UserOIDC\Service\LocalIdService; +use OCA\UserOIDC\Service\NetworkService; use OCA\UserOIDC\Service\ProviderService; use OCA\UserOIDC\Service\ProvisioningService; use OCP\Accounts\IAccountManager; use OCP\EventDispatcher\IEventDispatcher; -use OCP\Http\Client\IClientService; use OCP\IAvatarManager; use OCP\IConfig; use OCP\IGroup; @@ -56,8 +56,8 @@ class ProvisioningServiceTest extends TestCase { /** @var IAccountManager | MockObject */ private $accountManager; - /** @var IClientService | MockObject */ - private $clientService; + /** @var NetworkService | MockObject */ + private $networkService; /** @var IAvatarManager | MockObject */ private $avatarManager; @@ -76,7 +76,7 @@ public function setUp(): void { $this->eventDispatcher = $this->createMock(IEventDispatcher::class); $this->logger = $this->createMock(LoggerInterface::class); $this->accountManager = $this->createMock(IAccountManager::class); - $this->clientService = $this->createMock(IClientService::class); + $this->networkService = $this->createMock(NetworkService::class); $this->avatarManager = $this->createMock(IAvatarManager::class); $this->config = $this->createMock(IConfig::class); $this->session = $this->createMock(ISession::class); @@ -90,7 +90,7 @@ public function setUp(): void { $this->eventDispatcher, $this->logger, $this->accountManager, - $this->clientService, + $this->networkService, $this->avatarManager, $this->config, $this->session,