From cb700232414e97a07a0a35304a75273f69edb099 Mon Sep 17 00:00:00 2001 From: FreddleSpl0it <75116288+FreddleSpl0it@users.noreply.github.com> Date: Thu, 12 Mar 2026 13:06:16 +0100 Subject: [PATCH] [Web] Add User ACL to manage SOGo access --- data/conf/phpfpm/crons/keycloak-sync.php | 2 +- data/conf/phpfpm/crons/ldap-sync.php | 2 +- data/web/api/openapi.yaml | 14 +++--- data/web/inc/functions.acl.inc.php | 9 ++++ data/web/inc/functions.inc.php | 43 ++++++++++++++++--- data/web/inc/functions.mailbox.inc.php | 24 +++++++---- data/web/inc/init_db.inc.php | 17 ++++++-- data/web/inc/triggers.user.inc.php | 6 ++- data/web/inc/vars.inc.php | 4 +- data/web/index.php | 4 +- data/web/js/site/mailbox.js | 15 ++++--- data/web/lang/lang.de-de.json | 11 ++--- data/web/lang/lang.en-gb.json | 11 ++--- data/web/sogo-auth.php | 3 +- .../web/templates/edit/mailbox-templates.twig | 7 +-- data/web/templates/edit/mailbox.twig | 8 ++-- data/web/templates/modals/mailbox.twig | 13 +++--- data/web/templates/user/tab-user-auth.twig | 6 ++- 18 files changed, 135 insertions(+), 64 deletions(-) diff --git a/data/conf/phpfpm/crons/keycloak-sync.php b/data/conf/phpfpm/crons/keycloak-sync.php index f09a47d79..4fac8cc5d 100644 --- a/data/conf/phpfpm/crons/keycloak-sync.php +++ b/data/conf/phpfpm/crons/keycloak-sync.php @@ -66,7 +66,7 @@ $_SESSION['acl']['tls_policy'] = "1"; $_SESSION['acl']['quarantine_notification'] = "1"; $_SESSION['acl']['quarantine_category'] = "1"; $_SESSION['acl']['ratelimit'] = "1"; -$_SESSION['acl']['sogo_access'] = "1"; +$_SESSION['acl']['sogo_redirection'] = "1"; $_SESSION['acl']['protocol_access'] = "1"; $_SESSION['acl']['mailbox_relayhost'] = "1"; $_SESSION['acl']['unlimited_quota'] = "1"; diff --git a/data/conf/phpfpm/crons/ldap-sync.php b/data/conf/phpfpm/crons/ldap-sync.php index 32026c071..e82b8a6c3 100644 --- a/data/conf/phpfpm/crons/ldap-sync.php +++ b/data/conf/phpfpm/crons/ldap-sync.php @@ -66,7 +66,7 @@ $_SESSION['acl']['tls_policy'] = "1"; $_SESSION['acl']['quarantine_notification'] = "1"; $_SESSION['acl']['quarantine_category'] = "1"; $_SESSION['acl']['ratelimit'] = "1"; -$_SESSION['acl']['sogo_access'] = "1"; +$_SESSION['acl']['sogo_redirection'] = "1"; $_SESSION['acl']['protocol_access'] = "1"; $_SESSION['acl']['mailbox_relayhost'] = "1"; $_SESSION['acl']['unlimited_quota'] = "1"; diff --git a/data/web/api/openapi.yaml b/data/web/api/openapi.yaml index cf54f6add..52fd8b42f 100644 --- a/data/web/api/openapi.yaml +++ b/data/web/api/openapi.yaml @@ -754,7 +754,7 @@ paths: - syncjobs - quarantine - login_as - - sogo_access + - sogo_redirection - app_passwds - bcc_maps - pushover @@ -807,7 +807,7 @@ paths: - syncjobs - quarantine - login_as - - sogo_access + - sogo_redirection - app_passwds - bcc_maps - pushover @@ -3423,7 +3423,7 @@ paths: - info@domain2.tld - domain3.tld - "*" - sogo_access: "1" + sogo_redirection: "1" username: - info@domain.tld tags: ["tag3", "tag4"] @@ -3474,7 +3474,7 @@ paths: - info@domain2.tld - domain3.tld - "*" - sogo_access: "1" + sogo_redirection: "1" tags: ["tag3", "tag4"] items: - info@domain.tld @@ -3506,7 +3506,7 @@ paths: sender_acl: description: list of allowed send from addresses type: object - sogo_access: + sogo_redirection: description: is access to SOGo webmail active or not type: boolean type: object @@ -4883,7 +4883,7 @@ paths: force_pw_update: "0" mailbox_format: "maildir:" quarantine_notification: never - sogo_access: "1" + sogo_redirection: "1" tls_enforce_in: "0" tls_enforce_out: "0" domain: doman3.tld @@ -5807,7 +5807,7 @@ paths: force_pw_update: "0" mailbox_format: "maildir:" quarantine_notification: never - sogo_access: "1" + sogo_redirection: "1" tls_enforce_in: "0" tls_enforce_out: "0" custom_attributes: {} diff --git a/data/web/inc/functions.acl.inc.php b/data/web/inc/functions.acl.inc.php index dde9b1236..cc7ee3428 100644 --- a/data/web/inc/functions.acl.inc.php +++ b/data/web/inc/functions.acl.inc.php @@ -48,7 +48,12 @@ function acl($_action, $_scope = null, $_data = null, $_extra = null) { ); continue; } + $sogo_acl_changed = false; foreach ($set_acls as $set_acl_key => $set_acl_val) { + // Track if sogo_access ACL changed + if ($set_acl_key == 'sogo_access' && $is_now[$set_acl_key] != $set_acl_val) { + $sogo_acl_changed = true; + } $stmt = $pdo->prepare("UPDATE `user_acl` SET " . $set_acl_key . " = " . intval($set_acl_val) . " WHERE `username` = :username"); $stmt->execute(array( @@ -60,6 +65,10 @@ function acl($_action, $_scope = null, $_data = null, $_extra = null) { 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), 'msg' => array('acl_saved', $username) ); + // Update SOGo static view if sogo_access ACL changed + if ($sogo_acl_changed) { + update_sogo_static_view($username); + } } break; case 'domainadmin': diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php index 89f14b574..5c21b9721 100644 --- a/data/web/inc/functions.inc.php +++ b/data/web/inc/functions.inc.php @@ -940,8 +940,12 @@ function update_sogo_static_view($mailbox = null) { $mailbox_exists = false; if ($mailbox !== null) { - // Check if the mailbox exists - $stmt = $pdo->prepare("SELECT username FROM mailbox WHERE username = :mailbox AND active = '1'"); + // Check if the mailbox exists and should have SOGo access + $stmt = $pdo->prepare("SELECT m.username FROM mailbox m + LEFT JOIN user_acl u ON m.username = u.username + WHERE m.username = :mailbox + AND m.active = '1' + AND (u.sogo_access IS NULL OR u.sogo_access = 1)"); $stmt->execute(array(':mailbox' => $mailbox)); $row = $stmt->fetch(PDO::FETCH_ASSOC); if ($row){ @@ -976,8 +980,10 @@ function update_sogo_static_view($mailbox = null) { LEFT OUTER JOIN grouped_mail_aliases ga ON ga.username REGEXP CONCAT('(^|,)', mailbox.username, '($|,)') LEFT OUTER JOIN grouped_domain_alias_address gda ON gda.username = mailbox.username LEFT OUTER JOIN grouped_sender_acl_external external_acl ON external_acl.username = mailbox.username + LEFT OUTER JOIN user_acl ON user_acl.username = mailbox.username WHERE mailbox.active = '1' + AND (user_acl.sogo_access IS NULL OR user_acl.sogo_access = 1) $subquery ON DUPLICATE KEY UPDATE `domain` = VALUES(`domain`), @@ -1005,7 +1011,27 @@ function update_sogo_static_view($mailbox = null) { )); } - $stmt = $pdo->query("DELETE FROM _sogo_static_view WHERE `c_uid` NOT IN (SELECT `username` FROM `mailbox` WHERE `active` = '1');"); + if ($mailbox_exists) { + // For single mailbox update, only delete this specific user + $stmt = $pdo->prepare("DELETE FROM _sogo_static_view + WHERE `c_uid` = :mailbox + AND `c_uid` NOT IN ( + SELECT m.`username` FROM `mailbox` m + LEFT JOIN `user_acl` u ON m.`username` = u.`username` + WHERE m.`active` = '1' + AND m.`username` = :mailbox2 + AND (u.`sogo_access` IS NULL OR u.`sogo_access` = 1) + )"); + $stmt->execute(array(':mailbox' => $mailbox, ':mailbox2' => $mailbox)); + } else { + // Full cleanup for all users + $stmt = $pdo->query("DELETE FROM _sogo_static_view WHERE `c_uid` NOT IN ( + SELECT m.`username` FROM `mailbox` m + LEFT JOIN `user_acl` u ON m.`username` = u.`username` + WHERE m.`active` = '1' + AND (u.`sogo_access` IS NULL OR u.`sogo_access` = 1) + );"); + } flush_memcached(); } @@ -3490,9 +3516,14 @@ function set_user_loggedin_session($user) { session_regenerate_id(true); $_SESSION['mailcow_cc_username'] = $user; $_SESSION['mailcow_cc_role'] = 'user'; - $sogo_sso_pass = file_get_contents("/etc/sogo-sso/sogo-sso.pass"); - $_SESSION['sogo-sso-user-allowed'][] = $user; - $_SESSION['sogo-sso-pass'] = $sogo_sso_pass; + + acl('to_session'); + if (hasACLAccess("sogo_access")) { + $sogo_sso_pass = file_get_contents("/etc/sogo-sso/sogo-sso.pass"); + $_SESSION['sogo-sso-user-allowed'][] = $user; + $_SESSION['sogo-sso-pass'] = $sogo_sso_pass; + } + unset($_SESSION['pending_mailcow_cc_username']); unset($_SESSION['pending_mailcow_cc_role']); unset($_SESSION['pending_tfa_methods']); diff --git a/data/web/inc/functions.mailbox.inc.php b/data/web/inc/functions.mailbox.inc.php index a002ab41b..5c9c67b73 100644 --- a/data/web/inc/functions.mailbox.inc.php +++ b/data/web/inc/functions.mailbox.inc.php @@ -1101,7 +1101,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { $force_tfa = (isset($_data['force_tfa'])) ? intval($_data['force_tfa']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_tfa']); $tls_enforce_in = (isset($_data['tls_enforce_in'])) ? intval($_data['tls_enforce_in']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_in']); $tls_enforce_out = (isset($_data['tls_enforce_out'])) ? intval($_data['tls_enforce_out']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_out']); - $sogo_access = (isset($_data['sogo_access'])) ? intval($_data['sogo_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['sogo_access']); + $sogo_redirection = (isset($_data['sogo_redirection'])) ? intval($_data['sogo_redirection']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['sogo_redirection']); $imap_access = (isset($_data['imap_access'])) ? intval($_data['imap_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['imap_access']); $pop3_access = (isset($_data['pop3_access'])) ? intval($_data['pop3_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['pop3_access']); $smtp_access = (isset($_data['smtp_access'])) ? intval($_data['smtp_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['smtp_access']); @@ -1123,7 +1123,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { 'force_tfa' => strval($force_tfa), 'tls_enforce_in' => strval($tls_enforce_in), 'tls_enforce_out' => strval($tls_enforce_out), - 'sogo_access' => strval($sogo_access), + 'sogo_redirection' => strval($sogo_redirection), 'imap_access' => strval($imap_access), 'pop3_access' => strval($pop3_access), 'smtp_access' => strval($smtp_access), @@ -1314,6 +1314,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { $_data['syncjobs'] = (in_array('syncjobs', $_data['acl'])) ? 1 : 0; $_data['eas_reset'] = (in_array('eas_reset', $_data['acl'])) ? 1 : 0; $_data['sogo_profile_reset'] = (in_array('sogo_profile_reset', $_data['acl'])) ? 1 : 0; + $_data['sogo_access'] = (in_array('sogo_access', $_data['acl'])) ? 1 : 0; $_data['pushover'] = (in_array('pushover', $_data['acl'])) ? 1 : 0; $_data['quarantine'] = (in_array('quarantine', $_data['acl'])) ? 1 : 0; $_data['quarantine_attachments'] = (in_array('quarantine_attachments', $_data['acl'])) ? 1 : 0; @@ -1330,6 +1331,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { $_data['syncjobs'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_syncjobs']); $_data['eas_reset'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_eas_reset']); $_data['sogo_profile_reset'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_sogo_profile_reset']); + $_data['sogo_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_sogo_access']); $_data['pushover'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_pushover']); $_data['quarantine'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_quarantine']); $_data['quarantine_attachments'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_quarantine_attachments']); @@ -1341,9 +1343,9 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { try { $stmt = $pdo->prepare("INSERT INTO `user_acl` - (`username`, `spam_alias`, `tls_policy`, `spam_score`, `spam_policy`, `delimiter_action`, `syncjobs`, `eas_reset`, `sogo_profile_reset`, + (`username`, `spam_alias`, `tls_policy`, `spam_score`, `spam_policy`, `delimiter_action`, `syncjobs`, `eas_reset`, `sogo_profile_reset`, `sogo_access`, `pushover`, `quarantine`, `quarantine_attachments`, `quarantine_notification`, `quarantine_category`, `app_passwds`, `pw_reset`) - VALUES (:username, :spam_alias, :tls_policy, :spam_score, :spam_policy, :delimiter_action, :syncjobs, :eas_reset, :sogo_profile_reset, + VALUES (:username, :spam_alias, :tls_policy, :spam_score, :spam_policy, :delimiter_action, :syncjobs, :eas_reset, :sogo_profile_reset, :sogo_access, :pushover, :quarantine, :quarantine_attachments, :quarantine_notification, :quarantine_category, :app_passwds, :pw_reset) "); $stmt->execute(array( ':username' => $username, @@ -1355,6 +1357,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { ':syncjobs' => $_data['syncjobs'], ':eas_reset' => $_data['eas_reset'], ':sogo_profile_reset' => $_data['sogo_profile_reset'], + ':sogo_access' => $_data['sogo_access'], ':pushover' => $_data['pushover'], ':quarantine' => $_data['quarantine'], ':quarantine_attachments' => $_data['quarantine_attachments'], @@ -1735,7 +1738,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { $attr["rl_value"] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : ""; $attr["force_pw_update"] = isset($_data['force_pw_update']) ? intval($_data['force_pw_update']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update']); $attr["force_tfa"] = isset($_data['force_tfa']) ? intval($_data['force_tfa']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_tfa']); - $attr["sogo_access"] = isset($_data['sogo_access']) ? intval($_data['sogo_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['sogo_access']); + $attr["sogo_redirection"] = isset($_data['sogo_redirection']) ? intval($_data['sogo_redirection']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['sogo_redirection']); $attr["active"] = isset($_data['active']) ? intval($_data['active']) : 1; $attr["tls_enforce_in"] = isset($_data['tls_enforce_in']) ? intval($_data['tls_enforce_in']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_in']); $attr["tls_enforce_out"] = isset($_data['tls_enforce_out']) ? intval($_data['tls_enforce_out']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_out']); @@ -1766,6 +1769,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { $attr['acl_syncjobs'] = (in_array('syncjobs', $_data['acl'])) ? 1 : 0; $attr['acl_eas_reset'] = (in_array('eas_reset', $_data['acl'])) ? 1 : 0; $attr['acl_sogo_profile_reset'] = (in_array('sogo_profile_reset', $_data['acl'])) ? 1 : 0; + $attr['acl_sogo_access'] = (in_array('sogo_access', $_data['acl'])) ? 1 : 0; $attr['acl_pushover'] = (in_array('pushover', $_data['acl'])) ? 1 : 0; $attr['acl_quarantine'] = (in_array('quarantine', $_data['acl'])) ? 1 : 0; $attr['acl_quarantine_attachments'] = (in_array('quarantine_attachments', $_data['acl'])) ? 1 : 0; @@ -1783,6 +1787,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { $attr['acl_syncjobs'] = 0; $attr['acl_eas_reset'] = 0; $attr['acl_sogo_profile_reset'] = 0; + $attr['acl_sogo_access'] = 0; $attr['acl_pushover'] = 0; $attr['acl_quarantine'] = 0; $attr['acl_quarantine_attachments'] = 0; @@ -3103,7 +3108,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active']; (int)$force_pw_update = (isset($_data['force_pw_update'])) ? intval($_data['force_pw_update']) : intval($is_now['attributes']['force_pw_update']); (int)$force_tfa = (isset($_data['force_tfa'])) ? intval($_data['force_tfa']) : intval($is_now['attributes']['force_tfa']); - (int)$sogo_access = (isset($_data['sogo_access']) && hasACLAccess("sogo_access")) ? intval($_data['sogo_access']) : intval($is_now['attributes']['sogo_access']); + (int)$sogo_redirection = (isset($_data['sogo_redirection'])) ? intval($_data['sogo_redirection']) : intval($is_now['attributes']['sogo_redirection']); (int)$imap_access = (isset($_data['imap_access']) && hasACLAccess("protocol_access")) ? intval($_data['imap_access']) : intval($is_now['attributes']['imap_access']); (int)$pop3_access = (isset($_data['pop3_access']) && hasACLAccess("protocol_access")) ? intval($_data['pop3_access']) : intval($is_now['attributes']['pop3_access']); (int)$smtp_access = (isset($_data['smtp_access']) && hasACLAccess("protocol_access")) ? intval($_data['smtp_access']) : intval($is_now['attributes']['smtp_access']); @@ -3399,7 +3404,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { `authsource` = :authsource, `attributes` = JSON_SET(`attributes`, '$.force_pw_update', :force_pw_update), `attributes` = JSON_SET(`attributes`, '$.force_tfa', :force_tfa), - `attributes` = JSON_SET(`attributes`, '$.sogo_access', :sogo_access), + `attributes` = JSON_SET(`attributes`, '$.sogo_redirection', :sogo_redirection), `attributes` = JSON_SET(`attributes`, '$.imap_access', :imap_access), `attributes` = JSON_SET(`attributes`, '$.sieve_access', :sieve_access), `attributes` = JSON_SET(`attributes`, '$.pop3_access', :pop3_access), @@ -3417,7 +3422,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { ':attribute_hash' => $attribute_hash, ':force_pw_update' => $force_pw_update, ':force_tfa' => $force_tfa, - ':sogo_access' => $sogo_access, + ':sogo_redirection' => $sogo_redirection, ':imap_access' => $imap_access, ':pop3_access' => $pop3_access, ':sieve_access' => $sieve_access, @@ -3789,7 +3794,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { $attr["rl_frame"] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : $is_now['rl_frame']; $attr["rl_value"] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : $is_now['rl_value']; $attr["force_pw_update"] = isset($_data['force_pw_update']) ? intval($_data['force_pw_update']) : $is_now['force_pw_update']; - $attr["sogo_access"] = isset($_data['sogo_access']) ? intval($_data['sogo_access']) : $is_now['sogo_access']; + $attr["sogo_redirection"] = isset($_data['sogo_redirection']) ? intval($_data['sogo_redirection']) : $is_now['sogo_redirection']; $attr["active"] = isset($_data['active']) ? intval($_data['active']) : $is_now['active']; $attr["tls_enforce_in"] = isset($_data['tls_enforce_in']) ? intval($_data['tls_enforce_in']) : $is_now['tls_enforce_in']; $attr["tls_enforce_out"] = isset($_data['tls_enforce_out']) ? intval($_data['tls_enforce_out']) : $is_now['tls_enforce_out']; @@ -3817,6 +3822,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { $attr['acl_syncjobs'] = (in_array('syncjobs', $_data['acl'])) ? 1 : 0; $attr['acl_eas_reset'] = (in_array('eas_reset', $_data['acl'])) ? 1 : 0; $attr['acl_sogo_profile_reset'] = (in_array('sogo_profile_reset', $_data['acl'])) ? 1 : 0; + $attr['acl_sogo_access'] = (in_array('sogo_access', $_data['acl'])) ? 1 : 0; $attr['acl_pushover'] = (in_array('pushover', $_data['acl'])) ? 1 : 0; $attr['acl_quarantine'] = (in_array('quarantine', $_data['acl'])) ? 1 : 0; $attr['acl_quarantine_attachments'] = (in_array('quarantine_attachments', $_data['acl'])) ? 1 : 0; diff --git a/data/web/inc/init_db.inc.php b/data/web/inc/init_db.inc.php index 72018a6bc..5d1b6e9d1 100644 --- a/data/web/inc/init_db.inc.php +++ b/data/web/inc/init_db.inc.php @@ -4,7 +4,7 @@ function init_db_schema() try { global $pdo; - $db_version = "19022026_1220"; + $db_version = "12032026_1300"; $stmt = $pdo->query("SHOW TABLES LIKE 'versions'"); $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC)); @@ -506,6 +506,7 @@ function init_db_schema() "syncjobs" => "TINYINT(1) NOT NULL DEFAULT '0'", "eas_reset" => "TINYINT(1) NOT NULL DEFAULT '1'", "sogo_profile_reset" => "TINYINT(1) NOT NULL DEFAULT '0'", + "sogo_access" => "TINYINT(1) NOT NULL DEFAULT '1'", "pushover" => "TINYINT(1) NOT NULL DEFAULT '1'", // quarantine is for quarantine actions, todo: rename "quarantine" => "TINYINT(1) NOT NULL DEFAULT '1'", @@ -705,7 +706,7 @@ function init_db_schema() "syncjobs" => "TINYINT(1) NOT NULL DEFAULT '1'", "quarantine" => "TINYINT(1) NOT NULL DEFAULT '1'", "login_as" => "TINYINT(1) NOT NULL DEFAULT '1'", - "sogo_access" => "TINYINT(1) NOT NULL DEFAULT '1'", + "sogo_redirection" => "TINYINT(1) NOT NULL DEFAULT '1'", "app_passwds" => "TINYINT(1) NOT NULL DEFAULT '1'", "bcc_maps" => "TINYINT(1) NOT NULL DEFAULT '1'", "pushover" => "TINYINT(1) NOT NULL DEFAULT '0'", @@ -1397,7 +1398,10 @@ function init_db_schema() $pdo->query("UPDATE `admin` SET `attributes` = JSON_SET(`attributes`, '$.force_tfa', \"0\") WHERE JSON_VALUE(`attributes`, '$.force_tfa') IS NULL;"); $pdo->query("UPDATE `admin` SET `attributes` = JSON_SET(`attributes`, '$.force_pw_update', \"0\") WHERE JSON_VALUE(`attributes`, '$.force_pw_update') IS NULL;"); $pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.sieve_access', \"1\") WHERE JSON_VALUE(`attributes`, '$.sieve_access') IS NULL;"); - $pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.sogo_access', \"1\") WHERE JSON_VALUE(`attributes`, '$.sogo_access') IS NULL;"); + // Migrate sogo_access attribute to sogo_redirection + $pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.sogo_redirection', JSON_VALUE(`attributes`, '$.sogo_access')) WHERE JSON_VALUE(`attributes`, '$.sogo_access') IS NOT NULL;"); + $pdo->query("UPDATE `mailbox` SET `attributes` = JSON_REMOVE(`attributes`, '$.sogo_access') WHERE JSON_VALUE(`attributes`, '$.sogo_access') IS NOT NULL;"); + $pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.sogo_redirection', \"1\") WHERE JSON_VALUE(`attributes`, '$.sogo_redirection') IS NULL;"); $pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.imap_access', \"1\") WHERE JSON_VALUE(`attributes`, '$.imap_access') IS NULL;"); $pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.pop3_access', \"1\") WHERE JSON_VALUE(`attributes`, '$.pop3_access') IS NULL;"); $pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.smtp_access', \"1\") WHERE JSON_VALUE(`attributes`, '$.smtp_access') IS NULL;"); @@ -1421,6 +1425,10 @@ function init_db_schema() // Fix domain_admins $pdo->query("DELETE FROM `domain_admins` WHERE `domain` = 'ALL';"); + // Migrate template sogo_access to sogo_redirection + $pdo->query("UPDATE `templates` SET `attributes` = JSON_SET(`attributes`, '$.sogo_redirection', JSON_VALUE(`attributes`, '$.sogo_access')) WHERE `type` = 'mailbox' AND JSON_VALUE(`attributes`, '$.sogo_access') IS NOT NULL;"); + $pdo->query("UPDATE `templates` SET `attributes` = JSON_REMOVE(`attributes`, '$.sogo_access') WHERE `type` = 'mailbox' AND JSON_VALUE(`attributes`, '$.sogo_access') IS NOT NULL;"); + // add default templates $default_domain_template = array( "template" => "Default", @@ -1456,7 +1464,7 @@ function init_db_schema() "rl_value" => "", "force_pw_update" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['force_pw_update']), "force_tfa" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['force_tfa']), - "sogo_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['sogo_access']), + "sogo_redirection" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['sogo_redirection']), "active" => 1, "tls_enforce_in" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['tls_enforce_in']), "tls_enforce_out" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['tls_enforce_out']), @@ -1472,6 +1480,7 @@ function init_db_schema() "acl_syncjobs" => 0, "acl_eas_reset" => 1, "acl_sogo_profile_reset" => 0, + "acl_sogo_access" => 1, "acl_pushover" => 1, "acl_quarantine" => 1, "acl_quarantine_attachments" => 1, diff --git a/data/web/inc/triggers.user.inc.php b/data/web/inc/triggers.user.inc.php index 5dcde0b18..299c51390 100644 --- a/data/web/inc/triggers.user.inc.php +++ b/data/web/inc/triggers.user.inc.php @@ -81,8 +81,9 @@ if (isset($_POST["verify_tfa_login"])) { header("Location: /"); die(); } - if (intval($user_details['attributes']['sogo_access']) == 1 && + if (intval($user_details['attributes']['sogo_redirection']) == 1 && intval($user_details['attributes']['force_pw_update']) != 1 && + hasACLAccess('sogo_access') && getenv('SKIP_SOGO') != "y" && !$is_dual) { header("Location: /SOGo/so/"); @@ -161,8 +162,9 @@ if (isset($_POST["login_user"]) && isset($_POST["pass_user"])) { header("Location: /"); die(); } - if (intval($user_details['attributes']['sogo_access']) == 1 && + if (intval($user_details['attributes']['sogo_redirection']) == 1 && intval($user_details['attributes']['force_pw_update']) != 1 && + hasACLAccess('sogo_access') && getenv('SKIP_SOGO') != "y" && !$is_dual) { header("Location: /SOGo/so/"); diff --git a/data/web/inc/vars.inc.php b/data/web/inc/vars.inc.php index 2f4a4b076..27a195be4 100644 --- a/data/web/inc/vars.inc.php +++ b/data/web/inc/vars.inc.php @@ -196,8 +196,8 @@ $MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update'] = false; // Force 2FA enrollment at next login $MAILBOX_DEFAULT_ATTRIBUTES['force_tfa'] = false; -// Enable SOGo access - Users will be redirected to SOGo after login (set to false to disable redirect by default) -$MAILBOX_DEFAULT_ATTRIBUTES['sogo_access'] = true; +// Enable SOGo redirection - Users will be redirected to SOGo after login (set to false to disable redirect by default) +$MAILBOX_DEFAULT_ATTRIBUTES['sogo_redirection'] = true; // How to handle tagged emails // none - No special handling diff --git a/data/web/index.php b/data/web/index.php index b037c14f1..cb6219348 100644 --- a/data/web/index.php +++ b/data/web/index.php @@ -12,7 +12,9 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == ' if (empty($_SESSION['pending_tfa_setup']) && empty($_SESSION['pending_pw_update'])) { $user_details = mailbox("get", "mailbox_details", $_SESSION['mailcow_cc_username']); $is_dual = (!empty($_SESSION["dual-login"]["username"])) ? true : false; - if (intval($user_details['attributes']['sogo_access']) == 1 && !$is_dual && getenv('SKIP_SOGO') != "y") { + if (intval($user_details['attributes']['sogo_redirection']) == 1 && + hasACLAccess('sogo_access') && + !$is_dual && getenv('SKIP_SOGO') != "y") { header("Location: /SOGo/so/"); } else { header("Location: /user"); diff --git a/data/web/js/site/mailbox.js b/data/web/js/site/mailbox.js index e8edb9940..07a215d47 100644 --- a/data/web/js/site/mailbox.js +++ b/data/web/js/site/mailbox.js @@ -385,6 +385,9 @@ $(document).ready(function() { if (template.acl_sogo_profile_reset == 1){ acl.push("sogo_profile_reset"); } + if (template.acl_sogo_access == 1){ + acl.push("sogo_access"); + } if (template.acl_pushover == 1){ acl.push("pushover"); } @@ -424,10 +427,10 @@ $(document).ready(function() { } else { $('#force_pw_update').prop('checked', false); } - if (template.sogo_access == 1){ - $('#sogo_access').prop('checked', true); + if (template.sogo_redirection == 1){ + $('#sogo_redirection').prop('checked', true); } else { - $('#sogo_access').prop('checked', false); + $('#sogo_redirection').prop('checked', false); } // load tags @@ -1241,7 +1244,7 @@ jQuery(function($){ item.attributes.sieve_access = '' + (item.attributes.sieve_access == 1 ? '1' : '0') + ''; item.attributes.eas_access = '' + (item.attributes.eas_access == 1 ? '1' : '0') + ''; item.attributes.dav_access = '' + (item.attributes.dav_access == 1 ? '1' : '0') + ''; - item.attributes.sogo_access = '' + (item.attributes.sogo_access == 1 ? '1' : '0') + ''; + item.attributes.sogo_redirection = '' + (item.attributes.sogo_redirection == 1 ? '1' : '0') + ''; if (item.attributes.quarantine_notification === 'never') { item.attributes.quarantine_notification = lang.never; } else if (item.attributes.quarantine_notification === 'hourly') { @@ -1360,8 +1363,8 @@ jQuery(function($){ defaultContent: '', }, { - title: 'SOGO', - data: 'attributes.sogo_access', + title: 'SOGO redirection', + data: 'attributes.sogo_redirection', defaultContent: '', }, { diff --git a/data/web/lang/lang.de-de.json b/data/web/lang/lang.de-de.json index 487300fe9..0324909a4 100644 --- a/data/web/lang/lang.de-de.json +++ b/data/web/lang/lang.de-de.json @@ -22,14 +22,15 @@ "ratelimit": "Rate limit", "recipient_maps": "Empfängerumschreibungen", "smtp_ip_access": "Verwalten der erlaubten Hosts für SMTP", - "sogo_access": "Verwalten des SOGo-Zugriffsrechts erlauben", + "sogo_access": "SOGo-Nutzung erlauben", "sogo_profile_reset": "SOGo-Profil zurücksetzen", "spam_alias": "Temporäre E-Mail-Aliasse", "spam_policy": "Deny/Allowlist", "spam_score": "Spam-Bewertung", "syncjobs": "Sync Jobs", "tls_policy": "Verschlüsselungsrichtlinie", - "unlimited_quota": "Unendliche Quota für Mailboxen" + "unlimited_quota": "Unendliche Quota für Mailboxen", + "sogo_redirection": "Verwalten der SOGo-Weiterleitung erlauben" }, "add": { "activate_filter_warn": "Alle anderen Filter dieses Typs werden deaktiviert, falls dieses Script aktiviert wird.", @@ -767,8 +768,6 @@ "sieve_desc": "Kurze Beschreibung", "sieve_type": "Filtertyp", "skipcrossduplicates": "Duplikate auch über Ordner hinweg überspringen (\"first come, first serve\")", - "sogo_access": "Direktes weiterleiten an SOGo", - "sogo_access_info": "Nach dem Einloggen wird der Benutzer automatisch an SOGo weitergeleitet.", "sogo_visible": "Alias in SOGo sichtbar", "sogo_visible_info": "Diese Option hat lediglich Einfluss auf Objekte, die in SOGo darstellbar sind (geteilte oder nicht-geteilte Alias-Adressen mit dem Ziel mindestens einer lokalen Mailbox).", "spam_alias": "Anpassen temporärer Alias-Adressen", @@ -785,7 +784,9 @@ "unchanged_if_empty": "Unverändert, wenn leer", "username": "Benutzername", "validate_save": "Validieren und speichern", - "pushover_sound": "Ton" + "pushover_sound": "Ton", + "sogo_redirection": "Direktes weiterleiten an SOGo", + "sogo_redirection_info": "Nach dem Einloggen wird der Benutzer automatisch an SOGo weitergeleitet." }, "fido2": { "confirm": "Bestätigen", diff --git a/data/web/lang/lang.en-gb.json b/data/web/lang/lang.en-gb.json index eb26e3fcf..6d054637f 100644 --- a/data/web/lang/lang.en-gb.json +++ b/data/web/lang/lang.en-gb.json @@ -22,14 +22,15 @@ "ratelimit": "Rate limit", "recipient_maps": "Recipient maps", "smtp_ip_access": "Change allowed hosts for SMTP", - "sogo_access": "Allow management of SOGo access", + "sogo_access": "Allow SOGo usage", "sogo_profile_reset": "Reset SOGo profile", "spam_alias": "Temporary aliases", "spam_policy": "Denylist/Allowlist", "spam_score": "Spam score", "syncjobs": "Sync jobs", "tls_policy": "TLS policy", - "unlimited_quota": "Unlimited quota for mailboxes" + "unlimited_quota": "Unlimited quota for mailboxes", + "sogo_redirection": "Allow management of SOGo forwarding" }, "add": { "activate_filter_warn": "All other filters will be deactivated, when active is checked.", @@ -768,8 +769,6 @@ "sieve_desc": "Short description", "sieve_type": "Filter type", "skipcrossduplicates": "Skip duplicate messages across folders (first come, first serve)", - "sogo_access": "Direct forwarding to SOGo", - "sogo_access_info": "After logging in, the user is automatically redirected to SOGo.", "sogo_visible": "Alias is visible in SOGo", "sogo_visible_info": "This option only affects objects, that can be displayed in SOGo (shared or non-shared alias addresses pointing to at least one local mailbox). If hidden, an alias will not appear as selectable sender in SOGo.", "spam_alias": "Create or change time limited alias addresses", @@ -785,7 +784,9 @@ "title": "Edit object", "unchanged_if_empty": "If unchanged leave blank", "username": "Username", - "validate_save": "Validate and save" + "validate_save": "Validate and save", + "sogo_redirection": "Direct forwarding to SOGo", + "sogo_redirection_info": "After logging in, the user is automatically redirected to SOGo." }, "fido2": { "confirm": "Confirm", diff --git a/data/web/sogo-auth.php b/data/web/sogo-auth.php index 07456a7d1..35b3a8ab7 100644 --- a/data/web/sogo-auth.php +++ b/data/web/sogo-auth.php @@ -27,7 +27,7 @@ if (isset($_SERVER['PHP_AUTH_USER'])) { } $login_check = check_login($username, $password, array('service' => $service)); - if ($login_check === 'user') { + if ($login_check === 'user' && hasACLAccess('sogo_access')) { header("X-User: $username"); header("X-Auth: Basic ".base64_encode("$username:$password")); header("X-Auth-Type: Basic"); @@ -47,6 +47,7 @@ elseif (isset($_GET['login'])) { // check permissions (if dual_login is active, deny sso when acl is not given) $login = html_entity_decode(rawurldecode($_GET["login"])); if (isset($_SESSION['mailcow_cc_role']) && + hasACLAccess('sogo_access') && (($_SESSION['acl']['login_as'] == "1" && $ALLOW_ADMIN_EMAIL_LOGIN !== 0) || ($is_dual === false && $login == $_SESSION['mailcow_cc_username']))) { if (filter_var($login, FILTER_VALIDATE_EMAIL)) { if (user_get_alias_details($login) !== false) { diff --git a/data/web/templates/edit/mailbox-templates.twig b/data/web/templates/edit/mailbox-templates.twig index ddc139586..765f47b68 100644 --- a/data/web/templates/edit/mailbox-templates.twig +++ b/data/web/templates/edit/mailbox-templates.twig @@ -8,7 +8,7 @@ - +
@@ -125,6 +125,7 @@ + @@ -169,8 +170,8 @@
- - {{ lang.edit.sogo_access_info }} + + {{ lang.edit.sogo_redirection_info }}
diff --git a/data/web/templates/edit/mailbox.twig b/data/web/templates/edit/mailbox.twig index 34e869ce1..5f5b6ffbe 100644 --- a/data/web/templates/edit/mailbox.twig +++ b/data/web/templates/edit/mailbox.twig @@ -25,7 +25,7 @@ - +
@@ -327,11 +327,11 @@
{% if not skip_sogo %} -
+
- - {{ lang.edit.sogo_access_info }} + + {{ lang.edit.sogo_redirection_info }}
diff --git a/data/web/templates/modals/mailbox.twig b/data/web/templates/modals/mailbox.twig index 924d88c8b..dadae2436 100644 --- a/data/web/templates/modals/mailbox.twig +++ b/data/web/templates/modals/mailbox.twig @@ -10,7 +10,7 @@
- + @@ -166,6 +166,7 @@ + @@ -217,8 +218,8 @@
- - {{ lang.edit.sogo_access_info }} + + {{ lang.edit.sogo_redirection_info }}
@@ -247,7 +248,7 @@ - +
@@ -416,8 +417,8 @@
- - {{ lang.edit.sogo_access_info }} + + {{ lang.edit.sogo_redirection_info }}
diff --git a/data/web/templates/user/tab-user-auth.twig b/data/web/templates/user/tab-user-auth.twig index 171545d6c..c006853c0 100644 --- a/data/web/templates/user/tab-user-auth.twig +++ b/data/web/templates/user/tab-user-auth.twig @@ -23,10 +23,14 @@ {{ lang.user.open_webmail_sso }} - {% else %} + {% elseif acl.sogo_access == 1 %} {{ lang.user.open_webmail_sso }} + {% else %} + {% endif %}