Merge pull request #881 from smarlowucf/master

Add mfa device endpoints to iam backend.
This commit is contained in:
Steve Pulec 2017-04-12 20:23:49 -04:00 committed by GitHub
commit 42f6487c88
3 changed files with 129 additions and 0 deletions

View File

@ -11,6 +11,19 @@ from .utils import random_access_key, random_alphanumeric, random_resource_id, r
ACCOUNT_ID = 123456789012
class MFADevice(object):
"""MFA Device class."""
def __init__(self,
serial_number,
authentication_code_1,
authentication_code_2):
self.enable_date = datetime.now(pytz.utc)
self.serial_number = serial_number
self.authentication_code_1 = authentication_code_1
self.authentication_code_2 = authentication_code_2
class Policy(BaseModel):
is_attachable = False
@ -226,6 +239,7 @@ class User(BaseModel):
datetime.utcnow(),
"%Y-%m-%d-%H-%M-%S"
)
self.mfa_devices = {}
self.policies = {}
self.access_keys = []
self.password = None
@ -251,6 +265,9 @@ class User(BaseModel):
def put_policy(self, policy_name, policy_json):
self.policies[policy_name] = policy_json
def deactivate_mfa_device(self, serial_number):
self.mfa_devices.pop(serial_number)
def delete_policy(self, policy_name):
if policy_name not in self.policies:
raise IAMNotFoundException(
@ -263,6 +280,16 @@ class User(BaseModel):
self.access_keys.append(access_key)
return access_key
def enable_mfa_device(self,
serial_number,
authentication_code_1,
authentication_code_2):
self.mfa_devices[serial_number] = MFADevice(
serial_number,
authentication_code_1,
authentication_code_2
)
def get_all_access_keys(self):
return self.access_keys
@ -724,6 +751,39 @@ class IAMBackend(BaseBackend):
user = self.get_user(user_name)
user.delete_access_key(access_key_id)
def enable_mfa_device(self,
user_name,
serial_number,
authentication_code_1,
authentication_code_2):
"""Enable MFA Device for user."""
user = self.get_user(user_name)
if serial_number in user.mfa_devices:
raise IAMConflictException(
"EntityAlreadyExists",
"Device {0} already exists".format(serial_number)
)
user.enable_mfa_device(
serial_number,
authentication_code_1,
authentication_code_2
)
def deactivate_mfa_device(self, user_name, serial_number):
"""Deactivate and detach MFA Device from user if device exists."""
user = self.get_user(user_name)
if serial_number not in user.mfa_devices:
raise IAMNotFoundException(
"Device {0} not found".format(serial_number)
)
user.deactivate_mfa_device(serial_number)
def list_mfa_devices(self, user_name):
user = self.get_user(user_name)
return user.mfa_devices.values()
def delete_user(self, user_name):
try:
del self.users[user_name]

View File

@ -326,6 +326,35 @@ class IamResponse(BaseResponse):
template = self.response_template(GENERIC_EMPTY_TEMPLATE)
return template.render(name='DeleteAccessKey')
def deactivate_mfa_device(self):
user_name = self._get_param('UserName')
serial_number = self._get_param('SerialNumber')
iam_backend.deactivate_mfa_device(user_name, serial_number)
template = self.response_template(GENERIC_EMPTY_TEMPLATE)
return template.render(name='DeactivateMFADevice')
def enable_mfa_device(self):
user_name = self._get_param('UserName')
serial_number = self._get_param('SerialNumber')
authentication_code_1 = self._get_param('AuthenticationCode1')
authentication_code_2 = self._get_param('AuthenticationCode2')
iam_backend.enable_mfa_device(
user_name,
serial_number,
authentication_code_1,
authentication_code_2
)
template = self.response_template(GENERIC_EMPTY_TEMPLATE)
return template.render(name='EnableMFADevice')
def list_mfa_devices(self):
user_name = self._get_param('UserName')
devices = iam_backend.list_mfa_devices(user_name)
template = self.response_template(LIST_MFA_DEVICES_TEMPLATE)
return template.render(user_name=user_name, devices=devices)
def delete_user(self):
user_name = self._get_param('UserName')
iam_backend.delete_user(user_name)
@ -922,3 +951,20 @@ LIST_INSTANCE_PROFILES_FOR_ROLE_TEMPLATE = """<ListInstanceProfilesForRoleRespon
<RequestId>6a8c3992-99f4-11e1-a4c3-27EXAMPLE804</RequestId>
</ResponseMetadata>
</ListInstanceProfilesForRoleResponse>"""
LIST_MFA_DEVICES_TEMPLATE = """<ListMFADevicesResponse>
<ListMFADevicesResult>
<MFADevices>
{% for device in devices %}
<member>
<UserName>{{ user_name }}</UserName>
<SerialNumber>{{ device.serial_number }}</SerialNumber>
</member>
{% endfor %}
</MFADevices>
<IsTruncated>false</IsTruncated>
</ListMFADevicesResult>
<ResponseMetadata>
<RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
</ResponseMetadata>
</ListMFADevicesResponse>"""

View File

@ -292,6 +292,29 @@ def test_delete_access_key():
conn.delete_access_key(access_key_id, 'my-user')
@mock_iam()
def test_mfa_devices():
# Test enable device
conn = boto3.client('iam', region_name='us-east-1')
conn.create_user(UserName='my-user')
conn.enable_mfa_device(
UserName='my-user',
SerialNumber='123456789',
AuthenticationCode1='234567',
AuthenticationCode2='987654'
)
# Test list mfa devices
response = conn.list_mfa_devices(UserName='my-user')
device = response['MFADevices'][0]
device['SerialNumber'].should.equal('123456789')
# Test deactivate mfa device
conn.deactivate_mfa_device(UserName='my-user', SerialNumber='123456789')
response = conn.list_mfa_devices(UserName='my-user')
len(response['MFADevices']).should.equal(0)
@mock_iam_deprecated()
def test_delete_user():
conn = boto.connect_iam()