From 63c1b35b9738a9519c477e8d46d47fc29a8f439d Mon Sep 17 00:00:00 2001 From: Mark Woods Date: Fri, 10 Oct 2025 11:54:48 +0100 Subject: [PATCH 1/4] Add support for multiple MFA devices When multiple MFA devices found, ask user to choose which to use. Previously the first was used, and no info about the device was shown. The enquiries package was chosen for the prompt because it is simple. Normally I use inquirer for these things, but it seemed overkill here. --- awsmfa/__main__.py | 6 +++++- setup.py | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/awsmfa/__main__.py b/awsmfa/__main__.py index 08c684c..20043a6 100755 --- a/awsmfa/__main__.py +++ b/awsmfa/__main__.py @@ -12,6 +12,7 @@ import botocore.exceptions import botocore.session import pytz +import enquiries from six import PY2 # noinspection PyUnresolvedReferences from six.moves import configparser @@ -357,8 +358,11 @@ def find_mfa_for_user(user_specified_serial, botocore_session, boto3_session): if not serials: return None if len(serials) > 1: - print("Warning: user has %d MFA devices. Using the first." % + print("Warning: user has %d MFA devices." % len(devices), file=sys.stderr) + selected = enquiries.choose("Select device to use:", serials) + print("Using device %s " % selected) + return selected return serials[0] diff --git a/setup.py b/setup.py index 6561c4e..da1fe95 100644 --- a/setup.py +++ b/setup.py @@ -39,7 +39,8 @@ def get_version(): 'botocore>=1.12.216', 'boto3>=1.9.216', 'pytz>=2016.1', - 'six>=1.10.0' + 'six>=1.10.0', + 'enquiries' ], entry_points={ 'console_scripts': [ From 64e9d046b42cc74361dad02c75e32cd6b0485687 Mon Sep 17 00:00:00 2001 From: Mark Woods Date: Fri, 10 Oct 2025 12:29:41 +0100 Subject: [PATCH 2/4] Fix devices count in message re multiple devices --- awsmfa/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awsmfa/__main__.py b/awsmfa/__main__.py index 20043a6..e30993c 100755 --- a/awsmfa/__main__.py +++ b/awsmfa/__main__.py @@ -359,7 +359,7 @@ def find_mfa_for_user(user_specified_serial, botocore_session, boto3_session): return None if len(serials) > 1: print("Warning: user has %d MFA devices." % - len(devices), file=sys.stderr) + len(serials), file=sys.stderr) selected = enquiries.choose("Select device to use:", serials) print("Using device %s " % selected) return selected From a4ed10948f9009af956fb59a7c7f665444090a30 Mon Sep 17 00:00:00 2001 From: Mark Woods Date: Fri, 10 Oct 2025 14:49:54 +0100 Subject: [PATCH 3/4] Fix MFA device prompt on Windows Switch from enquiries package to questionary, which works on Windows --- awsmfa/__main__.py | 10 ++++++---- setup.py | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/awsmfa/__main__.py b/awsmfa/__main__.py index e30993c..01002a9 100755 --- a/awsmfa/__main__.py +++ b/awsmfa/__main__.py @@ -12,7 +12,7 @@ import botocore.exceptions import botocore.session import pytz -import enquiries +import questionary from six import PY2 # noinspection PyUnresolvedReferences from six.moves import configparser @@ -333,6 +333,10 @@ def safe_bool(s): return str(s).lower() == "true" +def choose(message, choices): + return questionary.select(message, choices).ask() + + def find_mfa_for_user(user_specified_serial, botocore_session, boto3_session): if user_specified_serial: return user_specified_serial @@ -360,9 +364,7 @@ def find_mfa_for_user(user_specified_serial, botocore_session, boto3_session): if len(serials) > 1: print("Warning: user has %d MFA devices." % len(serials), file=sys.stderr) - selected = enquiries.choose("Select device to use:", serials) - print("Using device %s " % selected) - return selected + return choose("Select device to use:", serials) return serials[0] diff --git a/setup.py b/setup.py index da1fe95..2aa15ae 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,7 @@ def get_version(): 'boto3>=1.9.216', 'pytz>=2016.1', 'six>=1.10.0', - 'enquiries' + 'questionary' ], entry_points={ 'console_scripts': [ From 4d2d064c69007d09c6c35a35aacfdbd03947a6a3 Mon Sep 17 00:00:00 2001 From: Mark Woods Date: Sat, 11 Oct 2025 09:34:19 +0100 Subject: [PATCH 4/4] Write MFA device prompt to stderr, fix eval --env Fixes use of `eval $(awsmfa --env)` when user has multiple devices --- awsmfa/__main__.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/awsmfa/__main__.py b/awsmfa/__main__.py index 01002a9..42990a4 100755 --- a/awsmfa/__main__.py +++ b/awsmfa/__main__.py @@ -334,7 +334,13 @@ def safe_bool(s): def choose(message, choices): - return questionary.select(message, choices).ask() + try: + stdout = sys.stdout + sys.stdout = sys.stderr + choice = questionary.select(message, choices).ask() + finally: + sys.stdout = stdout + return choice def find_mfa_for_user(user_specified_serial, botocore_session, boto3_session):