From 51e7002cbb84c9524372f216115461e2ce5c3f12 Mon Sep 17 00:00:00 2001 From: zscholl Date: Wed, 29 Apr 2020 15:49:14 -0500 Subject: [PATCH] add tests --- moto/iam/models.py | 12 +++++-- moto/iam/responses.py | 9 +++--- tests/test_iam/test_iam.py | 64 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 74 insertions(+), 11 deletions(-) diff --git a/moto/iam/models.py b/moto/iam/models.py index 6da6c6742..d3907da26 100755 --- a/moto/iam/models.py +++ b/moto/iam/models.py @@ -681,7 +681,9 @@ class User(BaseModel): access_key_2_last_rotated = "N/A" access_key_2_last_used = "N/A" elif len(self.access_keys) == 1: - access_key_1_active = "true" if self.access_keys[0].status == "Active" else "false" + access_key_1_active = ( + "true" if self.access_keys[0].status == "Active" else "false" + ) access_key_1_last_rotated = self.access_keys[0].create_date.strftime( date_format ) @@ -694,7 +696,9 @@ class User(BaseModel): access_key_2_last_rotated = "N/A" access_key_2_last_used = "N/A" else: - access_key_1_active = "true" if self.access_keys[0].status == "Active" else "false" + access_key_1_active = ( + "true" if self.access_keys[0].status == "Active" else "false" + ) access_key_1_last_rotated = self.access_keys[0].create_date.strftime( date_format ) @@ -703,7 +707,9 @@ class User(BaseModel): if self.access_keys[0].last_used is None else self.access_keys[0].last_used.strftime(date_format) ) - access_key_2_active = "true" if self.access_keys[1].status == "Active" else "false" + access_key_2_active = ( + "true" if self.access_keys[1].status == "Active" else "false" + ) access_key_2_last_rotated = self.access_keys[1].create_date.strftime( date_format ) diff --git a/moto/iam/responses.py b/moto/iam/responses.py index 086ba508b..667a6d13b 100644 --- a/moto/iam/responses.py +++ b/moto/iam/responses.py @@ -1779,12 +1779,11 @@ GET_ACCESS_KEY_LAST_USED_TEMPLATE = """ {{ user_name }} - {% if last_used is defined %} - {{ last_used }} - {% else %} - N/A - N/A + {% if last_used %} + {{ last_used }} {% endif %} + N/A + N/A diff --git a/tests/test_iam/test_iam.py b/tests/test_iam/test_iam.py index 995895437..986809bd5 100644 --- a/tests/test_iam/test_iam.py +++ b/tests/test_iam/test_iam.py @@ -4,6 +4,7 @@ import json import boto import boto3 +import csv import os import sure # noqa import sys @@ -12,12 +13,14 @@ from botocore.exceptions import ClientError from dateutil.tz import tzutc from moto import mock_iam, mock_iam_deprecated -from moto.iam.models import aws_managed_policies from moto.core import ACCOUNT_ID +from moto.iam.models import aws_managed_policies +from moto.backends import get_backend from nose.tools import assert_raises, assert_equals from nose.tools import raises from datetime import datetime +from datetime import timezone from tests.helpers import requires_boto_gte from uuid import uuid4 @@ -1215,6 +1218,44 @@ def test_boto3_get_credential_report(): report.should.match(r".*my-user.*") +@mock_iam +def test_boto3_get_credential_report_content(): + conn = boto3.client("iam", region_name="us-east-1") + username = "my-user" + conn.create_user(UserName=username) + key1 = conn.create_access_key(UserName=username)["AccessKey"] + conn.update_access_key( + UserName=username, AccessKeyId=key1["AccessKeyId"], Status="Inactive" + ) + key1 = conn.create_access_key(UserName=username)["AccessKey"] + iam_backend = get_backend("iam")["global"] + timestamp = datetime.now(tz=timezone.utc) + iam_backend.users[username].access_keys[1].last_used = timestamp + with assert_raises(ClientError): + conn.get_credential_report() + result = conn.generate_credential_report() + while result["State"] != "COMPLETE": + result = conn.generate_credential_report() + result = conn.get_credential_report() + report = result["Content"].decode("utf-8") + header = report.split("\n")[0] + header.should.equal( + "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" + ) + report_dict = csv.DictReader(report.split("\n")) + user = next(report_dict) + user["user"].should.equal("my-user") + user["access_key_1_active"].should.equal("false") + user["access_key_1_last_rotated"].should.equal( + timestamp.isoformat(timespec="seconds") + ) + user["access_key_1_last_used_date"].should.equal("N/A") + user["access_key_2_active"].should.equal("true") + user["access_key_2_last_used_date"].should.equal( + timestamp.isoformat(timespec="seconds") + ) + + @requires_boto_gte("2.39") @mock_iam_deprecated() def test_managed_policy(): @@ -1382,7 +1423,7 @@ def test_update_access_key(): @mock_iam -def test_get_access_key_last_used(): +def test_get_access_key_last_used_when_unused(): iam = boto3.resource("iam", region_name="us-east-1") client = iam.meta.client username = "test-user" @@ -1393,11 +1434,28 @@ def test_get_access_key_last_used(): resp = client.get_access_key_last_used( AccessKeyId=create_key_response["AccessKeyId"] ) + resp["AccessKeyLastUsed"].should_not.contain("LastUsedDate") + resp["UserName"].should.equal(create_key_response["UserName"]) + +@mock_iam +def test_get_access_key_last_used_when_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"] + # Set last used date using the IAM backend. Moto currently does not have a mechanism for tracking usage of access keys + iam_backend = get_backend("iam")["global"] + iam_backend.users[username].access_keys[0].last_used = datetime.utcnow() + 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