Fix MFA authorization

This is absolutely impractical to force users to code TOTP token in the
clouds.yaml. With this change it is possible to pass passcode
dynamically, what will especially be helping OSC with --os-passcode to
pass the MFA code.

Change-Id: I2b3b17f13744c05bdafb2367fb45cc6b39845807
This commit is contained in:
Artem Goncharov 2021-05-10 15:59:04 +02:00
parent 1b60894a7d
commit 3958422a86
3 changed files with 54 additions and 0 deletions

View File

@ -262,6 +262,31 @@ establish new connection.
auth: true
MFA Support
-----------
MFA support requires a specially prepared configuration file. In this case a
combination of 2 different authorization plugins is used with their individual
requirements to the specified parameteres.
.. code-block:: yaml
clouds:
mfa:
auth_type: "v3multifactor"
auth_methods:
- v3password
- v3totp
auth:
auth_url: https://identity.cloud.com
username: user
user_id: uid
password: XXXXXXXXX
project_name: project
user_domain_name: udn
project_domain_name: pdn
IPv6
----

View File

@ -1042,6 +1042,12 @@ class OpenStackConfig:
or ('token' in config and config['token'])):
config.setdefault('token', config.pop('auth_token', None))
# Infer passcode if it was given separately
# This is generally absolutely impractical to require setting passcode
# in the clouds.yaml
if 'auth' in config and 'passcode' in config:
config['auth']['passcode'] = config.pop('passcode', None)
# These backwards compat values are only set via argparse. If it's
# there, it's because it was passed in explicitly, and should win
config = self._fix_backwards_api_timeout(config)

View File

@ -205,6 +205,29 @@ class TestConfig(base.TestCase):
self.assertNotIn('domain_id', cc.auth)
self.assertNotIn('domain_id', cc)
def test_get_one_infer_passcode(self):
single_conf = base._write_yaml({
'clouds': {
'mfa': {
'auth_type': 'v3multifactor',
'auth_methods': ['v3password', 'v3totp'],
'auth': {
'auth_url': 'fake_url',
'username': 'testuser',
'password': 'testpass',
'project_name': 'testproject',
'project_domain_name': 'projectdomain',
'user_domain_name': 'udn'
},
'region_name': 'test-region',
}
}
})
c = config.OpenStackConfig(config_files=[single_conf])
cc = c.get_one(cloud='mfa', passcode='123')
self.assertEqual('123', cc.auth['passcode'])
def test_get_one_with_hyphenated_project_id(self):
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
vendor_files=[self.vendor_yaml])