mirror of
https://github.com/mail-in-a-box/mailinabox.git
synced 2024-11-23 02:27:05 +00:00
replace Dovecot authentication (formerly an sql query) with a call to our management daemon
This commit is contained in:
parent
7e05d7478f
commit
1f0345fe0e
53
conf/dovecot-checkpassword.py
Normal file
53
conf/dovecot-checkpassword.py
Normal file
@ -0,0 +1,53 @@
|
||||
#!/usr/bin/python3
|
||||
#
|
||||
# This script implement's Dovecot's checkpassword authentication mechanism:
|
||||
# http://wiki2.dovecot.org/AuthDatabase/CheckPassword?action=show&redirect=PasswordDatabase%2FCheckPassword
|
||||
#
|
||||
# This allows us to perform our own password validation, such as for two-factor authentication,
|
||||
# which Dovecot does not have any native support for.
|
||||
#
|
||||
# We will issue an HTTP request to our management server to perform authentication.
|
||||
|
||||
import sys, os, urllib.request, base64, json, traceback
|
||||
|
||||
try:
|
||||
# Read fd 3 which provides the username and password separated
|
||||
# by NULLs and two other undocumented/empty fields.
|
||||
creds = b''
|
||||
while True:
|
||||
b = os.read(3, 1024)
|
||||
if len(b) == 0: break
|
||||
creds += b
|
||||
email, pw, dummy, dummy = creds.split(b'\x00')
|
||||
|
||||
# Call the management server's "/me" method with the
|
||||
# provided credentials
|
||||
req = urllib.request.Request('http://127.0.0.1:10222/me')
|
||||
req.add_header(b'Authorization', b'Basic ' + base64.b64encode(email + b':' + pw))
|
||||
response = urllib.request.urlopen(req)
|
||||
|
||||
# The response is always success and always a JSON object
|
||||
# indicating the authentication result.
|
||||
resp = response.read().decode('utf8')
|
||||
resp = json.loads(resp)
|
||||
if not isinstance(resp, dict): raise ValueError("Response is not a JSON object.")
|
||||
|
||||
except:
|
||||
# Handle all exceptions. Print what happens (ends up in syslog, thanks
|
||||
# to dovecot) and return an exit status that indicates temporary failure,
|
||||
# which is passed on to the authenticating client.
|
||||
traceback.print_exc()
|
||||
print(json.dumps(dict(os.environ), indent=2), file=sys.stderr)
|
||||
sys.exit(111)
|
||||
|
||||
if resp.get('status') != 'authorized':
|
||||
# Indicates login failure.
|
||||
# (sys.exit should not be inside the try block.)
|
||||
sys.exit(1)
|
||||
|
||||
# Signal ok by executing the indicated process, per the Dovecot
|
||||
# protocol. (Note that the second parameter is the 0th argument
|
||||
# to the called process, which is required and is typically the
|
||||
# file itself.)
|
||||
os.execl(sys.argv[1], sys.argv[1])
|
||||
|
@ -26,31 +26,55 @@ fi
|
||||
|
||||
# ### User Authentication
|
||||
|
||||
# Have Dovecot query our database, and not system users, for authentication.
|
||||
sed -i "s/#*\(\!include auth-system.conf.ext\)/#\1/" /etc/dovecot/conf.d/10-auth.conf
|
||||
sed -i "s/#\(\!include auth-sql.conf.ext\)/\1/" /etc/dovecot/conf.d/10-auth.conf
|
||||
# Disable all of the built-in authentication mechanisms. (We formerly uncommented
|
||||
# a line to include auth-sql.conf.ext but we no longer use that.)
|
||||
sed -i "s/#*\(\!include auth-.*.conf.ext\)/#\1/" /etc/dovecot/conf.d/10-auth.conf
|
||||
|
||||
# Specify how the database is to be queried for user authentication (passdb)
|
||||
# and where user mailboxes are stored (userdb).
|
||||
cat > /etc/dovecot/conf.d/auth-sql.conf.ext << EOF;
|
||||
# Legacy: Delete our old sql conf files.
|
||||
rm -f /etc/dovecot/conf.d/auth-sql.conf.ext /etc/dovecot/dovecot-sql.conf.ext
|
||||
|
||||
# Specify how Dovecot should perform user authentication (passdb) and how it knows
|
||||
# where user mailboxes are stored (userdb).
|
||||
#
|
||||
# For passwords, we would normally have Dovecot query our mail user database
|
||||
# directly. The way to do that is commented out below. Instead, in order to
|
||||
# provide our own authentication framework so we can handle two-factor auth,
|
||||
# we will use a custom system that hooks into the Mail-in-a-Box management daemon.
|
||||
#
|
||||
# The user part of this is standard. The mailbox path and Unix system user are the
|
||||
# same for all mail users, modulo string substitution for the mailbox path that
|
||||
# Dovecot handles.
|
||||
cat > /etc/dovecot/conf.d/10-auth-mailinabox.conf << EOF;
|
||||
passdb {
|
||||
driver = sql
|
||||
args = /etc/dovecot/dovecot-sql.conf.ext
|
||||
driver = checkpassword
|
||||
args = /usr/local/bin/dovecot-checkpassword
|
||||
}
|
||||
userdb {
|
||||
driver = static
|
||||
args = uid=mail gid=mail home=$STORAGE_ROOT/mail/mailboxes/%d/%n
|
||||
}
|
||||
EOF
|
||||
chmod 0600 /etc/dovecot/conf.d/10-auth-mailinabox.conf
|
||||
|
||||
# Configure the SQL to query for a user's password.
|
||||
cat > /etc/dovecot/dovecot-sql.conf.ext << EOF;
|
||||
driver = sqlite
|
||||
connect = $db_path
|
||||
default_pass_scheme = SHA512-CRYPT
|
||||
password_query = SELECT email as user, password FROM users WHERE email='%u';
|
||||
EOF
|
||||
chmod 0600 /etc/dovecot/dovecot-sql.conf.ext # per Dovecot instructions
|
||||
# Copy dovecot-checkpassword into place.
|
||||
cp conf/dovecot-checkpassword.py /usr/local/bin/dovecot-checkpassword
|
||||
chown dovecot.dovecot /usr/local/bin/dovecot-checkpassword
|
||||
chmod 700 /usr/local/bin/dovecot-checkpassword
|
||||
|
||||
# If we were having Dovecot query our database directly, which we did
|
||||
# originally, `/etc/dovecot/conf.d/10-auth-mailinabox.conf` would say:
|
||||
#
|
||||
# passdb {
|
||||
# driver = sql
|
||||
# args = /etc/dovecot/dovecot-sql.conf.ext
|
||||
# }
|
||||
#
|
||||
# and then `/etc/dovecot/dovecot-sql.conf.ext` (chmod 0600) would contain:
|
||||
#
|
||||
# driver = sqlite
|
||||
# connect = $db_path
|
||||
# default_pass_scheme = SHA512-CRYPT
|
||||
# password_query = SELECT email as user, password FROM users WHERE email='%u';
|
||||
|
||||
# Have Dovecot provide an authorization service that Postfix can access & use.
|
||||
cat > /etc/dovecot/conf.d/99-local-auth.conf << EOF;
|
||||
|
Loading…
Reference in New Issue
Block a user