mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2024-12-14 10:52:49 +02:00
Allow an admin to login to SOGo as mailbox user
Thanks to @mhofer117 !
This commit is contained in:
commit
278ac6ce04
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
rebuild-images.sh
|
||||
data/conf/sogo/sieve.creds
|
||||
data/conf/phpfpm/sogo-sso/sogo-sso.pass
|
||||
data/conf/dovecot/dovecot-master.passwd
|
||||
data/conf/dovecot/dovecot-master.userdb
|
||||
mailcow.conf
|
||||
@ -24,6 +25,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/
|
||||
|
@ -3,7 +3,7 @@ LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ENV LC_ALL C
|
||||
ENV DOVECOT_VERSION 2.3.5
|
||||
ENV DOVECOT_VERSION 2.3.5.1
|
||||
ENV PIGEONHOLE_VERSION 0.5.5
|
||||
|
||||
RUN apt-get update && apt-get -y --no-install-recommends install \
|
||||
|
@ -127,6 +127,10 @@ if [[ $(stat -c %U /var/vmail/) != "vmail" ]] ; then chown -R vmail:vmail /var/v
|
||||
if [[ $(stat -c %U /var/vmail/_garbage) != "vmail" ]] ; then chown -R vmail:vmail /var/vmail/_garbage ; fi
|
||||
if [[ $(stat -c %U /var/attachments) != "vmail" ]] ; then chown -R vmail:vmail /var/attachments ; fi
|
||||
|
||||
# Cleanup random user maildirs
|
||||
rm -rf /var/vmail/mailcow.local/*
|
||||
|
||||
|
||||
# Create random master for SOGo sieve features
|
||||
RAND_USER=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 16 | head -n 1)
|
||||
RAND_PASS=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 24 | head -n 1)
|
||||
@ -135,6 +139,21 @@ echo ${RAND_USER}@mailcow.local:{SHA1}$(echo -n ${RAND_PASS} | sha1sum | awk '{p
|
||||
echo ${RAND_USER}@mailcow.local::5000:5000:::: > /usr/local/etc/dovecot/dovecot-master.userdb
|
||||
echo ${RAND_USER}@mailcow.local:${RAND_PASS} > /etc/sogo/sieve.creds
|
||||
|
||||
if [[ "${ALLOW_ADMIN_EMAIL_LOGIN}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
# Create random master Password for SOGo 'login as user' via proxy auth
|
||||
RAND_PASS=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 32 | head -n 1)
|
||||
echo -n ${RAND_PASS} > /etc/phpfpm/sogo-sso.pass
|
||||
cat <<EOF > /usr/local/etc/dovecot/sogo-sso.conf
|
||||
passdb {
|
||||
driver = static
|
||||
args = allow_real_nets=${IPV4_NETWORK}.248/32 password={plain}${RAND_PASS}
|
||||
}
|
||||
EOF
|
||||
else
|
||||
rm -f /usr/local/etc/dovecot/sogo-sso.pass
|
||||
rm -f /usr/local/etc/dovecot/sogo-sso.conf
|
||||
fi
|
||||
|
||||
# 401 is user dovecot
|
||||
if [[ ! -s /mail_crypt/ecprivkey.pem || ! -s /mail_crypt/ecpubkey.pem ]]; then
|
||||
openssl ecparam -name prime256v1 -genkey | openssl pkey -out /mail_crypt/ecprivkey.pem
|
||||
|
@ -31,7 +31,8 @@ RULES[2] = '-login: Disconnected \(auth failed, .+\): user=.*, method=.+, rip=([
|
||||
RULES[3] = '-login: Aborted login \(tried to use disallowed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
|
||||
RULES[4] = 'SOGo.+ Login from \'([0-9a-f\.:]+)\' for user .+ might not have worked'
|
||||
RULES[5] = 'mailcow UI: Invalid password for .+ by ([0-9a-f\.:]+)'
|
||||
#RULES[6] = '-login: Aborted login \(no auth .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
|
||||
RULES[6] = '([0-9a-f\.:]+) \"GET \/SOGo\/.* HTTP.+\" 403 .+'
|
||||
#RULES[7] = '-login: Aborted login \(no auth .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
|
||||
|
||||
bans = {}
|
||||
log = {}
|
||||
|
@ -83,9 +83,16 @@ EOF
|
||||
done
|
||||
|
||||
|
||||
mkdir -p /var/lib/sogo/GNUstep/Defaults/
|
||||
if [[ "${ALLOW_ADMIN_EMAIL_LOGIN}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
TRUST_PROXY="YES"
|
||||
else
|
||||
TRUST_PROXY="NO"
|
||||
fi
|
||||
# cat /dev/urandom seems to hang here occasionally and is not recommended anyway, better use openssl
|
||||
RAND_PASS=$(openssl rand -base64 16 | tr -dc _A-Z-a-z-0-9)
|
||||
|
||||
# Generate plist header with timezone data
|
||||
mkdir -p /var/lib/sogo/GNUstep/Defaults/
|
||||
cat <<EOF > /var/lib/sogo/GNUstep/Defaults/sogod.plist
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//GNUstep//DTD plist 0.9//EN" "http://www.gnustep.org/plist-0_9.xml">
|
||||
@ -93,6 +100,12 @@ cat <<EOF > /var/lib/sogo/GNUstep/Defaults/sogod.plist
|
||||
<dict>
|
||||
<key>OCSAclURL</key>
|
||||
<string>mysql://${DBUSER}:${DBPASS}@%2Fvar%2Frun%2Fmysqld%2Fmysqld.sock/${DBNAME}/sogo_acl</string>
|
||||
<key>SOGoIMAPServer</key>
|
||||
<string>imap://${IPV4_NETWORK}.250:143/?tls=YES</string>
|
||||
<key>SOGoTrustProxyAuthentication</key>
|
||||
<string>${TRUST_PROXY}</string>
|
||||
<key>SOGoEncryptionKey</key>
|
||||
<string>${RAND_PASS}</string>
|
||||
<key>OCSCacheFolderURL</key>
|
||||
<string>mysql://${DBUSER}:${DBPASS}@%2Fvar%2Frun%2Fmysqld%2Fmysqld.sock/${DBNAME}/sogo_cache_folder</string>
|
||||
<key>OCSEMailAlarmsFolderURL</key>
|
||||
|
@ -389,4 +389,5 @@ imap_max_line_length = 2 M
|
||||
#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
|
||||
|
@ -142,7 +142,19 @@ server {
|
||||
try_files /autoconfig.php =404;
|
||||
}
|
||||
|
||||
# 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 ^~ /Microsoft-Server-ActiveSync {
|
||||
include /etc/nginx/conf.d/sogo_proxy_auth.active;
|
||||
include /etc/nginx/conf.d/sogo_eas.active;
|
||||
proxy_connect_timeout 4000;
|
||||
proxy_next_upstream timeout error;
|
||||
@ -165,6 +177,7 @@ server {
|
||||
}
|
||||
|
||||
location ^~ /SOGo {
|
||||
include /etc/nginx/conf.d/sogo_proxy_auth.active;
|
||||
include /etc/nginx/conf.d/sogo.active;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
10
data/conf/nginx/templates/sogo.auth_request.template.sh
Normal file
10
data/conf/nginx/templates/sogo.auth_request.template.sh
Normal file
@ -0,0 +1,10 @@
|
||||
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_user;
|
||||
auth_request_set $auth $upstream_http_x_auth;
|
||||
auth_request_set $auth_type $upstream_http_x_auth_type;
|
||||
proxy_set_header x-webobjects-remote-user "$user";
|
||||
proxy_set_header Authorization "$auth";
|
||||
proxy_set_header x-webobjects-auth-type "$auth_type";
|
||||
'
|
||||
fi
|
0
data/conf/phpfpm/sogo-sso/.gitkeep
Normal file
0
data/conf/phpfpm/sogo-sso/.gitkeep
Normal file
@ -26,7 +26,6 @@
|
||||
// (domain3.tld, domain2.tld)
|
||||
// );
|
||||
|
||||
SOGoIMAPServer = "imap://dovecot:143/?tls=YES";
|
||||
SOGoSieveServer = "sieve://dovecot:4190/?tls=YES";
|
||||
SOGoSMTPServer = "postfix:588";
|
||||
WOPort = "0.0.0.0:20000";
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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";
|
||||
?>
|
||||
</script>
|
||||
<?php
|
||||
|
86
data/web/sogo-auth.php
Normal file
86
data/web/sogo-auth.php
Normal file
@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
$ALLOW_ADMIN_EMAIL_LOGIN = (preg_match(
|
||||
"/^([yY][eE][sS]|[yY])+$/",
|
||||
$_ENV["ALLOW_ADMIN_EMAIL_LOGIN"]
|
||||
));
|
||||
|
||||
$session_var_user_allowed = 'sogo-sso-user-allowed';
|
||||
$session_var_pass = 'sogo-sso-pass';
|
||||
|
||||
// prevent if feature is disabled
|
||||
if (!$ALLOW_ADMIN_EMAIL_LOGIN) {
|
||||
header('HTTP/1.0 403 Forbidden');
|
||||
echo "this feature is disabled";
|
||||
exit;
|
||||
}
|
||||
// validate credentials for basic auth requests
|
||||
elseif (isset($_SERVER['PHP_AUTH_USER'])) {
|
||||
// load prerequisites only when required
|
||||
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);
|
||||
if ($login_check === 'user') {
|
||||
header("X-User: $username");
|
||||
header("X-Auth: Basic ".base64_encode("$username:$password"));
|
||||
header("X-Auth-Type: Basic");
|
||||
exit;
|
||||
} else {
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
echo 'Invalid login';
|
||||
exit;
|
||||
}
|
||||
}
|
||||
// check permissions and redirect for direct GET ?login=xy requests
|
||||
elseif (isset($_GET['login'])) {
|
||||
// load prerequisites only when required
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
|
||||
// check permissions
|
||||
if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['acl']['login_as'] == "1") {
|
||||
$login = html_entity_decode(rawurldecode($_GET["login"]));
|
||||
if (filter_var($login, FILTER_VALIDATE_EMAIL)) {
|
||||
if (!empty(mailbox('get', 'mailbox_details', $login))) {
|
||||
// load master password
|
||||
$sogo_sso_pass = file_get_contents("/etc/sogo-sso/sogo-sso.pass");
|
||||
// register username and password in session
|
||||
$_SESSION[$session_var_user_allowed][] = $login;
|
||||
$_SESSION[$session_var_pass] = $sogo_sso_pass;
|
||||
// redirect to sogo (sogo will get the correct credentials via nginx auth_request
|
||||
header("Location: /SOGo/so/${login}");
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
header('HTTP/1.0 403 Forbidden');
|
||||
exit;
|
||||
}
|
||||
// only check for admin-login on sogo GUI requests
|
||||
elseif (
|
||||
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"
|
||||
$url_parts = explode("/", $_SERVER['HTTP_X_ORIGINAL_URI']);
|
||||
$email = $url_parts[3];
|
||||
// check if this email is in session allowed list
|
||||
if (
|
||||
!empty($email) &&
|
||||
filter_var($email, FILTER_VALIDATE_EMAIL) &&
|
||||
is_array($_SESSION[$session_var_user_allowed]) &&
|
||||
in_array($email, $_SESSION[$session_var_user_allowed])
|
||||
) {
|
||||
$username = $email;
|
||||
$password = $_SESSION[$session_var_pass];
|
||||
header("X-User: $username");
|
||||
header("X-Auth: Basic ".base64_encode("$username:$password"));
|
||||
header("X-Auth-Type: Basic");
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
// if username is empty, SOGo will use the normal login methods / login form
|
||||
header("X-User: ");
|
||||
header("X-Auth: ");
|
||||
header("X-Auth-Type: ");
|
@ -94,7 +94,7 @@ services:
|
||||
- rspamd
|
||||
|
||||
php-fpm-mailcow:
|
||||
image: mailcow/phpfpm:1.35
|
||||
image: mailcow/phpfpm:1.36
|
||||
build: ./data/Dockerfiles/phpfpm
|
||||
command: "php-fpm -d date.timezone=${TZ} -d expose_php=0"
|
||||
depends_on:
|
||||
@ -106,6 +106,7 @@ services:
|
||||
- mysql-socket-vol-1:/var/run/mysqld/
|
||||
- ./data/conf/sogo/:/etc/sogo/
|
||||
- ./data/conf/rspamd/meta_exporter:/meta_exporter:ro
|
||||
- ./data/conf/phpfpm/sogo-sso/:/etc/sogo-sso/
|
||||
- ./data/conf/phpfpm/php-fpm.d/pools.conf:/usr/local/etc/php-fpm.d/z-pools.conf
|
||||
- ./data/conf/phpfpm/php-conf.d/opcache-recommended.ini:/usr/local/etc/php/conf.d/opcache-recommended.ini
|
||||
- ./data/conf/phpfpm/php-conf.d/upload.ini:/usr/local/etc/php/conf.d/upload.ini
|
||||
@ -130,6 +131,7 @@ services:
|
||||
- API_ALLOW_FROM=${API_ALLOW_FROM:-invalid}
|
||||
- COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME:-mailcow-dockerized}
|
||||
- SKIP_SOLR=${SKIP_SOLR:-y}
|
||||
- ALLOW_ADMIN_EMAIL_LOGIN=${ALLOW_ADMIN_EMAIL_LOGIN:-n}
|
||||
restart: always
|
||||
dns:
|
||||
- ${IPV4_NETWORK:-172.22.1}.254
|
||||
@ -149,6 +151,8 @@ services:
|
||||
- LOG_LINES=${LOG_LINES:-9999}
|
||||
- MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
|
||||
- ACL_ANYONE=${ACL_ANYONE:-disallow}
|
||||
- ALLOW_ADMIN_EMAIL_LOGIN=${ALLOW_ADMIN_EMAIL_LOGIN:-n}
|
||||
- IPV4_NETWORK=${IPV4_NETWORK:-172.22.1}
|
||||
volumes:
|
||||
- ./data/conf/sogo/:/etc/sogo/
|
||||
- ./data/web/inc/init_db.inc.php:/init_db.inc.php
|
||||
@ -165,7 +169,7 @@ services:
|
||||
- sogo
|
||||
|
||||
dovecot-mailcow:
|
||||
image: mailcow/dovecot:1.65
|
||||
image: mailcow/dovecot:1.67
|
||||
build: ./data/Dockerfiles/dovecot
|
||||
cap_add:
|
||||
- NET_BIND_SERVICE
|
||||
@ -173,6 +177,7 @@ services:
|
||||
- ./data/conf/dovecot:/usr/local/etc/dovecot
|
||||
- ./data/assets/ssl:/etc/ssl/mail/:ro
|
||||
- ./data/conf/sogo/:/etc/sogo/
|
||||
- ./data/conf/phpfpm/sogo-sso/:/etc/phpfpm/
|
||||
- vmail-vol-1:/var/vmail
|
||||
- vmail-attachments-vol-1:/var/attachments
|
||||
- crypt-vol-1:/mail_crypt/
|
||||
@ -186,6 +191,8 @@ services:
|
||||
- DBUSER=${DBUSER}
|
||||
- DBPASS=${DBPASS}
|
||||
- TZ=${TZ}
|
||||
- IPV4_NETWORK=${IPV4_NETWORK:-172.22.1}
|
||||
- ALLOW_ADMIN_EMAIL_LOGIN=${ALLOW_ADMIN_EMAIL_LOGIN:-n}
|
||||
- MAILDIR_GC_TIME=${MAILDIR_GC_TIME:-1440}
|
||||
- ACL_ANYONE=${ACL_ANYONE:-disallow}
|
||||
- SKIP_SOLR=${SKIP_SOLR:-y}
|
||||
@ -209,6 +216,7 @@ services:
|
||||
hostname: ${MAILCOW_HOSTNAME}
|
||||
networks:
|
||||
mailcow-network:
|
||||
ipv4_address: ${IPV4_NETWORK:-172.22.1}.250
|
||||
aliases:
|
||||
- dovecot
|
||||
|
||||
@ -264,6 +272,7 @@ services:
|
||||
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 &&
|
||||
envsubst < /etc/nginx/conf.d/templates/sogo_eas.template > /etc/nginx/conf.d/sogo_eas.active &&
|
||||
. /etc/nginx/conf.d/templates/sogo.auth_request.template.sh > /etc/nginx/conf.d/sogo_proxy_auth.active &&
|
||||
nginx -qt &&
|
||||
until ping phpfpm -c1 > /dev/null; do sleep 1; done &&
|
||||
until ping sogo -c1 > /dev/null; do sleep 1; done &&
|
||||
@ -276,6 +285,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
|
||||
@ -325,7 +335,7 @@ services:
|
||||
- acme
|
||||
|
||||
netfilter-mailcow:
|
||||
image: mailcow/netfilter:1.22
|
||||
image: mailcow/netfilter:1.23
|
||||
build: ./data/Dockerfiles/netfilter
|
||||
stop_grace_period: 30s
|
||||
depends_on:
|
||||
|
@ -205,6 +205,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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user