From 35fde06381a910331410105be05bf4b28a37eb49 Mon Sep 17 00:00:00 2001 From: zscholl Date: Thu, 12 Mar 2020 13:07:30 -0500 Subject: [PATCH] update last_used for access keys --- moto/core/utils.py | 2 +- moto/iam/models.py | 23 ++++++++++++++++++++--- moto/iam/responses.py | 5 +++++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/moto/core/utils.py b/moto/core/utils.py index dce9f675c..921f64be2 100644 --- a/moto/core/utils.py +++ b/moto/core/utils.py @@ -187,7 +187,7 @@ def iso_8601_datetime_with_milliseconds(datetime): def iso_8601_datetime_without_milliseconds(datetime): - return datetime.strftime("%Y-%m-%dT%H:%M:%S") + "Z" + return None if datetime is None else datetime.strftime("%Y-%m-%dT%H:%M:%S") + "Z" RFC1123 = "%a, %d %b %Y %H:%M:%S GMT" diff --git a/moto/iam/models.py b/moto/iam/models.py index dfa6fd36a..c84e664c3 100755 --- a/moto/iam/models.py +++ b/moto/iam/models.py @@ -464,7 +464,7 @@ class AccessKey(BaseModel): self.secret_access_key = random_alphanumeric(40) self.status = "Active" self.create_date = datetime.utcnow() - self.last_used = datetime.utcnow() + self.last_used = None @property def created_iso_8601(self): @@ -683,6 +683,11 @@ class User(BaseModel): access_key_1_last_rotated = self.access_keys[0].create_date.strftime( date_format ) + access_key_2_last_rotated = ( + "N/A" + if self.access_key[0].last_used is None + else self.access_key[0].last_used.strftime(date_format) + ) access_key_2_active = "false" access_key_2_last_rotated = "N/A" else: @@ -690,12 +695,22 @@ class User(BaseModel): access_key_1_last_rotated = self.access_keys[0].create_date.strftime( date_format ) + access_key_1_last_used = ( + "N/A" + if self.access_key[0].last_used is None + else self.access_key[0].last_used.strftime(date_format) + ) access_key_2_active = "true" access_key_2_last_rotated = self.access_keys[1].create_date.strftime( date_format ) + access_key_2_last_used = ( + "N/A" + if self.access_key[1].last_used is None + else self.access_key[1].last_used.strftime(date_format) + ) - return "{0},{1},{2},{3},{4},{5},not_supported,false,{6},{7},{8},{9},false,N/A,false,N/A".format( + return "{0},{1},{2},{3},{4},{5},not_supported,false,{6},{7},{8},not_supported,not_supported,{9},{10},{11},false,N/A,false,N/A".format( self.name, self.arn, date_created.strftime(date_format), @@ -704,8 +719,10 @@ class User(BaseModel): date_created.strftime(date_format), access_key_1_active, access_key_1_last_rotated, + access_key_1_last_used, access_key_2_active, access_key_2_last_rotated, + access_key_2_last_used, ) @@ -1805,7 +1822,7 @@ class IAMBackend(BaseBackend): def get_credential_report(self): if not self.credential_report: raise IAMReportNotPresentException("Credential report not present") - report = "user,arn,user_creation_time,password_enabled,password_last_used,password_last_changed,password_next_rotation,mfa_active,access_key_1_active,access_key_1_last_rotated,access_key_2_active,access_key_2_last_rotated,cert_1_active,cert_1_last_rotated,cert_2_active,cert_2_last_rotated\n" + report = "user,arn,user_creation_time,password_enabled,password_last_used,password_last_changed,password_next_rotation,mfa_active,access_key_1_active,access_key_1_last_rotated,access_key_1_last_used_date,access_key_1_last_used_region,access_key_1_last_used_service,access_key_2_active,access_key_2_last_rotated,access_key_2_last_used_date,access_key_2_last_used_region,access_key_2_last_used_service,cert_1_active,cert_1_last_rotated,cert_2_active,cert_2_last_rotated\n" for user in self.users: report += self.users[user].to_csv() return base64.b64encode(report.encode("ascii")).decode("ascii") diff --git a/moto/iam/responses.py b/moto/iam/responses.py index 12501769e..947cccf33 100644 --- a/moto/iam/responses.py +++ b/moto/iam/responses.py @@ -1779,7 +1779,12 @@ GET_ACCESS_KEY_LAST_USED_TEMPLATE = """ {{ user_name }} + {{% if last_used % }} {{ last_used }} + {{% else % }} + N/A + N/A + {{% endif %}}