diff --git a/.gitignore b/.gitignore index 624e1c06..5c6cd161 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ data/conf/nginx/*.custom data/conf/nginx/*.bak data/conf/dovecot/acl_anyone data/conf/dovecot/mail_plugins* +data/conf/dovecot/sogo-sso.conf data/conf/dovecot/extra.conf data/conf/rspamd/custom/* data/conf/portainer/ diff --git a/data/Dockerfiles/dovecot/docker-entrypoint.sh b/data/Dockerfiles/dovecot/docker-entrypoint.sh index 0589579d..179ffb65 100755 --- a/data/Dockerfiles/dovecot/docker-entrypoint.sh +++ b/data/Dockerfiles/dovecot/docker-entrypoint.sh @@ -118,6 +118,17 @@ default_pass_scheme = SSHA256 password_query = SELECT password FROM mailbox WHERE active = '1' AND username = '%u' AND domain IN (SELECT domain FROM domain WHERE domain='%d' AND active='1') AND JSON_EXTRACT(attributes, '$.force_pw_update') NOT LIKE '%%1%%' EOF +if [[ "${ALLOW_ADMIN_EMAIL_LOGIN}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then + cat < /usr/local/etc/dovecot/sogo-sso.conf +passdb { + driver = static + args = password= allow_real_nets=${IPV4_NETWORK}.248/32 +} +EOF +else + rm -f /usr/local/etc/dovecot/sogo-sso.conf +fi + # Create global sieve_after script cat /usr/local/etc/dovecot/sieve_after > /var/vmail/sieve/global.sieve diff --git a/data/conf/dovecot/dovecot.conf b/data/conf/dovecot/dovecot.conf index 80422599..f28f9b5c 100644 --- a/data/conf/dovecot/dovecot.conf +++ b/data/conf/dovecot/dovecot.conf @@ -389,4 +389,5 @@ auth_cache_negative_ttl = 0 auth_cache_ttl = 30 s auth_cache_size = 2 M !include_try /usr/local/etc/dovecot/extra.conf +!include_try /usr/local/etc/dovecot/sogo-sso.conf default_client_limit = 10400 diff --git a/data/conf/nginx/site.conf b/data/conf/nginx/site.conf index 8b8959d5..c19310ae 100644 --- a/data/conf/nginx/site.conf +++ b/data/conf/nginx/site.conf @@ -164,6 +164,17 @@ server { client_max_body_size 0; } + # auth_request endpoint if ALLOW_ADMIN_EMAIL_LOGIN is set + location /sogo-auth-verify { + internal; + proxy_set_header X-Original-URI $request_uri; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $http_host; + proxy_set_header Content-Length ""; + proxy_pass http://127.0.0.1:80/sogo-auth; + proxy_pass_request_body off; + } + location ^~ /SOGo { include /etc/nginx/conf.d/sogo.active; proxy_set_header X-Real-IP $remote_addr; diff --git a/data/conf/nginx/templates/sogo.auth_request.template.sh b/data/conf/nginx/templates/sogo.auth_request.template.sh new file mode 100644 index 00000000..ae1a3879 --- /dev/null +++ b/data/conf/nginx/templates/sogo.auth_request.template.sh @@ -0,0 +1,6 @@ +if printf "%s\n" "${ALLOW_ADMIN_EMAIL_LOGIN}" | grep -E '^([yY][eE][sS]|[yY])+$' >/dev/null; then + echo 'auth_request /sogo-auth-verify; +auth_request_set $user $upstream_http_x_username; +proxy_set_header x-webobjects-remote-user $user; +' +fi diff --git a/data/conf/sogo/sogo.conf b/data/conf/sogo/sogo.conf index aa1a86ec..a8befc2b 100644 --- a/data/conf/sogo/sogo.conf +++ b/data/conf/sogo/sogo.conf @@ -83,4 +83,6 @@ //SOGoUIxDebugEnabled = YES; //WODontZipResponse = YES; WOLogFile = "/dev/sogo_log"; + + SOGoTrustProxyAuthentication = YES; } diff --git a/data/web/js/site/mailbox.js b/data/web/js/site/mailbox.js index 00a815e6..eb04590a 100644 --- a/data/web/js/site/mailbox.js +++ b/data/web/js/site/mailbox.js @@ -1,990 +1,993 @@ -$(document).ready(function() { - acl_data = JSON.parse(acl); - FooTable.domainFilter = FooTable.Filtering.extend({ - construct: function(instance){ - this._super(instance); - var domain_list = []; - $.ajax({ - dataType: 'json', - url: '/api/v1/get/domain/all', - jsonp: false, - async: true, - error: function () { - domain_list.push('Cannot read domain list'); - }, - success: function (data) { - $.each(data, function (i, item) { - domain_list.push(item.domain_name); - }); - } - }); - this.domains = domain_list; - this.def = 'All Domains'; - this.$domain = null; - }, - $create: function(){ - this._super(); - var self = this, - $form_grp = $('
', {'class': 'form-group'}) - .append($('
'; - item.chkbox = ''; - }); - } - }), - "paging": { - "enabled": true, - "limit": 5, - "size": pagination_size - }, - "state": { - "enabled": true - }, - "filtering": { - "enabled": true, - "delay": 100, - "position": "left", - "connectors": false, - "placeholder": lang.filter_table - }, - "sorting": { - "enabled": true - }, - "on": { - "ready.ft.table": function(e, ft){ - table_mailbox_ready(ft, 'aliasdomain_table'); - } - } - }); - } - - function draw_sync_job_table() { - ft_syncjob_table = FooTable.init('#sync_job_table', { - "columns": [ - {"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":"user2","title":lang.owner}, - {"name":"server_w_port","title":"Server","breakpoints":"xs","style":{"word-break":"break-all"}}, - {"name":"exclude","title":lang.excludes,"breakpoints":"all"}, - {"name":"mins_interval","title":lang.mins_interval,"breakpoints":"all"}, - {"name":"last_run","title":lang.last_run,"breakpoints":"sm"}, - {"name":"log","title":"Log"}, - {"name":"active","filterable": false,"style":{"maxWidth":"70px","width":"70px"},"title":lang.active}, - {"name":"is_running","filterable": false,"style":{"maxWidth":"120px","width":"100px"},"title":lang.status}, - {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"} - ], - "empty": lang.empty, - "rows": $.ajax({ - dataType: 'json', - url: '/api/v1/get/syncjobs/all/no_log', - jsonp: false, - error: function () { - console.log('Cannot draw sync job table'); - }, - success: function (data) { - $.each(data, function (i, item) { - item.log = 'Open logs' - item.user2 = escapeHtml(item.user2); - if (!item.exclude > 0) { - item.exclude = '-'; - } else { - item.exclude = '' + item.exclude + ''; - } - item.server_w_port = escapeHtml(item.user1) + '@' + item.host1 + ':' + item.port1; - item.action = '
' + - ' ' + lang.edit + '' + - ' ' + lang.remove + '' + - '
'; - item.chkbox = ''; - if (item.is_running == 1) { - item.is_running = '' + lang.running + ''; - } else { - item.is_running = '' + lang.waiting + ''; - } - if (!item.last_run > 0) { - item.last_run = lang.waiting; - } - }); - } - }), - "paging": { - "enabled": true, - "limit": 5, - "size": pagination_size - }, - "state": { - "enabled": true - }, - "filtering": { - "enabled": true, - "delay": 100, - "position": "left", - "connectors": false, - "placeholder": lang.filter_table - }, - "sorting": { - "enabled": true - }, - "on": { - "ready.ft.table": function(e, ft){ - table_mailbox_ready(ft, 'sync_job_table'); - } - } - }); - } - - function draw_filter_table() { - ft_filter_table = FooTable.init('#filter_table', { - "columns": [ - {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"}, - {"name":"id","title":"ID","style":{"maxWidth":"60px","width":"60px","text-align":"center"}}, - {"name":"active","style":{"maxWidth":"80px","width":"80px"},"title":lang.active}, - {"name":"filter_type","style":{"maxWidth":"80px","width":"80px"},"title":"Type"}, - {"sorted": true,"name":"username","title":lang.owner,"style":{"maxWidth":"550px","width":"350px"}}, - {"name":"script_desc","title":lang.description,"breakpoints":"xs"}, - {"name":"script_data","title":"Script","breakpoints":"all"}, - {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"} - ], - "empty": lang.empty, - "rows": $.ajax({ - dataType: 'json', - url: '/api/v1/get/filters/all', - jsonp: false, - error: function () { - console.log('Cannot draw filter table'); - }, - success: function (data) { - $.each(data, function (i, item) { - if (item.active_int == 1) { - item.active = '' + lang.active + ''; - } else { - item.active = '' + lang.inactive + ''; - } - item.script_data = '
' + escapeHtml(item.script_data) + '
' - item.filter_type = '
' + item.filter_type.charAt(0).toUpperCase() + item.filter_type.slice(1).toLowerCase() + '
' - item.action = '
' + - ' ' + lang.edit + '' + - ' ' + lang.remove + '' + - '
'; - item.chkbox = '' - }); - } - }), - "paging": { - "enabled": true, - "limit": 5, - "size": pagination_size - }, - "state": { - "enabled": true - }, - "filtering": { - "enabled": true, - "delay": 100, - "position": "left", - "connectors": false, - "placeholder": lang.filter_table - }, - "sorting": { - "enabled": true - }, - "on": { - "ready.ft.table": function(e, ft){ - table_mailbox_ready(ft, 'filter_table'); - } - } - }); - }; - - draw_domain_table(); - draw_mailbox_table(); - draw_resource_table(); - draw_alias_table(); - draw_aliasdomain_table(); - draw_sync_job_table(); - draw_filter_table(); - draw_bcc_table(); - draw_recipient_map_table(); - draw_tls_policy_table(); - draw_transport_maps_table(); - -}); +$(document).ready(function() { + acl_data = JSON.parse(acl); + FooTable.domainFilter = FooTable.Filtering.extend({ + construct: function(instance){ + this._super(instance); + var domain_list = []; + $.ajax({ + dataType: 'json', + url: '/api/v1/get/domain/all', + jsonp: false, + async: true, + error: function () { + domain_list.push('Cannot read domain list'); + }, + success: function (data) { + $.each(data, function (i, item) { + domain_list.push(item.domain_name); + }); + } + }); + this.domains = domain_list; + this.def = 'All Domains'; + this.$domain = null; + }, + $create: function(){ + this._super(); + var self = this, + $form_grp = $('
', {'class': 'form-group'}) + .append($('
'; + item.chkbox = ''; + }); + } + }), + "paging": { + "enabled": true, + "limit": 5, + "size": pagination_size + }, + "state": { + "enabled": true + }, + "filtering": { + "enabled": true, + "delay": 100, + "position": "left", + "connectors": false, + "placeholder": lang.filter_table + }, + "sorting": { + "enabled": true + }, + "on": { + "ready.ft.table": function(e, ft){ + table_mailbox_ready(ft, 'aliasdomain_table'); + } + } + }); + } + + function draw_sync_job_table() { + ft_syncjob_table = FooTable.init('#sync_job_table', { + "columns": [ + {"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":"user2","title":lang.owner}, + {"name":"server_w_port","title":"Server","breakpoints":"xs","style":{"word-break":"break-all"}}, + {"name":"exclude","title":lang.excludes,"breakpoints":"all"}, + {"name":"mins_interval","title":lang.mins_interval,"breakpoints":"all"}, + {"name":"last_run","title":lang.last_run,"breakpoints":"sm"}, + {"name":"log","title":"Log"}, + {"name":"active","filterable": false,"style":{"maxWidth":"70px","width":"70px"},"title":lang.active}, + {"name":"is_running","filterable": false,"style":{"maxWidth":"120px","width":"100px"},"title":lang.status}, + {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"} + ], + "empty": lang.empty, + "rows": $.ajax({ + dataType: 'json', + url: '/api/v1/get/syncjobs/all/no_log', + jsonp: false, + error: function () { + console.log('Cannot draw sync job table'); + }, + success: function (data) { + $.each(data, function (i, item) { + item.log = 'Open logs' + item.user2 = escapeHtml(item.user2); + if (!item.exclude > 0) { + item.exclude = '-'; + } else { + item.exclude = '' + item.exclude + ''; + } + item.server_w_port = escapeHtml(item.user1) + '@' + item.host1 + ':' + item.port1; + item.action = '
' + + ' ' + lang.edit + '' + + ' ' + lang.remove + '' + + '
'; + item.chkbox = ''; + if (item.is_running == 1) { + item.is_running = '' + lang.running + ''; + } else { + item.is_running = '' + lang.waiting + ''; + } + if (!item.last_run > 0) { + item.last_run = lang.waiting; + } + }); + } + }), + "paging": { + "enabled": true, + "limit": 5, + "size": pagination_size + }, + "state": { + "enabled": true + }, + "filtering": { + "enabled": true, + "delay": 100, + "position": "left", + "connectors": false, + "placeholder": lang.filter_table + }, + "sorting": { + "enabled": true + }, + "on": { + "ready.ft.table": function(e, ft){ + table_mailbox_ready(ft, 'sync_job_table'); + } + } + }); + } + + function draw_filter_table() { + ft_filter_table = FooTable.init('#filter_table', { + "columns": [ + {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"}, + {"name":"id","title":"ID","style":{"maxWidth":"60px","width":"60px","text-align":"center"}}, + {"name":"active","style":{"maxWidth":"80px","width":"80px"},"title":lang.active}, + {"name":"filter_type","style":{"maxWidth":"80px","width":"80px"},"title":"Type"}, + {"sorted": true,"name":"username","title":lang.owner,"style":{"maxWidth":"550px","width":"350px"}}, + {"name":"script_desc","title":lang.description,"breakpoints":"xs"}, + {"name":"script_data","title":"Script","breakpoints":"all"}, + {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"} + ], + "empty": lang.empty, + "rows": $.ajax({ + dataType: 'json', + url: '/api/v1/get/filters/all', + jsonp: false, + error: function () { + console.log('Cannot draw filter table'); + }, + success: function (data) { + $.each(data, function (i, item) { + if (item.active_int == 1) { + item.active = '' + lang.active + ''; + } else { + item.active = '' + lang.inactive + ''; + } + item.script_data = '
' + escapeHtml(item.script_data) + '
' + item.filter_type = '
' + item.filter_type.charAt(0).toUpperCase() + item.filter_type.slice(1).toLowerCase() + '
' + item.action = '
' + + ' ' + lang.edit + '' + + ' ' + lang.remove + '' + + '
'; + item.chkbox = '' + }); + } + }), + "paging": { + "enabled": true, + "limit": 5, + "size": pagination_size + }, + "state": { + "enabled": true + }, + "filtering": { + "enabled": true, + "delay": 100, + "position": "left", + "connectors": false, + "placeholder": lang.filter_table + }, + "sorting": { + "enabled": true + }, + "on": { + "ready.ft.table": function(e, ft){ + table_mailbox_ready(ft, 'filter_table'); + } + } + }); + }; + + draw_domain_table(); + draw_mailbox_table(); + draw_resource_table(); + draw_alias_table(); + draw_aliasdomain_table(); + draw_sync_job_table(); + draw_filter_table(); + draw_bcc_table(); + draw_recipient_map_table(); + draw_tls_policy_table(); + draw_transport_maps_table(); + +}); diff --git a/data/web/mailbox.php b/data/web/mailbox.php index 96c2e16d..392e9adf 100644 --- a/data/web/mailbox.php +++ b/data/web/mailbox.php @@ -348,6 +348,11 @@ $is_dual = (!empty($_SESSION["dual-login"]["username"])) ? 'true' : 'false'; echo "var role = '". $role . "';\n"; echo "var is_dual = " . $is_dual . ";\n"; echo "var pagination_size = '". $PAGINATION_SIZE . "';\n"; +$ALLOW_ADMIN_EMAIL_LOGIN = (preg_match( + "/^([yY][eE][sS]|[yY])+$/", + $_ENV["ALLOW_ADMIN_EMAIL_LOGIN"] +)) ? "true" : "false"; +echo "var ALLOW_ADMIN_EMAIL_LOGIN = " . $ALLOW_ADMIN_EMAIL_LOGIN . ";\n"; ?> /etc/nginx/conf.d/listen_plain.active && envsubst < /etc/nginx/conf.d/templates/listen_ssl.template > /etc/nginx/conf.d/listen_ssl.active && envsubst < /etc/nginx/conf.d/templates/server_name.template > /etc/nginx/conf.d/server_name.active && - envsubst < /etc/nginx/conf.d/templates/sogo.template > /etc/nginx/conf.d/sogo.active && + . /etc/nginx/conf.d/templates/sogo.auth_request.template.sh > /etc/nginx/conf.d/sogo.active && + envsubst < /etc/nginx/conf.d/templates/sogo.template >> /etc/nginx/conf.d/sogo.active && envsubst < /etc/nginx/conf.d/templates/sogo_eas.template > /etc/nginx/conf.d/sogo_eas.active && nginx -qt && until ping phpfpm -c1 > /dev/null; do sleep 1; done && @@ -274,6 +278,7 @@ services: - MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME} - IPV4_NETWORK=${IPV4_NETWORK:-172.22.1} - TZ=${TZ} + - ALLOW_ADMIN_EMAIL_LOGIN=${ALLOW_ADMIN_EMAIL_LOGIN:-n} volumes: - ./data/web:/web:ro - ./data/conf/rspamd/dynmaps:/dynmaps:ro diff --git a/generate_config.sh b/generate_config.sh index a882ec08..e6005b72 100755 --- a/generate_config.sh +++ b/generate_config.sh @@ -200,6 +200,10 @@ SOLR_HEAP=1024 USE_WATCHDOG=n +# Allow admins to log into SOGo as email user (without any password) + +ALLOW_ADMIN_EMAIL_LOGIN=n + # Send notifications by mail (no DKIM signature, sent from watchdog@MAILCOW_HOSTNAME) # Can by multiple rcpts, NO quotation marks diff --git a/update.sh b/update.sh index 17e818f9..9c18e0cc 100755 --- a/update.sh +++ b/update.sh @@ -130,6 +130,7 @@ CONFIG_ARRAY=( "ACL_ANYONE" "SOLR_HEAP" "SKIP_SOLR" + "ALLOW_ADMIN_EMAIL_LOGIN" ) sed -i '$a\' mailcow.conf