From 881b11ebe34bc42c108a5767cc159afff525123f Mon Sep 17 00:00:00 2001 From: Akhil Date: Fri, 14 Jul 2023 16:08:14 +0530 Subject: [PATCH 1/6] Delete all totp secrets, not just the nextcloud one --- lib/Db/SSOMapper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Db/SSOMapper.php b/lib/Db/SSOMapper.php index d172ddda..13f2cc08 100644 --- a/lib/Db/SSOMapper.php +++ b/lib/Db/SSOMapper.php @@ -56,7 +56,7 @@ class SSOMapper { $qb->delete(self::CREDENTIAL_TABLE) ->where('USER_ID = :username') ->andWhere('TYPE = "otp"') - ->andWhere('CREDENTIAL_DATA LIKE "%\"subType\":\"nextcloud_totp\"%"') + ->andWhere('CREDENTIAL_DATA LIKE "%\"subType\":\"totp\"%"') ->setParameter('username', $userId) ->execute(); } -- GitLab From e2d597b76f4fcff92b9040440a6a0e98ed7ab533 Mon Sep 17 00:00:00 2001 From: Akhil Date: Fri, 14 Jul 2023 16:10:20 +0530 Subject: [PATCH 2/6] Use or where --- lib/Db/SSOMapper.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Db/SSOMapper.php b/lib/Db/SSOMapper.php index 13f2cc08..089cdbd2 100644 --- a/lib/Db/SSOMapper.php +++ b/lib/Db/SSOMapper.php @@ -56,7 +56,8 @@ class SSOMapper { $qb->delete(self::CREDENTIAL_TABLE) ->where('USER_ID = :username') ->andWhere('TYPE = "otp"') - ->andWhere('CREDENTIAL_DATA LIKE "%\"subType\":\"totp\"%"') + ->andWhere('CREDENTIAL_DATA LIKE "%\"subType\":\"nextcloud_totp\"%"') + ->orWhere('CREDENTIAL_DATA LIKE "%\"subType\":\"totp\"%"') ->setParameter('username', $userId) ->execute(); } -- GitLab From 2846b6d5f4ffe7a8887e74c7c1dae4c0a9709d98 Mon Sep 17 00:00:00 2001 From: Akhil Date: Fri, 14 Jul 2023 16:24:21 +0530 Subject: [PATCH 3/6] Move the OR into the and --- lib/Db/SSOMapper.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/Db/SSOMapper.php b/lib/Db/SSOMapper.php index 089cdbd2..a53d20f5 100644 --- a/lib/Db/SSOMapper.php +++ b/lib/Db/SSOMapper.php @@ -56,8 +56,7 @@ class SSOMapper { $qb->delete(self::CREDENTIAL_TABLE) ->where('USER_ID = :username') ->andWhere('TYPE = "otp"') - ->andWhere('CREDENTIAL_DATA LIKE "%\"subType\":\"nextcloud_totp\"%"') - ->orWhere('CREDENTIAL_DATA LIKE "%\"subType\":\"totp\"%"') + ->andWhere('CREDENTIAL_DATA LIKE "%\"subType\":\"nextcloud_totp\"%" OR CREDENTIAL_DATA LIKE "%\"subType\":\"totp\"%"') ->setParameter('username', $userId) ->execute(); } -- GitLab From e2ac2a23d1c09f42cc0a481b713b9e5a35f42544 Mon Sep 17 00:00:00 2001 From: Akhil Date: Mon, 17 Jul 2023 13:29:04 +0530 Subject: [PATCH 4/6] Add label translations --- l10n/de.js | 4 +++- l10n/de.json | 3 ++- l10n/en.js | 3 ++- l10n/en.json | 3 ++- l10n/es.js | 3 ++- l10n/es.json | 3 ++- l10n/fr.js | 3 ++- l10n/fr.json | 3 ++- l10n/it.js | 3 ++- l10n/it.json | 3 ++- lib/Db/SSOMapper.php | 23 +++++++++-------------- 11 files changed, 30 insertions(+), 24 deletions(-) diff --git a/l10n/de.js b/l10n/de.js index 46823807..47243d09 100644 --- a/l10n/de.js +++ b/l10n/de.js @@ -38,6 +38,8 @@ OC.L10N.register( "Here is the list of currently available beta features:": "Hier ist die Liste der derzeit verfügbaren Beta-Funktionen:", "A subscription is active in this account. Please cancel it or let it expire before deleting your account.": "Für dieses Konto ist ein Abonnement aktiv. Bitte kündigen Sie es oder lassen Sie es auslaufen, bevor Sie Ihr Konto löschen.", "Loading...": "Laden...", - "Temporary error contacting murena.com; please try again later!": "Vorübergehender Fehler bei der Kontaktaufnahme mit murena.com; bitte versuchen Sie es später noch einmal!" + "Temporary error contacting murena.com; please try again later!": "Vorübergehender Fehler bei der Kontaktaufnahme mit murena.com; bitte versuchen Sie es später noch einmal!", + "Murena Cloud 2FA": "Murena Cloud 2FA" + }, "nplurals=2; plural=(n != 1);"); diff --git a/l10n/de.json b/l10n/de.json index b94ac709..d70e6d9c 100644 --- a/l10n/de.json +++ b/l10n/de.json @@ -37,7 +37,8 @@ "Here is the list of currently available beta features:": "Hier ist die Liste der derzeit verfügbaren Beta-Funktionen:", "A subscription is active in this account. Please cancel it or let it expire before deleting your account.": "Für dieses Konto ist ein Abonnement aktiv. Bitte kündigen Sie es oder lassen Sie es auslaufen, bevor Sie Ihr Konto löschen.", "Loading...": "Laden...", - "Temporary error contacting murena.com; please try again later!": "Vorübergehender Fehler bei der Kontaktaufnahme mit murena.com; bitte versuchen Sie es später noch einmal!" + "Temporary error contacting murena.com; please try again later!": "Vorübergehender Fehler bei der Kontaktaufnahme mit murena.com; bitte versuchen Sie es später noch einmal!", + "Murena Cloud 2FA": "Murena Cloud 2FA" }, "pluralForm": "nplurals=2; plural=(n != 1);" } diff --git a/l10n/en.js b/l10n/en.js index bc284754..422054cf 100644 --- a/l10n/en.js +++ b/l10n/en.js @@ -40,6 +40,7 @@ OC.L10N.register( "Here is the list of currently available beta features:": "Here is the list of currently available beta features:", "A subscription is active in this account. Please cancel it or let it expire before deleting your account.": "A subscription is active in this account. Please cancel it or let it expire before deleting your account.", "Loading...": "Loading...", - "Temporary error contacting murena.com; please try again later!": "Temporary error contacting murena.com; please try again later!" + "Temporary error contacting murena.com; please try again later!": "Temporary error contacting murena.com; please try again later!", + "Murena Cloud 2FA": "Murena Cloud 2FA" }, "nplurals=2; plural=(n != 1);"); diff --git a/l10n/en.json b/l10n/en.json index bdcda7af..83db6b42 100644 --- a/l10n/en.json +++ b/l10n/en.json @@ -37,7 +37,8 @@ "Here is the list of currently available beta features:": "Here is the list of currently available beta features:", "A subscription is active in this account. Please cancel it or let it expire before deleting your account.": "A subscription is active in this account. Please cancel it or let it expire before deleting your account.", "Loading...": "Loading...", - "Temporary error contacting murena.com; please try again later!": "Temporary error contacting murena.com; please try again later!" + "Temporary error contacting murena.com; please try again later!": "Temporary error contacting murena.com; please try again later!", + "Murena Cloud 2FA": "Murena Cloud 2FA" }, "pluralForm": "nplurals=2; plural=(n != 1);" } diff --git a/l10n/es.js b/l10n/es.js index 713bffb6..3a081dd1 100644 --- a/l10n/es.js +++ b/l10n/es.js @@ -39,6 +39,7 @@ OC.L10N.register( "Here is the list of currently available beta features:": "Esta es la lista de funciones de la versión beta disponibles actualmente:", "A subscription is active in this account. Please cancel it or let it expire before deleting your account.": "Hay una suscripción activa en esta cuenta. Por favor, cancélala o deja que expire antes de eliminar tu cuenta.", "Loading...": "Cargando...", - "Temporary error contacting murena.com; please try again later!": "Error temporal al contactar con murena.com; ¡por favor, inténtalo más tarde!" + "Temporary error contacting murena.com; please try again later!": "Error temporal al contactar con murena.com; ¡por favor, inténtalo más tarde!", + "Murena Cloud 2FA": "Nube Murena A2F" }, "nplurals=2; plural=(n != 1);"); diff --git a/l10n/es.json b/l10n/es.json index fc0959d3..b8594865 100644 --- a/l10n/es.json +++ b/l10n/es.json @@ -37,7 +37,8 @@ "Here is the list of currently available beta features:": "Esta es la lista de funciones de la versión beta disponibles actualmente:", "A subscription is active in this account. Please cancel it or let it expire before deleting your account.": "Hay una suscripción activa en esta cuenta. Por favor, cancélala o deja que expire antes de eliminar tu cuenta.", "Loading...": "Cargando...", - "Temporary error contacting murena.com; please try again later!": "Error temporal al contactar con murena.com; ¡por favor, inténtalo más tarde!" + "Temporary error contacting murena.com; please try again later!": "Error temporal al contactar con murena.com; ¡por favor, inténtalo más tarde!", + "Murena Cloud 2FA": "Nube Murena A2F" }, "pluralForm": "nplurals=2; plural=(n != 1);" } diff --git a/l10n/fr.js b/l10n/fr.js index 11002b93..1f668c1f 100644 --- a/l10n/fr.js +++ b/l10n/fr.js @@ -38,6 +38,7 @@ OC.L10N.register( "Here is the list of currently available beta features:": "Voici la liste des fonctionnalités de la version bêta actuellement disponibles :", "A subscription is active in this account. Please cancel it or let it expire before deleting your account.": "Un abonnement est actif dans ce compte. Veuillez l'annuler ou le laisser expirer avant de supprimer votre compte.", "Loading...": "Chargement...", - "Temporary error contacting murena.com; please try again later!": "Erreur temporaire en contactant murena.com ; veuillez réessayer plus tard !" + "Temporary error contacting murena.com; please try again later!": "Erreur temporaire en contactant murena.com ; veuillez réessayer plus tard !", + "Murena Cloud 2FA": "Authentification à 2 facteurs Murena Cloud" }, "nplurals=2; plural=(n != 1);"); diff --git a/l10n/fr.json b/l10n/fr.json index 1a3e3ae4..48a79c47 100644 --- a/l10n/fr.json +++ b/l10n/fr.json @@ -37,7 +37,8 @@ "Here is the list of currently available beta features:": "Voici la liste des fonctionnalités de la version bêta actuellement disponibles :", "A subscription is active in this account. Please cancel it or let it expire before deleting your account.": "Un abonnement est actif dans ce compte. Veuillez l'annuler ou le laisser expirer avant de supprimer votre compte.", "Loading...": "Chargement...", - "Temporary error contacting murena.com; please try again later!": "Erreur temporaire en contactant murena.com ; veuillez réessayer plus tard !" + "Temporary error contacting murena.com; please try again later!": "Erreur temporaire en contactant murena.com ; veuillez réessayer plus tard !", + "Murena Cloud 2FA": "Authentification à 2 facteurs Murena Cloud" }, "pluralForm": "nplurals=2; plural=(n != 1);" } diff --git a/l10n/it.js b/l10n/it.js index 12976c09..7dbe4434 100644 --- a/l10n/it.js +++ b/l10n/it.js @@ -38,6 +38,7 @@ OC.L10N.register( "Here is the list of currently available beta features:": "Ecco l'elenco delle funzioni beta attualmente disponibili:", "A subscription is active in this account. Please cancel it or let it expire before deleting your account.": "In questo account è attivo un abbonamento. Si prega di annullarlo o di lasciarlo scadere prima di cancellare l'account.", "Loading...": "Caricamento...", - "Temporary error contacting murena.com; please try again later!": "Errore temporaneo nel contattare murena.com; riprova più tardi!" + "Temporary error contacting murena.com; please try again later!": "Errore temporaneo nel contattare murena.com; riprova più tardi!", + "Murena Cloud 2FA": "Codice di Autenticazione a 2 Fattori Murena Cloud" }, "nplurals=2; plural=(n != 1);"); diff --git a/l10n/it.json b/l10n/it.json index 2dc17b44..1c9cb7a0 100644 --- a/l10n/it.json +++ b/l10n/it.json @@ -37,7 +37,8 @@ "Here is the list of currently available beta features:": "Ecco l'elenco delle funzioni beta attualmente disponibili:", "A subscription is active in this account. Please cancel it or let it expire before deleting your account.": "In questo account è attivo un abbonamento. Si prega di annullarlo o di lasciarlo scadere prima di cancellare l'account.", "Loading...": "Caricamento...", - "Temporary error contacting murena.com; please try again later!": "Errore temporaneo nel contattare murena.com; riprova più tardi!" + "Temporary error contacting murena.com; please try again later!": "Errore temporaneo nel contattare murena.com; riprova più tardi!", + "Murena Cloud 2FA": "Codice di Autenticazione a 2 Fattori Murena Cloud" }, "pluralForm": "nplurals=2; plural=(n != 1);" } diff --git a/lib/Db/SSOMapper.php b/lib/Db/SSOMapper.php index a53d20f5..588efb5d 100644 --- a/lib/Db/SSOMapper.php +++ b/lib/Db/SSOMapper.php @@ -6,10 +6,12 @@ use OCP\IConfig; use OCP\ILogger; use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\Connection; +use OCA\EcloudAccounts\AppInfo\Application; use OCP\IUserManager; use OCP\Security\ICrypto; use OCP\IUser; use OCA\EcloudAccounts\Exception\DbConnectionParamsException; +use OCP\L10N\IFactory; class SSOMapper { private IConfig $config; @@ -17,20 +19,14 @@ class SSOMapper { private Connection $conn; private IUserManager $userManager; private ICrypto $crypto; + private IFactory $l10nFactory; private const USER_ATTRIBUTE_TABLE = 'USER_ATTRIBUTE'; private const CREDENTIAL_TABLE = 'CREDENTIAL'; - private const SSO_CONFIG_KEY = 'keycloak'; - private const USER_LABELS = [ - 'en' => 'Murena Cloud 2FA', - 'es' => 'Murena Cloud 2FA', - 'de' => 'Murena Cloud 2FA', - 'it' => 'Murena Cloud 2FA', - 'fr' => 'Murena Cloud 2FA', - ]; - - public function __construct(IConfig $config, IUserManager $userManager, ILogger $logger, ICrypto $crypto) { + + public function __construct(IConfig $config, IUserManager $userManager, ILogger $logger, ICrypto $crypto, IFactory $l10nFactory) { + $this->l10nFactory = $l10nFactory; $this->config = $config; $this->logger = $logger; $this->userManager = $userManager; @@ -73,9 +69,6 @@ class SSOMapper { } $language = $this->config->getUserValue($username, 'core', 'lang', 'en'); - if (!array_key_exists($language, self::USER_LABELS)) { - $language = 'en'; - } // Only one "nextcloud_totp" at a time $this->deleteCredential($username); @@ -101,7 +94,9 @@ class SSOMapper { // Create the random UUID from the sso user ID so multiple entries of same credential do not happen $id = $this->randomUUID(substr($ssoUserId, 0, 16)); - $userLabel = self::USER_LABELS[$language]; + $l10n = $this->l10nFactory->get(Application::APP_ID, $language); + $userLabel = $l10n->t('Murena Cloud 2FA'); + $credentialEntry = [ 'ID' => $id, 'USER_ID' => $ssoUserId, -- GitLab From c0ef6337dda1a1eb05317e6b16778d28d1f3c43f Mon Sep 17 00:00:00 2001 From: Akhil Date: Mon, 17 Jul 2023 16:39:43 +0530 Subject: [PATCH 5/6] Rename method to plural --- lib/Db/SSOMapper.php | 6 +++--- lib/Listeners/TwoFactorStateChangedListener.php | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/Db/SSOMapper.php b/lib/Db/SSOMapper.php index 588efb5d..b1345da8 100644 --- a/lib/Db/SSOMapper.php +++ b/lib/Db/SSOMapper.php @@ -46,7 +46,7 @@ class SSOMapper { return (string) $result->fetchOne(); } - public function deleteCredential(string $username) { + public function deleteCredentials(string $username) { $userId = $this->getUserId($username); $qb = $this->conn->createQueryBuilder(); $qb->delete(self::CREDENTIAL_TABLE) @@ -70,8 +70,8 @@ class SSOMapper { $language = $this->config->getUserValue($username, 'core', 'lang', 'en'); - // Only one "nextcloud_totp" at a time - $this->deleteCredential($username); + // Only one 2FA device at a time + $this->deleteCredentials($username); $entry = $this->getCredentialEntry($decryptedSecret, $ssoUserId, $language); $this->insertCredential($entry); diff --git a/lib/Listeners/TwoFactorStateChangedListener.php b/lib/Listeners/TwoFactorStateChangedListener.php index 860ad4b6..0ba6223e 100644 --- a/lib/Listeners/TwoFactorStateChangedListener.php +++ b/lib/Listeners/TwoFactorStateChangedListener.php @@ -38,9 +38,10 @@ class TwoFactorStateChangedListener implements IEventListener { $user = $event->getUser(); $username = $user->getUID(); try { - // When state change event is fired by user disabling 2FA, delete existing credential and return + // When state change event is fired by user disabling 2FA, delete existing 2FA credentials and return + // i.e. disable 2FA for user at SSO if (!$event->isEnabled()) { - $this->ssoMapper->deleteCredential($username); + $this->ssoMapper->deleteCredentials($username); return; } -- GitLab From 9e21a01596a8e91d9f7177e89db5f6c4072f97df Mon Sep 17 00:00:00 2001 From: Akhil Date: Mon, 17 Jul 2023 16:43:57 +0530 Subject: [PATCH 6/6] Return if SSO not enabled --- lib/Db/SSOMapper.php | 4 ++++ lib/Listeners/TwoFactorStateChangedListener.php | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/Db/SSOMapper.php b/lib/Db/SSOMapper.php index b1345da8..3cb62a85 100644 --- a/lib/Db/SSOMapper.php +++ b/lib/Db/SSOMapper.php @@ -34,6 +34,10 @@ class SSOMapper { $this->initConnection(); } + public function isSSOEnabled() : bool { + return isset($this->conn); + } + public function getUserId(string $username) : string { $qb = $this->conn->createQueryBuilder(); $qb->select('USER_ID') diff --git a/lib/Listeners/TwoFactorStateChangedListener.php b/lib/Listeners/TwoFactorStateChangedListener.php index 0ba6223e..9624abdb 100644 --- a/lib/Listeners/TwoFactorStateChangedListener.php +++ b/lib/Listeners/TwoFactorStateChangedListener.php @@ -31,7 +31,7 @@ class TwoFactorStateChangedListener implements IEventListener { public function handle(Event $event): void { - if (!($event instanceof StateChanged) || !$this->appManager->isEnabledForUser(self::TWOFACTOR_APP_ID)) { + if (!($event instanceof StateChanged) || !$this->appManager->isEnabledForUser(self::TWOFACTOR_APP_ID) || !$this->ssoMapper->isSSOEnabled()) { return; } -- GitLab