From 2ac5294d550021d9c24690ba3ba1547cf458576d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Kellerer?= Date: Sun, 24 Oct 2021 13:12:34 +0200 Subject: [PATCH 01/11] Supporting app-passwds in cal/carddav & ActiveSync --- data/web/autodiscover.php | 3 ++- data/web/inc/functions.inc.php | 14 +++++++++++++- data/web/inc/vars.inc.php | 3 +++ data/web/sogo-auth.php | 3 ++- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/data/web/autodiscover.php b/data/web/autodiscover.php index c18edbfc1..265d138e3 100644 --- a/data/web/autodiscover.php +++ b/data/web/autodiscover.php @@ -67,7 +67,8 @@ if (empty($_SERVER['PHP_AUTH_USER']) || empty($_SERVER['PHP_AUTH_PW'])) { exit(0); } -$login_role = check_login($login_user, $login_pass); +$allow_app_passwords = $ALLOW_APP_PASSWORDS_IN_EAS === true || $autodiscover_config['autodiscoverType'] == 'imap'; +$login_role = check_login($login_user, $login_pass, $allow_app_passwords); if ($login_role === "user") { header("Content-Type: application/xml"); diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php index 072bf0b49..8245c46e5 100644 --- a/data/web/inc/functions.inc.php +++ b/data/web/inc/functions.inc.php @@ -807,7 +807,7 @@ function verify_hash($hash, $password) { } return false; } -function check_login($user, $pass) { +function check_login($user, $pass, $allow_app_passwords = false) { global $pdo; global $redis; global $imap_server; @@ -896,6 +896,18 @@ function check_login($user, $pass) { AND `username` = :user"); $stmt->execute(array(':user' => $user)); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); + if ($allow_app_passwords === true) { + $stmt = $pdo->prepare("SELECT `app_passwd`.`password` as `password`, `app_passwd`.`id` as `app_passwd_id` FROM `app_passwd` + INNER JOIN `mailbox` ON `mailbox`.`username` = `app_passwd`.`mailbox` + INNER JOIN `domain` ON `mailbox`.`domain` = `domain`.`domain` + WHERE `mailbox`.`kind` NOT REGEXP 'location|thing|group' + AND `mailbox`.`active` = '1' + AND `domain`.`active` = '1' + AND `app_passwd`.`active` = '1' + AND `app_passwd`.`mailbox` = :user"); + $stmt->execute(array(':user' => $user)); + $rows = array_merge($rows, $stmt->fetchAll(PDO::FETCH_ASSOC)); + } foreach ($rows as $row) { if (verify_hash($row['password'], $pass) !== false) { unset($_SESSION['ldelay']); diff --git a/data/web/inc/vars.inc.php b/data/web/inc/vars.inc.php index 91d2145da..8a83f964e 100644 --- a/data/web/inc/vars.inc.php +++ b/data/web/inc/vars.inc.php @@ -188,6 +188,9 @@ $MAILBOX_DEFAULT_ATTRIBUTES['mailbox_format'] = 'maildir:'; // Show last IMAP and POP3 logins $SHOW_LAST_LOGIN = true; +// Allow app passwords in CardDav, CalDav and ActiveSync +$ALLOW_APP_PASSWORDS_IN_EAS = true; + // UV flag handling in FIDO2/WebAuthn - defaults to false to allow iOS logins // true = required // false = preferred diff --git a/data/web/sogo-auth.php b/data/web/sogo-auth.php index 3bd19c6e4..e3557cc84 100644 --- a/data/web/sogo-auth.php +++ b/data/web/sogo-auth.php @@ -14,7 +14,8 @@ if (isset($_SERVER['PHP_AUTH_USER'])) { require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php'; $username = $_SERVER['PHP_AUTH_USER']; $password = $_SERVER['PHP_AUTH_PW']; - $login_check = check_login($username, $password); + $is_eas = preg_match('/^(\/SOGo|)\/(dav|Microsoft-Server-ActiveSync).*/', $_SERVER['HTTP_X_ORIGINAL_URI']); + $login_check = check_login($username, $password, $is_eas && $ALLOW_APP_PASSWORDS_IN_EAS); if ($login_check === 'user') { header("X-User: $username"); header("X-Auth: Basic ".base64_encode("$username:$password")); From 06ac1a14643e4718629f187045407b6a3cd0f348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Kellerer?= Date: Sun, 24 Oct 2021 17:30:33 +0200 Subject: [PATCH 02/11] Updated L10N DE,EN,FR,IT(EN) --- data/web/lang/lang.de.json | 2 +- data/web/lang/lang.en.json | 2 +- data/web/lang/lang.fr.json | 2 +- data/web/lang/lang.it.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/data/web/lang/lang.de.json b/data/web/lang/lang.de.json index ed516240f..15e981e21 100644 --- a/data/web/lang/lang.de.json +++ b/data/web/lang/lang.de.json @@ -991,7 +991,7 @@ "alias_valid_until": "Gültig bis", "aliases_also_send_as": "Darf außerdem versenden als Benutzer", "aliases_send_as_all": "Absender für folgende Domains und zugehörige Alias-Domains nicht prüfen", - "app_hint": "App-Passwörter sind alternative Passwörter für den IMAP- und SMTP-Login am Mailserver. Der Benutzername bleibt unverändert.
SOGo (und damit ActiveSync) ist mit diesem Kennwort nicht verwendbar.", + "app_hint": "App-Passwörter sind alternative Passwörter für den IMAP-, SMTP-, CalDAV-, CardDAV- und EAS-Login am Mailserver. Der Benutzername bleibt unverändert.
SOGo Webmail ist mit diesem Kennwort nicht verwendbar.", "app_name": "App-Name", "app_passwds": "App-Passwörter", "apple_connection_profile": "Apple-Verbindungsprofil", diff --git a/data/web/lang/lang.en.json b/data/web/lang/lang.en.json index 3f8be347a..3f4a62202 100644 --- a/data/web/lang/lang.en.json +++ b/data/web/lang/lang.en.json @@ -1033,7 +1033,7 @@ "alias_valid_until": "Valid until", "aliases_also_send_as": "Also allowed to send as user", "aliases_send_as_all": "Do not check sender access for the following domain(s) and its alias domains", - "app_hint": "App passwords are alternative passwords for your IMAP and SMTP login. The username remains unchanged.
SOGo (including ActiveSync) is not available through app passwords.", + "app_hint": "App passwords are alternative passwords for your IMAP, SMTP, CalDAV, CardDAV and EAS login. The username remains unchanged. SOGo webmail is not available through app passwords.", "app_name": "App name", "app_passwds": "App passwords", "apple_connection_profile": "Apple connection profile", diff --git a/data/web/lang/lang.fr.json b/data/web/lang/lang.fr.json index baf407c00..9ba9e2796 100644 --- a/data/web/lang/lang.fr.json +++ b/data/web/lang/lang.fr.json @@ -953,7 +953,7 @@ "alias_valid_until": "Valide jusque", "aliases_also_send_as": "Aussi autorisé à envoyer en tant qu’utilisateur", "aliases_send_as_all": "Ne pas vérifier l’accès de l’expéditeur pour les domaines suivants et leurs alias", - "app_hint": "Les mots de passe d’application sont des mots de passe alternatifs pour votre connexion IMAP et SMTP. Le nom d’utilisateur reste inchangé.
SOGo (incluant ActiveSync) n'est pas disponible au travers de mots de passe.", + "app_hint": "Les mots de passe d’application sont des mots de passe alternatifs pour votre connexion IMAP, SMTP, Caldav, Carddav et EAS. Le nom d’utilisateur reste inchangé.
SOGo n'est pas disponible au travers de mots de passe.", "app_name": "Nom d'application", "app_passwds": "Mots de passe de l'application", "apple_connection_profile": "Profil de connexion Apple", diff --git a/data/web/lang/lang.it.json b/data/web/lang/lang.it.json index a7422d8b7..aa7a8dc28 100644 --- a/data/web/lang/lang.it.json +++ b/data/web/lang/lang.it.json @@ -999,7 +999,7 @@ "alias_valid_until": "Valido fino a", "aliases_also_send_as": "Può inviare come utente", "aliases_send_as_all": "Do not check sender access for the following domain(s) and its alias domains", - "app_hint": "App passwords are alternative passwords for your IMAP and SMTP login. The username remains unchanged.
SOGo (including ActiveSync) is not available through app passwords.", + "app_hint": "App passwords are alternative passwords for your IMAP, SMTP, CalDAV, CardDAV and EAS login. The username remains unchanged. SOGo webmail is not available through app passwords.", "app_name": "App name", "app_passwds": "App passwords", "apple_connection_profile": "Profilo di connessione Apple", From 2a4764aa4164f92865e206e47f97f3f4baaffb8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Kellerer?= Date: Sun, 24 Oct 2021 17:42:00 +0200 Subject: [PATCH 03/11] Updated L10N CS,DA,NL,RO,RU,SK,SV --- data/web/lang/lang.cs.json | 2 +- data/web/lang/lang.da.json | 2 +- data/web/lang/lang.nl.json | 2 +- data/web/lang/lang.ro.json | 2 +- data/web/lang/lang.ru.json | 2 +- data/web/lang/lang.sk.json | 2 +- data/web/lang/lang.sv.json | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/data/web/lang/lang.cs.json b/data/web/lang/lang.cs.json index edddb44e5..10cdc2357 100644 --- a/data/web/lang/lang.cs.json +++ b/data/web/lang/lang.cs.json @@ -1015,7 +1015,7 @@ "alias_valid_until": "Platný do", "aliases_also_send_as": "Smí odesílat také jako uživatel", "aliases_send_as_all": "Nekontrolovat přístup odesílatele pro následující doménu(y) a jejich aliasy domény:", - "app_hint": "Hesla aplikací jsou alternativní heslo pro přihlášení k IMAP a SMTP. Uživatelské jméno zůstává stejné.
SOGo (včetně ActiveSync) však nelze s heslem aplikace použít.", + "app_hint": "Hesla aplikací jsou alternativní heslo pro přihlášení k IMAP, SMTP, CalDAV, CardDAV a EAS. Uživatelské jméno zůstává stejné.
SOGo však nelze s heslem aplikace použít.", "app_name": "Název aplikace", "app_passwds": "Hesla aplikací", "apple_connection_profile": "Profil připojení Apple", diff --git a/data/web/lang/lang.da.json b/data/web/lang/lang.da.json index 5a854cfa7..95169179b 100644 --- a/data/web/lang/lang.da.json +++ b/data/web/lang/lang.da.json @@ -944,7 +944,7 @@ "alias_valid_until": "Gyldig indtil", "aliases_also_send_as": "Også tilladt at sende som bruger", "aliases_send_as_all": "Do not check sender access for the following domain(s) and its alias domains", - "app_hint": "App adgangskoder er alternative adgangskoder til din IMAP og SMTP login. Brugernavnet forbliver uændret.
SOGo (inklusive AktivSync) er ikke tilgængelig via app-adgangskoder.", + "app_hint": "App adgangskoder er alternative adgangskoder til din IMAP, SMTP, CalDAV, CardDAV og EAS login. Brugernavnet forbliver uændret.
SOGo er ikke tilgængelig via app-adgangskoder.", "app_name": "App navn", "app_passwds": "App kodeord", "apple_connection_profile": "Apple forbindelses profil", diff --git a/data/web/lang/lang.nl.json b/data/web/lang/lang.nl.json index 3ec00d54a..4afd4b143 100644 --- a/data/web/lang/lang.nl.json +++ b/data/web/lang/lang.nl.json @@ -968,7 +968,7 @@ "alias_valid_until": "Geldig tot", "aliases_also_send_as": "Toegestaan om te verzenden als", "aliases_send_as_all": "Controleer verzendtoegang voor de volgende domeinen, inclusief aliassen, niet", - "app_hint": "Appwachtwoorden zijn alternatieve wachtwoorden voor IMAP en SMTP. De gebruikersnaam blijft ongewijzigd.
SOGo (inclusief ActiveSync) is niet toegankelijk met een appwachtwoord.", + "app_hint": "Appwachtwoorden zijn alternatieve wachtwoorden voor IMAP, SMTP, CalDAV, CardDAV en EAS. De gebruikersnaam blijft ongewijzigd.
SOGo is niet toegankelijk met een appwachtwoord.", "app_name": "Naam van app", "app_passwds": "Appwachtwoorden", "apple_connection_profile": "Apple-verbindingsprofiel", diff --git a/data/web/lang/lang.ro.json b/data/web/lang/lang.ro.json index 289fbc059..3e03351da 100644 --- a/data/web/lang/lang.ro.json +++ b/data/web/lang/lang.ro.json @@ -1003,7 +1003,7 @@ "alias_valid_until": "Valabil până la", "aliases_also_send_as": "De asemenea, este permis să trimită ca utilizator", "aliases_send_as_all": "Nu se verifică accesul expeditorului pentru următorul(arele) domeniu(i) și domeniile sale alias", - "app_hint": "Parolele aplicației sunt parole alternative pentru autentificarea IMAP și SMTP. Numele de utilizator rămâne neschimbat.
SOGo (inclusiv ActiveSync) nu este disponibil prin parolele aplicației.", + "app_hint": "Parolele aplicației sunt parole alternative pentru autentificarea IMAP, SMTP, CalDAV, CardDAV și EAS. Numele de utilizator rămâne neschimbat.
SOGo nu este disponibil prin parolele aplicației.", "app_name": "Nume aplicație", "app_passwds": "Parole aplicație", "apple_connection_profile": "Profil de conexiune Apple", diff --git a/data/web/lang/lang.ru.json b/data/web/lang/lang.ru.json index a77025c23..8c8ab887f 100644 --- a/data/web/lang/lang.ru.json +++ b/data/web/lang/lang.ru.json @@ -1034,7 +1034,7 @@ "alias_valid_until": "Действителен до", "aliases_also_send_as": "Разрешено отправлять письма от имени", "aliases_send_as_all": "Разрешено отправлять письма от любого имени для домена и его псевдонимов", - "app_hint": "Пароли приложений - это альтернативные пароли для авторизации в IMAP и SMTP. При этом имя пользователя остается неизменным.
SOGo (включая ActiveSync) недоступен через пароли приложений.", + "app_hint": "Пароли приложений - это альтернативные пароли для авторизации в IMAP, SMTP, CalDAV, CardDAV и EAS. При этом имя пользователя остается неизменным.
SOGo недоступен через пароли приложений.", "app_name": "Название приложения", "app_passwds": "Пароли приложений", "apple_connection_profile": "Профиль подключения Apple", diff --git a/data/web/lang/lang.sk.json b/data/web/lang/lang.sk.json index 8be8efce4..bdf81425e 100644 --- a/data/web/lang/lang.sk.json +++ b/data/web/lang/lang.sk.json @@ -1034,7 +1034,7 @@ "alias_valid_until": "Platné do", "aliases_also_send_as": "Môže odosielať ako používateľ", "aliases_send_as_all": "Nekontrolovať prístup odosielateľa pre nasledujúcu doménu/y a jej alias domény", - "app_hint": "Heslá aplikácií sú alternatívne heslá pre vaše IMAP a SMTP prihlásenie. Používateľské meno zostáva nezmenené.
SOGo (zahŕňajúc ActiveSync) nie je momentálne podporovaný.", + "app_hint": "Heslá aplikácií sú alternatívne heslá pre vaše IMAP, SMTP, CalDAV, CardDAV a EAS prihlásenie. Používateľské meno zostáva nezmenené.
SOGo nie je momentálne podporovaný.", "app_name": "Meno aplikácie", "app_passwds": "Heslá aplikácií", "apple_connection_profile": "Apple konfiguračný profil", diff --git a/data/web/lang/lang.sv.json b/data/web/lang/lang.sv.json index a68b8602f..063a8f4a2 100644 --- a/data/web/lang/lang.sv.json +++ b/data/web/lang/lang.sv.json @@ -986,7 +986,7 @@ "alias_valid_until": "Giltig till", "aliases_also_send_as": "Som också har tillåtelse att skicka som användare", "aliases_send_as_all": "Kontrollera inte avsändaråtkomsten för följande domän/domäner och aliasdomäner", - "app_hint": "Applikationslösenord är ett alternativt lösenord för IMAP och SMTP inloggning på e-postservern. Användarnamnet förblir oförändrat.
SOGo (och därmed ActiveSync) kan inte användas med det här lösenordet.", + "app_hint": "Applikationslösenord är ett alternativt lösenord för IMAP, SMTP, CalDAV, CardDAV och EAS inloggning på e-postservern. Användarnamnet förblir oförändrat.
SOGo kan inte användas med det här lösenordet.", "app_name": "Applikationsnamn", "app_passwds": "Applikationslösenord", "apple_connection_profile": "Apple-anslutningsprofil", From 75c01bd5df4fd942072a53237c4f961358f7f1b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Kellerer?= Date: Sun, 24 Oct 2021 17:42:00 +0200 Subject: [PATCH 04/11] Updated L10N CS,DA,NL,RO,RU,SK,SV --- data/web/lang/lang.cs.json | 2 +- data/web/lang/lang.da.json | 2 +- data/web/lang/lang.nl.json | 2 +- data/web/lang/lang.ro.json | 2 +- data/web/lang/lang.ru.json | 2 +- data/web/lang/lang.sk.json | 2 +- data/web/lang/lang.sv.json | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/data/web/lang/lang.cs.json b/data/web/lang/lang.cs.json index 594be20c0..06e61353d 100644 --- a/data/web/lang/lang.cs.json +++ b/data/web/lang/lang.cs.json @@ -1015,7 +1015,7 @@ "alias_valid_until": "Platný do", "aliases_also_send_as": "Smí odesílat také jako uživatel", "aliases_send_as_all": "Nekontrolovat přístup odesílatele pro následující doménu(y) a jejich aliasy domény:", - "app_hint": "Hesla aplikací jsou alternativní heslo pro přihlášení k IMAP a SMTP. Uživatelské jméno zůstává stejné.
SOGo (včetně ActiveSync) však nelze s heslem aplikace použít.", + "app_hint": "Hesla aplikací jsou alternativní heslo pro přihlášení k IMAP, SMTP, CalDAV, CardDAV a EAS. Uživatelské jméno zůstává stejné.
SOGo však nelze s heslem aplikace použít.", "app_name": "Název aplikace", "app_passwds": "Hesla aplikací", "apple_connection_profile": "Profil připojení Apple", diff --git a/data/web/lang/lang.da.json b/data/web/lang/lang.da.json index 5a854cfa7..95169179b 100644 --- a/data/web/lang/lang.da.json +++ b/data/web/lang/lang.da.json @@ -944,7 +944,7 @@ "alias_valid_until": "Gyldig indtil", "aliases_also_send_as": "Også tilladt at sende som bruger", "aliases_send_as_all": "Do not check sender access for the following domain(s) and its alias domains", - "app_hint": "App adgangskoder er alternative adgangskoder til din IMAP og SMTP login. Brugernavnet forbliver uændret.
SOGo (inklusive AktivSync) er ikke tilgængelig via app-adgangskoder.", + "app_hint": "App adgangskoder er alternative adgangskoder til din IMAP, SMTP, CalDAV, CardDAV og EAS login. Brugernavnet forbliver uændret.
SOGo er ikke tilgængelig via app-adgangskoder.", "app_name": "App navn", "app_passwds": "App kodeord", "apple_connection_profile": "Apple forbindelses profil", diff --git a/data/web/lang/lang.nl.json b/data/web/lang/lang.nl.json index 3ec00d54a..4afd4b143 100644 --- a/data/web/lang/lang.nl.json +++ b/data/web/lang/lang.nl.json @@ -968,7 +968,7 @@ "alias_valid_until": "Geldig tot", "aliases_also_send_as": "Toegestaan om te verzenden als", "aliases_send_as_all": "Controleer verzendtoegang voor de volgende domeinen, inclusief aliassen, niet", - "app_hint": "Appwachtwoorden zijn alternatieve wachtwoorden voor IMAP en SMTP. De gebruikersnaam blijft ongewijzigd.
SOGo (inclusief ActiveSync) is niet toegankelijk met een appwachtwoord.", + "app_hint": "Appwachtwoorden zijn alternatieve wachtwoorden voor IMAP, SMTP, CalDAV, CardDAV en EAS. De gebruikersnaam blijft ongewijzigd.
SOGo is niet toegankelijk met een appwachtwoord.", "app_name": "Naam van app", "app_passwds": "Appwachtwoorden", "apple_connection_profile": "Apple-verbindingsprofiel", diff --git a/data/web/lang/lang.ro.json b/data/web/lang/lang.ro.json index 289fbc059..3e03351da 100644 --- a/data/web/lang/lang.ro.json +++ b/data/web/lang/lang.ro.json @@ -1003,7 +1003,7 @@ "alias_valid_until": "Valabil până la", "aliases_also_send_as": "De asemenea, este permis să trimită ca utilizator", "aliases_send_as_all": "Nu se verifică accesul expeditorului pentru următorul(arele) domeniu(i) și domeniile sale alias", - "app_hint": "Parolele aplicației sunt parole alternative pentru autentificarea IMAP și SMTP. Numele de utilizator rămâne neschimbat.
SOGo (inclusiv ActiveSync) nu este disponibil prin parolele aplicației.", + "app_hint": "Parolele aplicației sunt parole alternative pentru autentificarea IMAP, SMTP, CalDAV, CardDAV și EAS. Numele de utilizator rămâne neschimbat.
SOGo nu este disponibil prin parolele aplicației.", "app_name": "Nume aplicație", "app_passwds": "Parole aplicație", "apple_connection_profile": "Profil de conexiune Apple", diff --git a/data/web/lang/lang.ru.json b/data/web/lang/lang.ru.json index a77025c23..8c8ab887f 100644 --- a/data/web/lang/lang.ru.json +++ b/data/web/lang/lang.ru.json @@ -1034,7 +1034,7 @@ "alias_valid_until": "Действителен до", "aliases_also_send_as": "Разрешено отправлять письма от имени", "aliases_send_as_all": "Разрешено отправлять письма от любого имени для домена и его псевдонимов", - "app_hint": "Пароли приложений - это альтернативные пароли для авторизации в IMAP и SMTP. При этом имя пользователя остается неизменным.
SOGo (включая ActiveSync) недоступен через пароли приложений.", + "app_hint": "Пароли приложений - это альтернативные пароли для авторизации в IMAP, SMTP, CalDAV, CardDAV и EAS. При этом имя пользователя остается неизменным.
SOGo недоступен через пароли приложений.", "app_name": "Название приложения", "app_passwds": "Пароли приложений", "apple_connection_profile": "Профиль подключения Apple", diff --git a/data/web/lang/lang.sk.json b/data/web/lang/lang.sk.json index 1858533f8..59dc0780c 100644 --- a/data/web/lang/lang.sk.json +++ b/data/web/lang/lang.sk.json @@ -1034,7 +1034,7 @@ "alias_valid_until": "Platné do", "aliases_also_send_as": "Môže odosielať ako používateľ", "aliases_send_as_all": "Nekontrolovať prístup odosielateľa pre nasledujúcu doménu/y a jej alias domény", - "app_hint": "Heslá aplikácií sú alternatívne heslá pre vaše IMAP a SMTP prihlásenie. Používateľské meno zostáva nezmenené.
SOGo (zahŕňajúc ActiveSync) nie je momentálne podporovaný.", + "app_hint": "Heslá aplikácií sú alternatívne heslá pre vaše IMAP, SMTP, CalDAV, CardDAV a EAS prihlásenie. Používateľské meno zostáva nezmenené.
SOGo nie je momentálne podporovaný.", "app_name": "Meno aplikácie", "app_passwds": "Heslá aplikácií", "apple_connection_profile": "Apple konfiguračný profil", diff --git a/data/web/lang/lang.sv.json b/data/web/lang/lang.sv.json index a68b8602f..063a8f4a2 100644 --- a/data/web/lang/lang.sv.json +++ b/data/web/lang/lang.sv.json @@ -986,7 +986,7 @@ "alias_valid_until": "Giltig till", "aliases_also_send_as": "Som också har tillåtelse att skicka som användare", "aliases_send_as_all": "Kontrollera inte avsändaråtkomsten för följande domän/domäner och aliasdomäner", - "app_hint": "Applikationslösenord är ett alternativt lösenord för IMAP och SMTP inloggning på e-postservern. Användarnamnet förblir oförändrat.
SOGo (och därmed ActiveSync) kan inte användas med det här lösenordet.", + "app_hint": "Applikationslösenord är ett alternativt lösenord för IMAP, SMTP, CalDAV, CardDAV och EAS inloggning på e-postservern. Användarnamnet förblir oförändrat.
SOGo kan inte användas med det här lösenordet.", "app_name": "Applikationsnamn", "app_passwds": "Applikationslösenord", "apple_connection_profile": "Apple-anslutningsprofil", From d38c37125393faf4eef00590b8437cfd862bef66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Kellerer?= Date: Wed, 27 Oct 2021 09:39:34 +0200 Subject: [PATCH 05/11] Removed toggle ALLOW_APP_PASSWORDS_IN_EAS --- data/web/autodiscover.php | 3 +-- data/web/inc/vars.inc.php | 3 --- data/web/sogo-auth.php | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/data/web/autodiscover.php b/data/web/autodiscover.php index 5834235be..cc6807baf 100644 --- a/data/web/autodiscover.php +++ b/data/web/autodiscover.php @@ -68,8 +68,7 @@ if (empty($_SERVER['PHP_AUTH_USER']) || empty($_SERVER['PHP_AUTH_PW'])) { exit(0); } -$allow_app_passwords = $ALLOW_APP_PASSWORDS_IN_EAS === true || $autodiscover_config['autodiscoverType'] == 'imap'; -$login_role = check_login($login_user, $login_pass, $allow_app_passwords); +$login_role = check_login($login_user, $login_pass, true); if ($login_role === "user") { header("Content-Type: application/xml"); diff --git a/data/web/inc/vars.inc.php b/data/web/inc/vars.inc.php index 8a83f964e..91d2145da 100644 --- a/data/web/inc/vars.inc.php +++ b/data/web/inc/vars.inc.php @@ -188,9 +188,6 @@ $MAILBOX_DEFAULT_ATTRIBUTES['mailbox_format'] = 'maildir:'; // Show last IMAP and POP3 logins $SHOW_LAST_LOGIN = true; -// Allow app passwords in CardDav, CalDav and ActiveSync -$ALLOW_APP_PASSWORDS_IN_EAS = true; - // UV flag handling in FIDO2/WebAuthn - defaults to false to allow iOS logins // true = required // false = preferred diff --git a/data/web/sogo-auth.php b/data/web/sogo-auth.php index 7784a181d..a4b8ffcfd 100644 --- a/data/web/sogo-auth.php +++ b/data/web/sogo-auth.php @@ -15,7 +15,7 @@ if (isset($_SERVER['PHP_AUTH_USER'])) { $username = $_SERVER['PHP_AUTH_USER']; $password = $_SERVER['PHP_AUTH_PW']; $is_eas = preg_match('/^(\/SOGo|)\/(dav|Microsoft-Server-ActiveSync).*/', $_SERVER['HTTP_X_ORIGINAL_URI']); - $login_check = check_login($username, $password, $is_eas && $ALLOW_APP_PASSWORDS_IN_EAS); + $login_check = check_login($username, $password, $is_eas); if ($login_check === 'user') { header("X-User: $username"); header("X-Auth: Basic ".base64_encode("$username:$password")); From c0011013b8f29af1bc5dce4349e8ccf145dc4264 Mon Sep 17 00:00:00 2001 From: andryyy Date: Wed, 27 Oct 2021 12:49:52 +0200 Subject: [PATCH 06/11] [Compose] Update SOGo image --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 7a63f4972..9269421b3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -164,7 +164,7 @@ services: - phpfpm sogo-mailcow: - image: mailcow/sogo:1.101 + image: mailcow/sogo:1.102 environment: - DBNAME=${DBNAME} - DBUSER=${DBUSER} From f01de1a5c064808f11760aa1daf0dedc3bb46fda Mon Sep 17 00:00:00 2001 From: andryyy Date: Wed, 27 Oct 2021 13:42:45 +0200 Subject: [PATCH 07/11] [Web] Disable SSO button when admin login is disabled, fixes #4297 --- data/web/inc/header.inc.php | 1 + data/web/templates/user/tab-user-auth.twig | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/data/web/inc/header.inc.php b/data/web/inc/header.inc.php index feea441f3..6c783a0bf 100644 --- a/data/web/inc/header.inc.php +++ b/data/web/inc/header.inc.php @@ -44,6 +44,7 @@ $globalVariables = [ 'available_languages' => $AVAILABLE_LANGUAGES, 'lang' => $lang, 'skip_sogo' => (getenv('SKIP_SOGO') == 'y'), + 'allow_admin_email_login' => (getenv('ALLOW_ADMIN_EMAIL_LOGIN') == 'n'), 'mailcow_apps' => $MAILCOW_APPS, 'app_links' => customize('get', 'app_links'), 'is_root_uri' => (parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) == '/'), diff --git a/data/web/templates/user/tab-user-auth.twig b/data/web/templates/user/tab-user-auth.twig index f658215a8..0dbfbb005 100644 --- a/data/web/templates/user/tab-user-auth.twig +++ b/data/web/templates/user/tab-user-auth.twig @@ -6,9 +6,15 @@
- - {{ lang.user.open_webmail_sso }} - + {% if dual_login and allow_admin_email_login == 'n' %} + + {% else %} + + {{ lang.user.open_webmail_sso }} + + {% endif %}

From e13bc242a4130c1333f995c1bf02369c06e3a16d Mon Sep 17 00:00:00 2001 From: andryyy Date: Thu, 28 Oct 2021 21:57:19 +0200 Subject: [PATCH 08/11] [Web, Dovecot] Allow to define scope of services for app passwords --- data/Dockerfiles/dovecot/docker-entrypoint.sh | 36 ++++++++------- data/web/edit.php | 2 +- data/web/inc/functions.app_passwd.inc.php | 43 ++++++++++++++---- data/web/inc/functions.inc.php | 44 ++++++++++++++++++- data/web/inc/init_db.inc.php | 6 ++- data/web/js/site/user.js | 13 ++++-- data/web/lang/lang.de.json | 3 ++ data/web/lang/lang.en.json | 3 ++ data/web/sogo-auth.php | 23 +++++++--- data/web/templates/base.twig | 2 +- data/web/templates/edit/app-passwd.twig | 12 +++++ data/web/templates/modals/user.twig | 11 +++++ data/web/templates/user/tab-user-auth.twig | 2 +- docker-compose.yml | 2 +- 14 files changed, 161 insertions(+), 41 deletions(-) diff --git a/data/Dockerfiles/dovecot/docker-entrypoint.sh b/data/Dockerfiles/dovecot/docker-entrypoint.sh index 798078bd4..b6b775fb0 100755 --- a/data/Dockerfiles/dovecot/docker-entrypoint.sh +++ b/data/Dockerfiles/dovecot/docker-entrypoint.sh @@ -163,24 +163,26 @@ function auth_password_verify(req, pass) row = cur:fetch (row, "a") end - -- check against app passwds - -- removed on 22nd Oct 2021: AND IFNULL(JSON_UNQUOTE(JSON_VALUE(mailbox.attributes, '$.force_pw_update')), 0) != '1' - local cur,errorString = con:execute(string.format([[SELECT app_passwd.id, app_passwd.password FROM app_passwd - INNER JOIN mailbox ON mailbox.username = app_passwd.mailbox - WHERE mailbox = '%s' - AND IFNULL(JSON_UNQUOTE(JSON_VALUE(mailbox.attributes, '$.%s_access')), 1) = '1' - AND app_passwd.active = '1' - AND mailbox.active = '1' - AND app_passwd.domain IN (SELECT domain FROM domain WHERE domain='%s' AND active='1')]], con:escape(req.user), con:escape(req.service), con:escape(req.domain))) - local row = cur:fetch ({}, "a") - while row do - if req.password_verify(req, row.password, pass) == 1 then - cur:close() - con:execute(string.format([[REPLACE INTO sasl_log (service, app_password, username, real_rip) - VALUES ("%s", %d, "%s", "%s")]], con:escape(req.service), row.id, con:escape(req.user), con:escape(req.real_rip))) - return dovecot.auth.PASSDB_RESULT_OK, "password=" .. pass + -- check against app passwds for imap and smtp + -- app passwords are only available for imap and smtp in dovecot + if req.service == "smtp" or req.service == "imap" then + local cur,errorString = con:execute(string.format([[SELECT app_passwd.id, app_passwd.imap_access, app_passwd.smtp_access, app_passwd.password FROM app_passwd + INNER JOIN mailbox ON mailbox.username = app_passwd.mailbox + WHERE mailbox = '%s' + AND app_passwd.%s_access = '1' + AND app_passwd.active = '1' + AND mailbox.active = '1' + AND app_passwd.domain IN (SELECT domain FROM domain WHERE domain='%s' AND active='1')]], con:escape(req.user), con:escape(req.service), con:escape(req.domain))) + local row = cur:fetch ({}, "a") + while row do + if req.password_verify(req, row.password, pass) == 1 then + cur:close() + con:execute(string.format([[REPLACE INTO sasl_log (service, app_password, username, real_rip) + VALUES ("%s", %d, "%s", "%s")]], con:escape(req.service), row.id, con:escape(req.user), con:escape(req.real_rip))) + return dovecot.auth.PASSDB_RESULT_OK, "password=" .. pass + end + row = cur:fetch (row, "a") end - row = cur:fetch (row, "a") end return dovecot.auth.PASSDB_RESULT_PASSWORD_MISMATCH, "Failed to authenticate" diff --git a/data/web/edit.php b/data/web/edit.php index bc27c6f21..dfba84794 100644 --- a/data/web/edit.php +++ b/data/web/edit.php @@ -11,7 +11,7 @@ $template = 'edit.twig'; $template_data = []; $result = null; if (isset($_SESSION['mailcow_cc_role'])) { - if ($_SESSION['mailcow_cc_role'] == "admin" || $_SESSION['mailcow_cc_role'] == "domainadmin") { + if ($_SESSION['mailcow_cc_role'] == "admin" || $_SESSION['mailcow_cc_role'] == "domainadmin") { if (isset($_GET["alias"]) && !empty($_GET["alias"])) { $alias = html_entity_decode(rawurldecode($_GET["alias"])); diff --git a/data/web/inc/functions.app_passwd.inc.php b/data/web/inc/functions.app_passwd.inc.php index 68cc85cde..701bbe686 100644 --- a/data/web/inc/functions.app_passwd.inc.php +++ b/data/web/inc/functions.app_passwd.inc.php @@ -27,6 +27,11 @@ function app_passwd($_action, $_data = null) { $password = $_data['app_passwd']; $password2 = $_data['app_passwd2']; $active = intval($_data['active']); + $protocols = (array)$_data['protocols']; + $imap_access = (in_array('imap_access', $protocols)) ? 1 : 0; + $dav_access = (in_array('dav_access', $protocols)) ? 1 : 0; + $smtp_access = (in_array('smtp_access', $protocols)) ? 1 : 0; + $eas_access = (in_array('eas_access', $protocols)) ? 1 : 0; $domain = mailbox('get', 'mailbox_details', $username)['domain']; if (empty($domain)) { $_SESSION['return'][] = array( @@ -61,13 +66,17 @@ function app_passwd($_action, $_data = null) { ); return false; } - $stmt = $pdo->prepare("INSERT INTO `app_passwd` (`name`, `mailbox`, `domain`, `password`, `active`) - VALUES (:app_name, :mailbox, :domain, :password, :active)"); + $stmt = $pdo->prepare("INSERT INTO `app_passwd` (`name`, `mailbox`, `domain`, `password`, `imap_access`, `smtp_access`, `eas_access`, `dav_access`, `active`) + VALUES (:app_name, :mailbox, :domain, :password, :imap_access, :smtp_access, :eas_access, :dav_access, :active)"); $stmt->execute(array( ':app_name' => $app_name, ':mailbox' => $username, ':domain' => $domain, ':password' => $password_hashed, + ':imap_access' => $imap_access, + ':smtp_access' => $smtp_access, + ':eas_access' => $eas_access, + ':dav_access' => $dav_access, ':active' => $active )); $_SESSION['return'][] = array( @@ -84,6 +93,19 @@ function app_passwd($_action, $_data = null) { $app_name = (!empty($_data['app_name'])) ? $_data['app_name'] : $is_now['name']; $password = (!empty($_data['password'])) ? $_data['password'] : null; $password2 = (!empty($_data['password2'])) ? $_data['password2'] : null; + if (isset($_data['protocols'])) { + $protocols = (array)$_data['protocols']; + $imap_access = (in_array('imap_access', $protocols)) ? 1 : 0; + $dav_access = (in_array('dav_access', $protocols)) ? 1 : 0; + $smtp_access = (in_array('smtp_access', $protocols)) ? 1 : 0; + $eas_access = (in_array('eas_access', $protocols)) ? 1 : 0; + } + else { + $imap_access = $is_now['imap_access']; + $smtp_access = $is_now['smtp_access']; + $dav_access = $is_now['dav_access']; + $eas_access = $is_now['eas_access']; + } $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active']; } else { @@ -122,14 +144,23 @@ function app_passwd($_action, $_data = null) { ':id' => $id )); } + $stmt = $pdo->prepare("UPDATE `app_passwd` SET `name` = :app_name, `mailbox` = :username, + `imap_access` = :imap_access, + `smtp_access` = :smtp_access, + `eas_access` = :eas_access, + `dav_access` = :dav_access, `active` = :active WHERE `id` = :id"); $stmt->execute(array( ':app_name' => $app_name, ':username' => $username, + ':imap_access' => $imap_access, + ':smtp_access' => $smtp_access, + ':eas_access' => $eas_access, + ':dav_access' => $dav_access, ':active' => $active, ':id' => $id )); @@ -180,13 +211,7 @@ function app_passwd($_action, $_data = null) { break; case 'details': $app_passwd_data = array(); - $stmt = $pdo->prepare("SELECT `id`, - `name`, - `mailbox`, - `domain`, - `created`, - `modified`, - `active` + $stmt = $pdo->prepare("SELECT * FROM `app_passwd` WHERE `id` = :id"); $stmt->execute(array(':id' => $_data)); diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php index 8245c46e5..d05f6255c 100644 --- a/data/web/inc/functions.inc.php +++ b/data/web/inc/functions.inc.php @@ -807,10 +807,17 @@ function verify_hash($hash, $password) { } return false; } -function check_login($user, $pass, $allow_app_passwords = false) { +function check_login($user, $pass, $app_passwd_data = false) { global $pdo; global $redis; global $imap_server; + + if ($app_passwd_data === false) { + $app_passwd_data['eas'] = false; + $app_passwd_data['dav'] = false; + $app_passwd_data['proxyauth'] = false; + } + if (!filter_var($user, FILTER_VALIDATE_EMAIL) && !ctype_alnum(str_replace(array('_', '.', '-'), '', $user))) { $_SESSION['return'][] = array( 'type' => 'danger', @@ -819,6 +826,8 @@ function check_login($user, $pass, $allow_app_passwords = false) { ); return false; } + + // Validate admin $user = strtolower(trim($user)); $stmt = $pdo->prepare("SELECT `password` FROM `admin` WHERE `superadmin` = '1' @@ -854,6 +863,8 @@ function check_login($user, $pass, $allow_app_passwords = false) { } } } + + // Validate domain admin $stmt = $pdo->prepare("SELECT `password` FROM `admin` WHERE `superadmin` = '0' AND `active`='1' @@ -888,6 +899,8 @@ function check_login($user, $pass, $allow_app_passwords = false) { } } } + + // Validate mailbox user $stmt = $pdo->prepare("SELECT `password` FROM `mailbox` INNER JOIN domain on mailbox.domain = domain.domain WHERE `kind` NOT REGEXP 'location|thing|group' @@ -896,7 +909,7 @@ function check_login($user, $pass, $allow_app_passwords = false) { AND `username` = :user"); $stmt->execute(array(':user' => $user)); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); - if ($allow_app_passwords === true) { + if ($app_passwd_data['eas'] === true) { $stmt = $pdo->prepare("SELECT `app_passwd`.`password` as `password`, `app_passwd`.`id` as `app_passwd_id` FROM `app_passwd` INNER JOIN `mailbox` ON `mailbox`.`username` = `app_passwd`.`mailbox` INNER JOIN `domain` ON `mailbox`.`domain` = `domain`.`domain` @@ -904,6 +917,20 @@ function check_login($user, $pass, $allow_app_passwords = false) { AND `mailbox`.`active` = '1' AND `domain`.`active` = '1' AND `app_passwd`.`active` = '1' + AND `app_passwd`.`eas_access` = '1' + AND `app_passwd`.`mailbox` = :user"); + $stmt->execute(array(':user' => $user)); + $rows = array_merge($rows, $stmt->fetchAll(PDO::FETCH_ASSOC)); + } + elseif ($app_passwd_data['dav'] === true) { + $stmt = $pdo->prepare("SELECT `app_passwd`.`password` as `password`, `app_passwd`.`id` as `app_passwd_id` FROM `app_passwd` + INNER JOIN `mailbox` ON `mailbox`.`username` = `app_passwd`.`mailbox` + INNER JOIN `domain` ON `mailbox`.`domain` = `domain`.`domain` + WHERE `mailbox`.`kind` NOT REGEXP 'location|thing|group' + AND `mailbox`.`active` = '1' + AND `domain`.`active` = '1' + AND `app_passwd`.`active` = '1' + AND `app_passwd`.`dav_access` = '1' AND `app_passwd`.`mailbox` = :user"); $stmt->execute(array(':user' => $user)); $rows = array_merge($rows, $stmt->fetchAll(PDO::FETCH_ASSOC)); @@ -916,9 +943,20 @@ function check_login($user, $pass, $allow_app_passwords = false) { 'log' => array(__FUNCTION__, $user, '*'), 'msg' => array('logged_in_as', $user) ); + if ($app_passwd_data['proxyauth'] === true) { + $service = ($app_passwd_data['eas'] === true) ? 'EAS' : (($app_passwd_data['dav'] === true) ? 'DAV' : 'SSO'); + $stmt = $pdo->prepare("REPLACE INTO sasl_log (`service`, `app_password`, `username`, `real_rip`) VALUES (:service, :app_id, :username, :remote_addr)"); + $stmt->execute(array( + ':service' => $service, + ':app_id' => $row['app_passwd_id'], + ':username' => $user, + ':remote_addr' => $_SERVER['REMOTE_ADDR'] + )); + } return "user"; } } + if (!isset($_SESSION['ldelay'])) { $_SESSION['ldelay'] = "0"; $redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']); @@ -929,11 +967,13 @@ function check_login($user, $pass, $allow_app_passwords = false) { $redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']); error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']); } + $_SESSION['return'][] = array( 'type' => 'danger', 'log' => array(__FUNCTION__, $user, '*'), 'msg' => 'login_failed' ); + sleep($_SESSION['ldelay']); return false; } diff --git a/data/web/inc/init_db.inc.php b/data/web/inc/init_db.inc.php index c0c984b8b..f3aada9ad 100644 --- a/data/web/inc/init_db.inc.php +++ b/data/web/inc/init_db.inc.php @@ -3,7 +3,7 @@ function init_db_schema() { try { global $pdo; - $db_version = "23082021_2224"; + $db_version = "28102021_1600"; $stmt = $pdo->query("SHOW TABLES LIKE 'versions'"); $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC)); @@ -364,6 +364,10 @@ function init_db_schema() { "password" => "VARCHAR(255) NOT NULL", "created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)", "modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP", + "imap_access" => "TINYINT(1) NOT NULL DEFAULT '1'", + "smtp_access" => "TINYINT(1) NOT NULL DEFAULT '1'", + "dav_access" => "TINYINT(1) NOT NULL DEFAULT '1'", + "eas_access" => "TINYINT(1) NOT NULL DEFAULT '1'", "active" => "TINYINT(1) NOT NULL DEFAULT '1'" ), "keys" => array( diff --git a/data/web/js/site/user.js b/data/web/js/site/user.js index 6bfd84788..62d6e7891 100644 --- a/data/web/js/site/user.js +++ b/data/web/js/site/user.js @@ -101,8 +101,8 @@ jQuery(function($){ $.each(data.sasl, function (i, item) { var datetime = new Date(item.datetime.replace(/-/g, "/")); var local_datetime = datetime.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"}); - item.app_password ? app_password = ' (App)' : app_password = "", item.location ? ip_location = ' ' : ip_location = ""; - "smtp" == item.service ? service = '
' + item.service.toUpperCase() + '
' : "imap" == item.service ? service = '
' + item.service.toUpperCase() + "
" : service = '
' + item.service.toUpperCase() + "
"; + item.app_password ? app_password = ' App' : app_password = "", item.location ? ip_location = ' ' : ip_location = ""; + service = '
' + item.service.toUpperCase() + '
'; item.real_rip.startsWith("Web") ? real_rip = item.real_rip : real_rip = '' + item.real_rip + ""; ip_data = real_rip + ip_location + app_password; $(".last-login").append('
  • ' + local_datetime + " " + service + " " + lang.from + " " + ip_data + "
  • "); @@ -258,6 +258,7 @@ jQuery(function($){ {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"}, {"sorted": true,"name":"id","title":"ID","style":{"maxWidth":"60px","width":"60px","text-align":"center"}}, {"name":"name","title":lang.app_name}, + {"name":"protocols","title":lang.allowed_protocols}, {"name":"active","filterable": false,"style":{"maxWidth":"70px","width":"70px"},"title":lang.active,"formatter": function(value){return 1==value?'':0==value&&'';}}, {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"220px","width":"220px"},"type":"html","title":lang.action,"breakpoints":"xs sm"} ], @@ -271,7 +272,13 @@ jQuery(function($){ }, success: function (data) { $.each(data, function (i, item) { - item.name = escapeHtml(item.name); + item.name = escapeHtml(item.name) + item.protocols = [] + if (item.imap_access == 1) { item.protocols.push("IMAP"); } + if (item.smtp_access == 1) { item.protocols.push("SMTP"); } + if (item.eas_access == 1) { item.protocols.push("EAS/ActiveSync"); } + if (item.dav_access == 1) { item.protocols.push("DAV"); } + item.protocols = item.protocols.join(" ") if (acl_data.app_passwds === 1) { item.action = '
    ' + ' ' + lang.edit + '' + diff --git a/data/web/lang/lang.de.json b/data/web/lang/lang.de.json index 15e981e21..33fadb417 100644 --- a/data/web/lang/lang.de.json +++ b/data/web/lang/lang.de.json @@ -42,6 +42,7 @@ "alias_domain_info": "Nur gültige Domains. Getrennt durch Komma.", "app_name": "App-Name", "app_password": "App-Passwort hinzufügen", + "app_passwd_protocols": "Zugelassene Protokolle für App-Passwort", "automap": "Ordner automatisch mappen (\"Sent items\", \"Sent\" => \"Sent\" etc.)", "backup_mx_options": "Relay-Optionen", "bcc_dest_format": "BCC-Ziel muss eine gültige E-Mail-Adresse sein.", @@ -508,6 +509,7 @@ "allowed_protocols": "Erlaubte Protokolle", "app_name": "App-Name", "app_passwd": "App-Passwörter", + "app_passwd_protocols": "Zugelassene Protokolle für App-Passwort", "automap": "Ordner automatisch mappen (\"Sent items\", \"Sent\" => \"Sent\" etc.)", "backup_mx_options": "Relay-Optionen", "bcc_dest_format": "BCC-Ziel muss eine gültige E-Mail-Adresse sein.", @@ -992,6 +994,7 @@ "aliases_also_send_as": "Darf außerdem versenden als Benutzer", "aliases_send_as_all": "Absender für folgende Domains und zugehörige Alias-Domains nicht prüfen", "app_hint": "App-Passwörter sind alternative Passwörter für den IMAP-, SMTP-, CalDAV-, CardDAV- und EAS-Login am Mailserver. Der Benutzername bleibt unverändert.
    SOGo Webmail ist mit diesem Kennwort nicht verwendbar.", + "allowed_protocols": "Erlaubte Protokolle", "app_name": "App-Name", "app_passwds": "App-Passwörter", "apple_connection_profile": "Apple-Verbindungsprofil", diff --git a/data/web/lang/lang.en.json b/data/web/lang/lang.en.json index 3f4a62202..d060b6ec8 100644 --- a/data/web/lang/lang.en.json +++ b/data/web/lang/lang.en.json @@ -42,6 +42,7 @@ "alias_domain_info": "Valid domain names only (comma-separated).", "app_name": "App name", "app_password": "Add app password", + "app_passwd_protocols": "Allowed protocols for app password", "automap": "Try to automap folders (\"Sent items\", \"Sent\" => \"Sent\" etc.)", "backup_mx_options": "Relay options", "bcc_dest_format": "BCC destination must be a single valid email address.
    If you need to send a copy to multiple addresses, create an alias and use it here.", @@ -514,6 +515,7 @@ "allowed_protocols": "Allowed protocols", "app_name": "App name", "app_passwd": "App password", + "app_passwd_protocols": "Allowed protocols for app password", "automap": "Try to automap folders (\"Sent items\", \"Sent\" => \"Sent\" etc.)", "backup_mx_options": "Relay options", "bcc_dest_format": "BCC destination must be a single valid email address.
    If you need to send a copy to multiple addresses, create an alias and use it here.", @@ -1034,6 +1036,7 @@ "aliases_also_send_as": "Also allowed to send as user", "aliases_send_as_all": "Do not check sender access for the following domain(s) and its alias domains", "app_hint": "App passwords are alternative passwords for your IMAP, SMTP, CalDAV, CardDAV and EAS login. The username remains unchanged. SOGo webmail is not available through app passwords.", + "allowed_protocols": "Allowed protocols", "app_name": "App name", "app_passwds": "App passwords", "apple_connection_profile": "Apple connection profile", diff --git a/data/web/sogo-auth.php b/data/web/sogo-auth.php index a4b8ffcfd..3c0130da8 100644 --- a/data/web/sogo-auth.php +++ b/data/web/sogo-auth.php @@ -14,8 +14,16 @@ if (isset($_SERVER['PHP_AUTH_USER'])) { require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php'; $username = $_SERVER['PHP_AUTH_USER']; $password = $_SERVER['PHP_AUTH_PW']; - $is_eas = preg_match('/^(\/SOGo|)\/(dav|Microsoft-Server-ActiveSync).*/', $_SERVER['HTTP_X_ORIGINAL_URI']); - $login_check = check_login($username, $password, $is_eas); + $is_eas = false; + $is_dav = false; + $original_uri = isset($_SERVER['HTTP_X_ORIGINAL_URI']) ? $_SERVER['HTTP_X_ORIGINAL_URI'] : ''; + if (preg_match('/^(\/SOGo|)\/dav.*/', $original_uri) === 1) { + $is_dav = true; + } + elseif (preg_match('/^(\/SOGo|)\/Microsoft-Server-ActiveSync.*/', $original_uri) === 1) { + $is_eas = true; + } + $login_check = check_login($username, $password, array('dav' => $is_dav, 'eas' => $is_eas, 'proxyauth' => true)); if ($login_check === 'user') { header("X-User: $username"); header("X-Auth: Basic ".base64_encode("$username:$password")); @@ -44,6 +52,13 @@ elseif (isset($_GET['login'])) { // register username and password in session $_SESSION[$session_var_user_allowed][] = $login; $_SESSION[$session_var_pass] = $sogo_sso_pass; + // update sasl logs + $service = ($app_passwd_data['eas'] === true) ? 'EAS' : 'DAV'; + $stmt = $pdo->prepare("REPLACE INTO sasl_log (`service`, `app_password`, `username`, `real_rip`) VALUES ('SSO', 0, :username, :remote_addr)"); + $stmt->execute(array( + ':username' => $login, + ':remote_addr' => $_SERVER['REMOTE_ADDR'] + )); // redirect to sogo (sogo will get the correct credentials via nginx auth_request header("Location: /SOGo/so/${login}"); exit; @@ -55,9 +70,7 @@ elseif (isset($_GET['login'])) { exit; } // only check for admin-login on sogo GUI requests -elseif ( - strcasecmp(substr($_SERVER['HTTP_X_ORIGINAL_URI'], 0, 9), "/SOGo/so/") === 0 -) { +elseif (isset($_SERVER['HTTP_X_ORIGINAL_URI']) && strcasecmp(substr($_SERVER['HTTP_X_ORIGINAL_URI'], 0, 9), "/SOGo/so/") === 0) { // this is an nginx auth_request call, we check for existing sogo-sso session variables session_start(); // extract email address from "/SOGo/so/user@domain/xy" diff --git a/data/web/templates/base.twig b/data/web/templates/base.twig index 4243f6ac2..e587500a6 100644 --- a/data/web/templates/base.twig +++ b/data/web/templates/base.twig @@ -170,7 +170,7 @@ function recursiveBase64StrToArrayBuffer(obj) { // TFA, CSRF, Alerts in footer.inc.php // Other general functions in mailcow.js {% for alert_type, alert_msg in alerts %} - mailcow_alert_box('{{ alert_msg|raw }}', '{{ alert_type }}'); + mailcow_alert_box('{{ alert_msg|raw|replace({"\n": "", "\r": "", "\t": "
    "}) }}', '{{ alert_type }}'); {% endfor %} // Confirm TFA modal diff --git a/data/web/templates/edit/app-passwd.twig b/data/web/templates/edit/app-passwd.twig index d220c47e6..d7bb617a2 100644 --- a/data/web/templates/edit/app-passwd.twig +++ b/data/web/templates/edit/app-passwd.twig @@ -5,6 +5,7 @@

    {{ lang.edit.app_passwd }}

    +
    @@ -30,6 +31,17 @@
    +
    + +
    + +
    +
    diff --git a/data/web/templates/modals/user.twig b/data/web/templates/modals/user.twig index c3b4086c7..130658390 100644 --- a/data/web/templates/modals/user.twig +++ b/data/web/templates/modals/user.twig @@ -213,6 +213,17 @@

    {{ lang.user.new_password_description }}

    +
    + +
    + +
    +
    diff --git a/data/web/templates/user/tab-user-auth.twig b/data/web/templates/user/tab-user-auth.twig index 0dbfbb005..5687f5a05 100644 --- a/data/web/templates/user/tab-user-auth.twig +++ b/data/web/templates/user/tab-user-auth.twig @@ -11,7 +11,7 @@ {{ lang.user.open_webmail_sso }} {% else %} - + {{ lang.user.open_webmail_sso }} {% endif %} diff --git a/docker-compose.yml b/docker-compose.yml index 9269421b3..753271ad8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -211,7 +211,7 @@ services: - sogo dovecot-mailcow: - image: mailcow/dovecot:1.157 + image: mailcow/dovecot:1.158 depends_on: - mysql-mailcow dns: From 514340b2a705d08908ed6e5d84efb54e45c41f8a Mon Sep 17 00:00:00 2001 From: andryyy Date: Thu, 28 Oct 2021 22:05:28 +0200 Subject: [PATCH 09/11] [Web] Minor fix --- data/web/inc/functions.inc.php | 10 ++-------- data/web/sogo-auth.php | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php index d05f6255c..1425ea3aa 100644 --- a/data/web/inc/functions.inc.php +++ b/data/web/inc/functions.inc.php @@ -812,12 +812,6 @@ function check_login($user, $pass, $app_passwd_data = false) { global $redis; global $imap_server; - if ($app_passwd_data === false) { - $app_passwd_data['eas'] = false; - $app_passwd_data['dav'] = false; - $app_passwd_data['proxyauth'] = false; - } - if (!filter_var($user, FILTER_VALIDATE_EMAIL) && !ctype_alnum(str_replace(array('_', '.', '-'), '', $user))) { $_SESSION['return'][] = array( 'type' => 'danger', @@ -943,8 +937,8 @@ function check_login($user, $pass, $app_passwd_data = false) { 'log' => array(__FUNCTION__, $user, '*'), 'msg' => array('logged_in_as', $user) ); - if ($app_passwd_data['proxyauth'] === true) { - $service = ($app_passwd_data['eas'] === true) ? 'EAS' : (($app_passwd_data['dav'] === true) ? 'DAV' : 'SSO'); + if ($app_passwd_data['eas'] === true || $app_passwd_data['dav'] === true) { + $service = ($app_passwd_data['eas'] === true) ? 'EAS' : 'DAV'; $stmt = $pdo->prepare("REPLACE INTO sasl_log (`service`, `app_password`, `username`, `real_rip`) VALUES (:service, :app_id, :username, :remote_addr)"); $stmt->execute(array( ':service' => $service, diff --git a/data/web/sogo-auth.php b/data/web/sogo-auth.php index 3c0130da8..1e1632324 100644 --- a/data/web/sogo-auth.php +++ b/data/web/sogo-auth.php @@ -23,7 +23,7 @@ if (isset($_SERVER['PHP_AUTH_USER'])) { elseif (preg_match('/^(\/SOGo|)\/Microsoft-Server-ActiveSync.*/', $original_uri) === 1) { $is_eas = true; } - $login_check = check_login($username, $password, array('dav' => $is_dav, 'eas' => $is_eas, 'proxyauth' => true)); + $login_check = check_login($username, $password, array('dav' => $is_dav, 'eas' => $is_eas)); if ($login_check === 'user') { header("X-User: $username"); header("X-Auth: Basic ".base64_encode("$username:$password")); From 15ce95e78d262322cd65f1a6241753d686e462e3 Mon Sep 17 00:00:00 2001 From: andryyy Date: Fri, 29 Oct 2021 06:15:10 +0200 Subject: [PATCH 10/11] [Web, Dovecot] Add sieve and pop3 to protocol access for app passwords --- data/Dockerfiles/dovecot/docker-entrypoint.sh | 6 +++--- data/web/inc/functions.app_passwd.inc.php | 16 ++++++++++++++-- data/web/inc/init_db.inc.php | 4 +++- data/web/js/site/user.js | 4 +++- data/web/templates/edit/app-passwd.twig | 2 ++ data/web/templates/modals/user.twig | 2 ++ 6 files changed, 27 insertions(+), 7 deletions(-) diff --git a/data/Dockerfiles/dovecot/docker-entrypoint.sh b/data/Dockerfiles/dovecot/docker-entrypoint.sh index b6b775fb0..6645331bd 100755 --- a/data/Dockerfiles/dovecot/docker-entrypoint.sh +++ b/data/Dockerfiles/dovecot/docker-entrypoint.sh @@ -164,9 +164,9 @@ function auth_password_verify(req, pass) end -- check against app passwds for imap and smtp - -- app passwords are only available for imap and smtp in dovecot - if req.service == "smtp" or req.service == "imap" then - local cur,errorString = con:execute(string.format([[SELECT app_passwd.id, app_passwd.imap_access, app_passwd.smtp_access, app_passwd.password FROM app_passwd + -- app passwords are only available for imap, smtp, sieve and pop3 when using sasl + if req.service == "smtp" or req.service == "imap" or req.service == "sieve" or req.service == "pop3" then + local cur,errorString = con:execute(string.format([[SELECT app_passwd.id, app_passwd.imap_access, app_passwd.smtp_access, app_passwd.sieve_access, app_passwd.pop3_access, app_passwd.password FROM app_passwd INNER JOIN mailbox ON mailbox.username = app_passwd.mailbox WHERE mailbox = '%s' AND app_passwd.%s_access = '1' diff --git a/data/web/inc/functions.app_passwd.inc.php b/data/web/inc/functions.app_passwd.inc.php index 701bbe686..b493fc914 100644 --- a/data/web/inc/functions.app_passwd.inc.php +++ b/data/web/inc/functions.app_passwd.inc.php @@ -32,6 +32,8 @@ function app_passwd($_action, $_data = null) { $dav_access = (in_array('dav_access', $protocols)) ? 1 : 0; $smtp_access = (in_array('smtp_access', $protocols)) ? 1 : 0; $eas_access = (in_array('eas_access', $protocols)) ? 1 : 0; + $pop3_access = (in_array('pop3_access', $protocols)) ? 1 : 0; + $sieve_access = (in_array('sieve_access', $protocols)) ? 1 : 0; $domain = mailbox('get', 'mailbox_details', $username)['domain']; if (empty($domain)) { $_SESSION['return'][] = array( @@ -66,8 +68,8 @@ function app_passwd($_action, $_data = null) { ); return false; } - $stmt = $pdo->prepare("INSERT INTO `app_passwd` (`name`, `mailbox`, `domain`, `password`, `imap_access`, `smtp_access`, `eas_access`, `dav_access`, `active`) - VALUES (:app_name, :mailbox, :domain, :password, :imap_access, :smtp_access, :eas_access, :dav_access, :active)"); + $stmt = $pdo->prepare("INSERT INTO `app_passwd` (`name`, `mailbox`, `domain`, `password`, `imap_access`, `smtp_access`, `eas_access`, `dav_access`, `pop3_access`, `sieve_access`, `active`) + VALUES (:app_name, :mailbox, :domain, :password, :imap_access, :smtp_access, :eas_access, :dav_access, :pop3_access, :sieve_access, :active)"); $stmt->execute(array( ':app_name' => $app_name, ':mailbox' => $username, @@ -77,6 +79,8 @@ function app_passwd($_action, $_data = null) { ':smtp_access' => $smtp_access, ':eas_access' => $eas_access, ':dav_access' => $dav_access, + ':pop3_access' => $pop3_access, + ':sieve_access' => $sieve_access, ':active' => $active )); $_SESSION['return'][] = array( @@ -99,12 +103,16 @@ function app_passwd($_action, $_data = null) { $dav_access = (in_array('dav_access', $protocols)) ? 1 : 0; $smtp_access = (in_array('smtp_access', $protocols)) ? 1 : 0; $eas_access = (in_array('eas_access', $protocols)) ? 1 : 0; + $pop3_access = (in_array('pop3_access', $protocols)) ? 1 : 0; + $sieve_access = (in_array('sieve_access', $protocols)) ? 1 : 0; } else { $imap_access = $is_now['imap_access']; $smtp_access = $is_now['smtp_access']; $dav_access = $is_now['dav_access']; $eas_access = $is_now['eas_access']; + $pop3_access = $is_now['pop3_access']; + $sieve_access = $is_now['sieve_access']; } $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active']; } @@ -152,6 +160,8 @@ function app_passwd($_action, $_data = null) { `smtp_access` = :smtp_access, `eas_access` = :eas_access, `dav_access` = :dav_access, + `pop3_access` = :pop3_access, + `sieve_access` = :sieve_access, `active` = :active WHERE `id` = :id"); $stmt->execute(array( @@ -161,6 +171,8 @@ function app_passwd($_action, $_data = null) { ':smtp_access' => $smtp_access, ':eas_access' => $eas_access, ':dav_access' => $dav_access, + ':pop3_access' => $pop3_access, + ':sieve_access' => $sieve_access, ':active' => $active, ':id' => $id )); diff --git a/data/web/inc/init_db.inc.php b/data/web/inc/init_db.inc.php index f3aada9ad..395ce2e1b 100644 --- a/data/web/inc/init_db.inc.php +++ b/data/web/inc/init_db.inc.php @@ -3,7 +3,7 @@ function init_db_schema() { try { global $pdo; - $db_version = "28102021_1600"; + $db_version = "29102021_0620"; $stmt = $pdo->query("SHOW TABLES LIKE 'versions'"); $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC)); @@ -368,6 +368,8 @@ function init_db_schema() { "smtp_access" => "TINYINT(1) NOT NULL DEFAULT '1'", "dav_access" => "TINYINT(1) NOT NULL DEFAULT '1'", "eas_access" => "TINYINT(1) NOT NULL DEFAULT '1'", + "pop3_access" => "TINYINT(1) NOT NULL DEFAULT '1'", + "sieve_access" => "TINYINT(1) NOT NULL DEFAULT '1'", "active" => "TINYINT(1) NOT NULL DEFAULT '1'" ), "keys" => array( diff --git a/data/web/js/site/user.js b/data/web/js/site/user.js index 62d6e7891..f37ae7473 100644 --- a/data/web/js/site/user.js +++ b/data/web/js/site/user.js @@ -277,7 +277,9 @@ jQuery(function($){ if (item.imap_access == 1) { item.protocols.push("IMAP"); } if (item.smtp_access == 1) { item.protocols.push("SMTP"); } if (item.eas_access == 1) { item.protocols.push("EAS/ActiveSync"); } - if (item.dav_access == 1) { item.protocols.push("DAV"); } + if (item.dav_access == 1) { item.protocols.push("DAV"); } + if (item.pop3_access == 1) { item.protocols.push("POP3"); } + if (item.sieve_access == 1) { item.protocols.push("Sieve"); } item.protocols = item.protocols.join(" ") if (acl_data.app_passwds === 1) { item.action = '
    ' + diff --git a/data/web/templates/edit/app-passwd.twig b/data/web/templates/edit/app-passwd.twig index d7bb617a2..046a34f52 100644 --- a/data/web/templates/edit/app-passwd.twig +++ b/data/web/templates/edit/app-passwd.twig @@ -39,6 +39,8 @@ + +
    diff --git a/data/web/templates/modals/user.twig b/data/web/templates/modals/user.twig index 130658390..6de779b90 100644 --- a/data/web/templates/modals/user.twig +++ b/data/web/templates/modals/user.twig @@ -221,6 +221,8 @@ + +
    From e391b054d3bbdf52a3e6cfe0e31a2b65b88349ee Mon Sep 17 00:00:00 2001 From: andryyy Date: Fri, 29 Oct 2021 06:49:32 +0200 Subject: [PATCH 11/11] [Web] Remove service chevrons --- data/web/js/site/debug.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/data/web/js/site/debug.js b/data/web/js/site/debug.js index ba08248f4..8f2aa6639 100644 --- a/data/web/js/site/debug.js +++ b/data/web/js/site/debug.js @@ -707,9 +707,7 @@ jQuery(function($){ $.each(data, function (i, item) { if (item === null) { return true; } item.username = escapeHtml(item.username); - if (item.service == "smtp") { item.service = '
    ' + item.service.toUpperCase() + '
    '; } - else if (item.service == "imap") { item.service = '
    ' + item.service.toUpperCase() + '
    '; } - else { item.service = '
    ' + item.service.toUpperCase() + '
    '; } + item.service = '
    ' + item.service.toUpperCase() + '
    '; }); } else if (table == 'general_syslog') { $.each(data, function (i, item) {