1
0
mirror of https://github.com/mail-in-a-box/mailinabox.git synced 2026-03-15 17:37:22 +01:00

Add TOTP secret to user_key hash

thanks @downtownallday
* this invalidates all user_keys after TOTP status is changed for user
* after changing TOTP state, a login is required
* due to the forced login, we can't and don't need to store the code used for setup in `mru_code`
This commit is contained in:
Felix Spöttel
2020-09-12 16:34:06 +02:00
parent 2ea97f0643
commit dcb93d071c
6 changed files with 43 additions and 26 deletions

View File

@@ -3,7 +3,7 @@ import base64, os, os.path, hmac
from flask import make_response
import utils, totp
from mailconfig import get_mail_password, get_mail_user_privileges
from mailconfig import get_mail_password, get_mail_user_privileges, get_mfa_state
DEFAULT_KEY_PATH = '/var/lib/mailinabox/api.key'
DEFAULT_AUTH_REALM = 'Mail-in-a-Box Management Server'
@@ -136,15 +136,23 @@ class KeyAuthService:
def create_user_key(self, email, env):
# Store an HMAC with the client. The hashed message of the HMAC will be the user's
# email address & hashed password and the key will be the master API key. The user of
# course has their own email address and password. We assume they do not have the master
# API key (unless they are trusted anyway). The HMAC proves that they authenticated
# with us in some other way to get the HMAC. Including the password means that when
# email address & hashed password and the key will be the master API key. If TOTP
# is active, the key will also include the TOTP secret. The user of course has their
# own email address and password. We assume they do not have the master API key
# (unless they are trusted anyway). The HMAC proves that they authenticated with us
# in some other way to get the HMAC. Including the password means that when
# a user's password is reset, the HMAC changes and they will correctly need to log
# in to the control panel again. This method raises a ValueError if the user does
# not exist, due to get_mail_password.
msg = b"AUTH:" + email.encode("utf8") + b" " + get_mail_password(email, env).encode("utf8")
return hmac.new(self.key.encode('ascii'), msg, digestmod="sha256").hexdigest()
mfa_state = get_mfa_state(email, env)
hash_key = self.key.encode('ascii')
if mfa_state['type'] == 'totp':
hash_key = hash_key + mfa_state['secret'].encode('ascii')
return hmac.new(hash_key, msg, digestmod="sha256").hexdigest()
def _generate_key(self):
raw_key = os.urandom(32)