Merge pull request #1972 from surfaslt/implement-get-access-key-last-used
Implement get_access_key_last_used
This commit is contained in:
		
						commit
						25595815e5
					
				| @ -2257,7 +2257,7 @@ | |||||||
| - [X] detach_user_policy | - [X] detach_user_policy | ||||||
| - [X] enable_mfa_device | - [X] enable_mfa_device | ||||||
| - [ ] generate_credential_report | - [ ] generate_credential_report | ||||||
| - [ ] get_access_key_last_used | - [X] get_access_key_last_used | ||||||
| - [X] get_account_authorization_details | - [X] get_account_authorization_details | ||||||
| - [ ] get_account_password_policy | - [ ] get_account_password_policy | ||||||
| - [ ] get_account_summary | - [ ] get_account_summary | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								Makefile
									
									
									
									
									
								
							| @ -19,6 +19,7 @@ test: lint | |||||||
| 	rm -f .coverage | 	rm -f .coverage | ||||||
| 	rm -rf cover | 	rm -rf cover | ||||||
| 	@nosetests -sv --with-coverage --cover-html ./tests/ $(TEST_EXCLUDE) | 	@nosetests -sv --with-coverage --cover-html ./tests/ $(TEST_EXCLUDE) | ||||||
|  | 
 | ||||||
| test_server: | test_server: | ||||||
| 	@TEST_SERVER_MODE=true nosetests -sv --with-coverage --cover-html ./tests/ | 	@TEST_SERVER_MODE=true nosetests -sv --with-coverage --cover-html ./tests/ | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -250,6 +250,10 @@ class AccessKey(BaseModel): | |||||||
|             datetime.utcnow(), |             datetime.utcnow(), | ||||||
|             "%Y-%m-%dT%H:%M:%SZ" |             "%Y-%m-%dT%H:%M:%SZ" | ||||||
|         ) |         ) | ||||||
|  |         self.last_used = datetime.strftime( | ||||||
|  |             datetime.utcnow(), | ||||||
|  |             "%Y-%m-%dT%H:%M:%SZ" | ||||||
|  |         ) | ||||||
| 
 | 
 | ||||||
|     def get_cfn_attribute(self, attribute_name): |     def get_cfn_attribute(self, attribute_name): | ||||||
|         from moto.cloudformation.exceptions import UnformattedGetAttTemplateException |         from moto.cloudformation.exceptions import UnformattedGetAttTemplateException | ||||||
| @ -379,21 +383,20 @@ class User(BaseModel): | |||||||
|         return self.access_keys |         return self.access_keys | ||||||
| 
 | 
 | ||||||
|     def delete_access_key(self, access_key_id): |     def delete_access_key(self, access_key_id): | ||||||
|         for key in self.access_keys: |         key = self.get_access_key_by_id(access_key_id) | ||||||
|             if key.access_key_id == access_key_id: |  | ||||||
|         self.access_keys.remove(key) |         self.access_keys.remove(key) | ||||||
|                 break |  | ||||||
|         else: |  | ||||||
|             raise IAMNotFoundException( |  | ||||||
|                 "Key {0} not found".format(access_key_id)) |  | ||||||
| 
 | 
 | ||||||
|     def update_access_key(self, access_key_id, status): |     def update_access_key(self, access_key_id, status): | ||||||
|  |         key = self.get_access_key_by_id(access_key_id) | ||||||
|  |         key.status = status | ||||||
|  | 
 | ||||||
|  |     def get_access_key_by_id(self, access_key_id): | ||||||
|         for key in self.access_keys: |         for key in self.access_keys: | ||||||
|             if key.access_key_id == access_key_id: |             if key.access_key_id == access_key_id: | ||||||
|                 key.status = status |                 return key | ||||||
|                 break |  | ||||||
|         else: |         else: | ||||||
|             raise IAMNotFoundException("The Access Key with id {0} cannot be found".format(access_key_id)) |             raise IAMNotFoundException( | ||||||
|  |                 "The Access Key with id {0} cannot be found".format(access_key_id)) | ||||||
| 
 | 
 | ||||||
|     def get_cfn_attribute(self, attribute_name): |     def get_cfn_attribute(self, attribute_name): | ||||||
|         from moto.cloudformation.exceptions import UnformattedGetAttTemplateException |         from moto.cloudformation.exceptions import UnformattedGetAttTemplateException | ||||||
| @ -908,6 +911,24 @@ class IAMBackend(BaseBackend): | |||||||
|         user = self.get_user(user_name) |         user = self.get_user(user_name) | ||||||
|         user.update_access_key(access_key_id, status) |         user.update_access_key(access_key_id, status) | ||||||
| 
 | 
 | ||||||
|  |     def get_access_key_last_used(self, access_key_id): | ||||||
|  |         access_keys_list = self.get_all_access_keys_for_all_users() | ||||||
|  |         for key in access_keys_list: | ||||||
|  |             if key.access_key_id == access_key_id: | ||||||
|  |                 return { | ||||||
|  |                     'user_name': key.user_name, | ||||||
|  |                     'last_used': key.last_used | ||||||
|  |                 } | ||||||
|  |         else: | ||||||
|  |             raise IAMNotFoundException( | ||||||
|  |                 "The Access Key with id {0} cannot be found".format(access_key_id)) | ||||||
|  | 
 | ||||||
|  |     def get_all_access_keys_for_all_users(self): | ||||||
|  |         access_keys_list = [] | ||||||
|  |         for user_name in self.users: | ||||||
|  |             access_keys_list += self.get_all_access_keys(user_name) | ||||||
|  |         return access_keys_list | ||||||
|  | 
 | ||||||
|     def get_all_access_keys(self, user_name, marker=None, max_items=None): |     def get_all_access_keys(self, user_name, marker=None, max_items=None): | ||||||
|         user = self.get_user(user_name) |         user = self.get_user(user_name) | ||||||
|         keys = user.get_all_access_keys() |         keys = user.get_all_access_keys() | ||||||
|  | |||||||
| @ -454,9 +454,14 @@ class IamResponse(BaseResponse): | |||||||
|         template = self.response_template(GENERIC_EMPTY_TEMPLATE) |         template = self.response_template(GENERIC_EMPTY_TEMPLATE) | ||||||
|         return template.render(name='UpdateAccessKey') |         return template.render(name='UpdateAccessKey') | ||||||
| 
 | 
 | ||||||
|  |     def get_access_key_last_used(self): | ||||||
|  |         access_key_id = self._get_param('AccessKeyId') | ||||||
|  |         last_used_response = iam_backend.get_access_key_last_used(access_key_id) | ||||||
|  |         template = self.response_template(GET_ACCESS_KEY_LAST_USED_TEMPLATE) | ||||||
|  |         return template.render(user_name=last_used_response["user_name"], last_used=last_used_response["last_used"]) | ||||||
|  | 
 | ||||||
|     def list_access_keys(self): |     def list_access_keys(self): | ||||||
|         user_name = self._get_param('UserName') |         user_name = self._get_param('UserName') | ||||||
| 
 |  | ||||||
|         keys = iam_backend.get_all_access_keys(user_name) |         keys = iam_backend.get_all_access_keys(user_name) | ||||||
|         template = self.response_template(LIST_ACCESS_KEYS_TEMPLATE) |         template = self.response_template(LIST_ACCESS_KEYS_TEMPLATE) | ||||||
|         return template.render(user_name=user_name, keys=keys) |         return template.render(user_name=user_name, keys=keys) | ||||||
| @ -1308,6 +1313,18 @@ LIST_ACCESS_KEYS_TEMPLATE = """<ListAccessKeysResponse> | |||||||
|    </ResponseMetadata> |    </ResponseMetadata> | ||||||
| </ListAccessKeysResponse>""" | </ListAccessKeysResponse>""" | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | GET_ACCESS_KEY_LAST_USED_TEMPLATE = """ | ||||||
|  | <GetAccessKeyLastUsedResponse> | ||||||
|  |     <GetAccessKeyLastUsedResult> | ||||||
|  |         <UserName>{{ user_name }}</UserName> | ||||||
|  |         <AccessKeyLastUsed> | ||||||
|  |             <LastUsedDate>{{ last_used }}</LastUsedDate> | ||||||
|  |         </AccessKeyLastUsed> | ||||||
|  |     </GetAccessKeyLastUsedResult> | ||||||
|  | </GetAccessKeyLastUsedResponse> | ||||||
|  | """ | ||||||
|  | 
 | ||||||
| CREDENTIAL_REPORT_GENERATING = """ | CREDENTIAL_REPORT_GENERATING = """ | ||||||
| <GenerateCredentialReportResponse> | <GenerateCredentialReportResponse> | ||||||
|     <GenerateCredentialReportResult> |     <GenerateCredentialReportResult> | ||||||
|  | |||||||
| @ -13,6 +13,7 @@ from moto.iam.models import aws_managed_policies | |||||||
| from nose.tools import assert_raises, assert_equals | from nose.tools import assert_raises, assert_equals | ||||||
| from nose.tools import raises | from nose.tools import raises | ||||||
| 
 | 
 | ||||||
|  | from datetime import datetime | ||||||
| from tests.helpers import requires_boto_gte | from tests.helpers import requires_boto_gte | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -735,6 +736,24 @@ def test_update_access_key(): | |||||||
|     resp['AccessKeyMetadata'][0]['Status'].should.equal('Inactive') |     resp['AccessKeyMetadata'][0]['Status'].should.equal('Inactive') | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @mock_iam | ||||||
|  | def test_get_access_key_last_used(): | ||||||
|  |     iam = boto3.resource('iam', region_name='us-east-1') | ||||||
|  |     client = iam.meta.client | ||||||
|  |     username = 'test-user' | ||||||
|  |     iam.create_user(UserName=username) | ||||||
|  |     with assert_raises(ClientError): | ||||||
|  |         client.get_access_key_last_used(AccessKeyId='non-existent-key-id') | ||||||
|  |     create_key_response = client.create_access_key(UserName=username)['AccessKey'] | ||||||
|  |     resp = client.get_access_key_last_used(AccessKeyId=create_key_response['AccessKeyId']) | ||||||
|  | 
 | ||||||
|  |     datetime.strftime(resp["AccessKeyLastUsed"]["LastUsedDate"], "%Y-%m-%d").should.equal(datetime.strftime( | ||||||
|  |         datetime.utcnow(), | ||||||
|  |         "%Y-%m-%d" | ||||||
|  |     )) | ||||||
|  |     resp["UserName"].should.equal(create_key_response["UserName"]) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| @mock_iam | @mock_iam | ||||||
| def test_get_account_authorization_details(): | def test_get_account_authorization_details(): | ||||||
|     import json |     import json | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user