Allow an admin to login to SOGo as mailbox user
Thanks to @mhofer117 !
This commit is contained in:
		
							
								
								
									
										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 | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user