diff --git a/management/auth.py b/management/auth.py index cf2a4bdc..46768684 100644 --- a/management/auth.py +++ b/management/auth.py @@ -4,7 +4,7 @@ from flask import make_response import utils from mailconfig import validate_login, get_mail_password, get_mail_user_privileges -from mfa import get_mfa_state, validate_auth_mfa +from mfa import get_hash_mfa_state, validate_auth_mfa DEFAULT_KEY_PATH = '/var/lib/mailinabox/api.key' DEFAULT_AUTH_REALM = 'Mail-in-a-Box Management Server' @@ -135,7 +135,7 @@ class KeyAuthService: # Add to the message the current MFA state, which is a list of MFA information. # Turn it into a string stably. - msg += b" " + json.dumps(get_mfa_state(email, env), sort_keys=True).encode("utf8") + msg += b" " + json.dumps(get_hash_mfa_state(email, env), sort_keys=True).encode("utf8") # Make the HMAC. hash_key = self.key.encode('ascii') diff --git a/management/mfa.py b/management/mfa.py index 260b80a4..84659c79 100644 --- a/management/mfa.py +++ b/management/mfa.py @@ -9,8 +9,8 @@ def strip_order_prefix(rec, attributes): `rec` is modified in-place - the server returns X-ORDERED values in-order so the values will be - correctly orded in the record. + the server returns X-ORDERED values ordered so the values will be + sorted in the record making the prefix superfluous. For example, the function will change: totpSecret: {0}secret1 @@ -65,10 +65,26 @@ def get_public_mfa_state(email, env): particular MFA by label and the id of each so it may be disabled. ''' - user = get_mfa_user(email, env) - state_list = [] - state_list += mfa_totp.get_public_state(user) - return state_list + mfa_state = get_mfa_state(email, env) + return [ + { "id": s["id"], "type": s["type"], "label": s["label"] } + for s in mfa_state + ] + +def get_hash_mfa_state(email, env): + '''return details about what MFA schemes are enabled for a user + ordered by the priority that the scheme will be tried, with index + zero being the first. This function may return secrets. It's + intended use is for the result to be included as part of the input + to a hashing function to generate a user api key (see + auth.py:create_user_key) + + ''' + mfa_state = get_mfa_state(email, env) + return [ + { "id": s["id"], "type": s["type"], "secret": s["secret"] } + for s in mfa_state + ] def enable_mfa(email, type, secret, token, label, env): '''enable MFA using the scheme specified in `type`. users may have diff --git a/management/mfa_totp.py b/management/mfa_totp.py index 931ef021..3bea84e0 100644 --- a/management/mfa_totp.py +++ b/management/mfa_totp.py @@ -45,18 +45,6 @@ def get_state(user): }) return state_list -def get_public_state(user): - state_list = [] - - # totp - for idx in range(0, len(user['totpSecret'])): - state_list.append({ - 'id': totp_id_from_index(user, idx), - 'type': 'totp', - 'label': user['totpLabel'][idx] - }) - return state_list - def enable(user, secret, token, label, env): validate_secret(secret) # Sanity check with the provide current token.