CVE-2024-37312: Insufficient Information (NVD-CWE-noinfo)
value: user_oidc app is an OpenID Connect user backend for Nextcloud. Missing access control on the ID4me endpoint allows an attacker to register an account eventually getting access to data that is available to all registered users. It is recommended that the OpenID Connect user backend is upgraded to 3.0.0 (Nextcloud 20-23), 4.0.0 (Nexcloud 24) or 5.0.0 (Nextcloud 25-28).

CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
Published: 2024-06-14T15:15Z
Repository: https://github.com/nextcloud/user_oidc
Language: PHP
Files changed: lib/Controller/Id4meController.php
Commit date: 2024-02-28 11:21:51 +0100
Commit message: prevent using ID4ME routes if ID4ME is disabled

Signed-off-by: Julien Veyssier <julien-nc@posteo.net>

Diff: diff --git a/lib/Controller/Id4meController.php b/lib/Controller/Id4meController.php
index aeb8050..aee1f52 100644
--- a/lib/Controller/Id4meController.php
+++ b/lib/Controller/Id4meController.php
@@ -31,10 +31,11 @@ use OC\User\Session as OC_UserSession;
 use OCA\UserOIDC\AppInfo\Application;
 use OCA\UserOIDC\Db\Id4Me;
 use OCA\UserOIDC\Db\Id4MeMapper;
 use OCA\UserOIDC\Db\UserMapper;
 use OCA\UserOIDC\Helper\HttpClientHelper;
+use OCA\UserOIDC\Service\ID4MeService;
 use OCP\AppFramework\Db\DoesNotExistException;
 use OCP\AppFramework\Db\MultipleObjectsReturnedException;
 use OCP\AppFramework\Http;
 use OCP\AppFramework\Http\JSONResponse;
 use OCP\AppFramework\Http\RedirectResponse;
@@ -87,10 +88,12 @@ class Id4meController extends BaseOidcController {
 	private $logger;
 	/** @var ICrypto */
 	private $crypto;
 	/** @var ITimeFactory */
 	private $timeFactory;
+	/** @var ID4MeService */
+	private $id4MeService;
 
 	public function __construct(
 		IRequest $request,
 		ISecureRandom $random,
 		ISession $session,
@@ -102,10 +105,11 @@ class Id4meController extends BaseOidcController {
 		UserMapper $userMapper,
 		IUserSession $userSession,
 		IUserManager $userManager,
 		HttpClientHelper $clientHelper,
 		Id4MeMapper $id4MeMapper,
+		ID4MeService $id4MeService,
 		LoggerInterface $logger,
 		ICrypto $crypto
 	) {
 		parent::__construct($request, $config);
 
@@ -120,18 +124,24 @@ class Id4meController extends BaseOidcController {
 		$this->id4MeMapper = $id4MeMapper;
 		$this->l10n = $l10n;
 		$this->logger = $logger;
 		$this->crypto = $crypto;
 		$this->timeFactory = $timeFactory;
+		$this->id4MeService = $id4MeService;
 	}
 
 	/**
 	 * @PublicPage
 	 * @NoCSRFRequired
 	 * @UseSession
 	 */
 	public function showLogin() {
+		if (!$this->id4MeService->getID4ME()) {
+			$message = $this->l10n->t('ID4Me is disabled');
+			return $this->build403TemplateResponse($message, Http::STATUS_FORBIDDEN, [], false);
+		}
+
 		Util::addStyle(Application::APP_ID, 'id4me-login');
 		$response = new Http\TemplateResponse('user_oidc', 'id4me/login', [], 'guest');
 
 		$csp = new Http\ContentSecurityPolicy();
 		$csp->addAllowedFormActionDomain('*');
@@ -148,10 +158,15 @@ class Id4meController extends BaseOidcController {
 	 *
 	 * @param string $domain
 	 * @return RedirectResponse|TemplateResponse
 	 */
 	public function login(string $domain) {
+		if (!$this->id4MeService->getID4ME()) {
+			$message = $this->l10n->t('ID4Me is disabled');
+			return $this->build403TemplateResponse($message, Http::STATUS_FORBIDDEN, [], false);
+		}
+
 		try {
 			$authorityName = $this->id4me->discover($domain);
 		} catch (InvalidOpenIdDomainException | OpenIdDnsRecordNotFoundException $e) {
 			$message = $this->l10n->t('Invalid OpenID domain');
 			return $this->buildErrorTemplateResponse($message, Http::STATUS_BAD_REQUEST, ['invalid_openid_domain' => $domain]);
@@ -217,10 +232,15 @@ class Id4meController extends BaseOidcController {
 	 * @param string $scope
 	 * @return JSONResponse|RedirectResponse|TemplateResponse
 	 * @throws \Exception
 	 */
 	public function code(string $state = '', string $code = '', string $scope = '') {
+		if (!$this->id4MeService->getID4ME()) {
+			$message = $this->l10n->t('ID4Me is disabled');
+			return $this->build403TemplateResponse($message, Http::STATUS_FORBIDDEN, [], false);
+		}
+
 		if ($this->session->get(self::STATE) !== $state) {
 			$this->logger->debug('state does not match');
 
 			$message = $this->l10n->t('The received state does not match the expected value.');
 			if ($this->isDebugModeEnabled()) {

Fixed code: use OCA\UserOIDC\Service\ID4MeService;
	/** @var ID4MeService */
	private $id4MeService;
		ID4MeService $id4MeService,
		$this->id4MeService = $id4MeService;
		if (!$this->id4MeService->getID4ME()) {
			$message = $this->l10n->t('ID4Me is disabled');
			return $this->build403TemplateResponse($message, Http::STATUS_FORBIDDEN, [], false);
		}

		if (!$this->id4MeService->getID4ME()) {
			$message = $this->l10n->t('ID4Me is disabled');
			return $this->build403TemplateResponse($message, Http::STATUS_FORBIDDEN, [], false);
		}

		if (!$this->id4MeService->getID4ME()) {
			$message = $this->l10n->t('ID4Me is disabled');
			return $this->build403TemplateResponse($message, Http::STATUS_FORBIDDEN, [], false);
		}