Merge branch 'master' into add-iam-virtual-mfa-device

This commit is contained in:
Jack Danger 2019-10-22 14:54:10 -07:00 committed by GitHub
commit 00045ae480
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 745 additions and 230 deletions

View file

@ -1,8 +1,8 @@
-----BEGIN CERTIFICATE-----
MIIEUDCCAjgCCQDfXZHMio+6oDANBgkqhkiG9w0BAQ0FADBjMQswCQYDVQQGEwJH
MIIEUDCCAjgCCQDfXZHMio+6oDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJH
QjESMBAGA1UECAwJQmVya3NoaXJlMQ8wDQYDVQQHDAZTbG91Z2gxEzARBgNVBAoM
Ck1vdG9TZXJ2ZXIxCzAJBgNVBAsMAlFBMQ0wCwYDVQQDDARNb3RvMB4XDTE3MDky
MTIxMjQ1MFoXDTI3MDkxOTIxMjQ1MFowcTELMAkGA1UEBhMCR0IxEjAQBgNVBAgM
Ck1vdG9TZXJ2ZXIxCzAJBgNVBAsMAlFBMQ0wCwYDVQQDDARNb3RvMB4XDTE5MTAy
MTEzMjczMVoXDTQ5MTIzMTEzMjczNFowcTELMAkGA1UEBhMCR0IxEjAQBgNVBAgM
CUJlcmtzaGlyZTEPMA0GA1UEBwwGU2xvdWdoMRMwEQYDVQQKDApNb3RvU2VydmVy
MRMwEQYDVQQLDApPcGVyYXRpb25zMRMwEQYDVQQDDAoqLm1vdG8uY29tMIIBIjAN
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzC/oBkzwiIBEceSC/tSD7hkqs8AW
@ -11,16 +11,16 @@ niDXbMgAQE9oxUxtkFESxiNa+EbAMLBFtBkPRvc3iKXh/cfLo7yP8VdqEIDmJCB/
vpjJvf6HnrNJ7keQR+oGJNf7jVaCgOVdJ4lt7+98YDVde7jLx1DN+QbvViJQl60n
K3bmfuLiiw8154Eyi9DOcJE8AB+W7KpPdrmbPisR1EiqY0i0L62ZixN0rPi5hHF+
ozwURL1axcmLjlhIFi8YhBCNcY6ThE7jrqgLIq1n6d8ezRxjDKmqfH1spQIDAQAB
MA0GCSqGSIb3DQEBDQUAA4ICAQCgl/EfjE0Jh3cqQgoOlaFq6L1iJVgy5sYKCC4r
OU4dHgifZ6/grqCJesGiS1Vh4L8XklN++C2aSL73lVtxXoCSopP8Yj0rOGeA6b+7
Fetm4ZQYF61QtahC0L2fkvKXR+uz1I85ndSoMJPT8lbm7sYJuL81Si32NOo6kC6y
4eKzV4KznxdAf6XaQMKtMIyXO3PWTrjm5ayzS6UsmnBvULGDCaAQznFlVFdGNSHx
CaENICR0CBcB+vbL7FPC683a4afceM+aMcMVElWG5q8fxtgbL/aPhzfonhDGWOM4
Rdg8x+yDdi7swxmWlcW5wlP8LpLxN/S3GR9j9IyelxUGmb20yTph3i1K6RM/Fm2W
PI8xdneA6qycUAJo93NfaCuNK7yBfK3uDLqmWlGh3xCG+I1JETLRbxYBWiqeVTb3
qjHMrsgqTqjcaCiKR/5H2eVkdcr8mLxrV5niyBItDl1xGxj4LF8hDLormhaCjiBb
N1cMq5saj/BpoIanlqOWby6uRMYlZvuhwKQGPVWgfuRWKFzGbMWyPCxATbiU89Wb
IykNkT1zTCE/eZwH12T4A7jrBiWq8WNfIST0Z7MReE6Oz+M9Pxx7DyDzSb2Y1RmU
xNYd8CavZLCfns00xZSo+10deMoKVS9GgxSHcS4ELaVaBQwu35emiMJSLcK7iNGE
I4WVSA==
MA0GCSqGSIb3DQEBCwUAA4ICAQAOwvJjY1cLIBVGCDPkkxH4xCP6+QRdm7bqF7X5
DNZ70YcJ27GldrEPmKX8C1RvkC4oCsaytl8Hlw3ZcS1GvwBxTVlnYIE6nLPPi1ix
LvYYgoq+Mjk/2XPCnU/6cqJhb5INskg9s0o15jv27cUIgWVMnj+d5lvSiy1HhdYM
wvuQzXELjhe/rHw1/BFGaBV2vd7einUQwla50UZLcsj6FwWSIsv7EB4GaY/G0XqC
Mai2PltBgBPFqsZo27uBeVfxqMZtwAQlr4iWwWZm1haDy6D4GFCSR8E/gtlyhiN4
MOk1cmr9PSOMB3CWqKjkx7lPMOQT/f+gxlCnupNHsHcZGvQV4mCPiU+lLwp+8z/s
bupQwRvu1SwSUD2rIsVeUuSP3hbMcfhiZA50lenQNApimgrThdPUoFXi07FUdL+F
1QCk6cvA48KzGRo+bPSfZQusj51k/2+hl4sHHZdWg6mGAIY9InMKmPDE4VzM8hro
fr2fJLqKQ4h+xKbEYnvPEPttUdJbvUgr9TKKVw+m3lmW9SktzE5KtvWvN6daTj9Z
oHDJkOyko3uyTzk+HwWDC/pQ2cC+iF1MjIHi72U9ibObSODg/d9cMH3XJTnZ9W3+
He9iuH4dJpKnVjnJ5NKt7IOrPHID77160hpwF1dim22ZRp508eYapRzgawPMpCcd
a6YipQ==
-----END CERTIFICATE-----

View file

@ -0,0 +1,59 @@
from __future__ import unicode_literals
import datetime
from botocore.exceptions import ClientError
import boto3
import sure # noqa
from moto import mock_athena
@mock_athena
def test_create_work_group():
client = boto3.client('athena', region_name='us-east-1')
response = client.create_work_group(
Name='athena_workgroup',
Description='Test work group',
Configuration={
'ResultConfiguration': {
'OutputLocation': 's3://bucket-name/prefix/',
'EncryptionConfiguration': {
'EncryptionOption': 'SSE_KMS',
'KmsKey': 'aws:arn:kms:1233456789:us-east-1:key/number-1',
},
},
},
Tags=[],
)
try:
# The second time should throw an error
response = client.create_work_group(
Name='athena_workgroup',
Description='duplicate',
Configuration={
'ResultConfiguration': {
'OutputLocation': 's3://bucket-name/prefix/',
'EncryptionConfiguration': {
'EncryptionOption': 'SSE_KMS',
'KmsKey': 'aws:arn:kms:1233456789:us-east-1:key/number-1',
},
},
},
)
except ClientError as err:
err.response['Error']['Code'].should.equal('InvalidRequestException')
err.response['Error']['Message'].should.equal('WorkGroup already exists')
else:
raise RuntimeError('Should have raised ResourceNotFoundException')
# Then test the work group appears in the work group list
response = client.list_work_groups()
response['WorkGroups'].should.have.length_of(1)
work_group = response['WorkGroups'][0]
work_group['Name'].should.equal('athena_workgroup')
work_group['Description'].should.equal('Test work group')
work_group['State'].should.equal('ENABLED')

View file

@ -769,10 +769,10 @@ def test_get_function_created_with_zipfile():
@mock_lambda
def add_function_permission():
def test_add_function_permission():
conn = boto3.client('lambda', 'us-west-2')
zip_content = get_test_zip_file1()
result = conn.create_function(
conn.create_function(
FunctionName='testFunction',
Runtime='python2.7',
Role='test-iam-role',
@ -796,16 +796,16 @@ def add_function_permission():
EventSourceToken='blah',
Qualifier='2'
)
assert 'Statement' in response
res = json.loads(response['Statement'])
assert res['Action'] == "lambda:InvokeFunction"
assert u'Statement' in response
res = json.loads(response[u'Statement'])
assert res[u'Action'] == u'lambda:InvokeFunction'
@mock_lambda
def get_function_policy():
def test_get_function_policy():
conn = boto3.client('lambda', 'us-west-2')
zip_content = get_test_zip_file1()
result = conn.create_function(
conn.create_function(
FunctionName='testFunction',
Runtime='python2.7',
Role='test-iam-role',
@ -834,10 +834,9 @@ def get_function_policy():
FunctionName='testFunction'
)
assert 'Policy' in response
assert isinstance(response['Policy'], str)
res = json.loads(response['Policy'])
assert res['Statement'][0]['Action'] == 'lambda:InvokeFunction'
assert u'Policy' in response
res = json.loads(response[u'Policy'])
assert res[u'Statement'][0][u'Action'] == u'lambda:InvokeFunction'
@mock_lambda

View file

@ -2161,20 +2161,11 @@ def test_condition_expression__attr_doesnt_exist():
client.create_table(
TableName='test',
KeySchema=[{'AttributeName': 'forum_name', 'KeyType': 'HASH'}],
AttributeDefinitions=[
{'AttributeName': 'forum_name', 'AttributeType': 'S'},
],
ProvisionedThroughput={'ReadCapacityUnits': 1, 'WriteCapacityUnits': 1},
)
client.put_item(
TableName='test',
Item={
'forum_name': {'S': 'foo'},
'ttl': {'N': 'bar'},
}
)
AttributeDefinitions=[{'AttributeName': 'forum_name', 'AttributeType': 'S'}],
ProvisionedThroughput={'ReadCapacityUnits': 1, 'WriteCapacityUnits': 1})
client.put_item(TableName='test',
Item={'forum_name': {'S': 'foo'}, 'ttl': {'N': 'bar'}})
def update_if_attr_doesnt_exist():
# Test nonexistent top-level attribute.
@ -2261,6 +2252,7 @@ def test_condition_expression__and_order():
}
)
@mock_dynamodb2
def test_query_gsi_with_range_key():
dynamodb = boto3.client('dynamodb', region_name='us-east-1')
@ -2510,13 +2502,15 @@ def test_index_with_unknown_attributes_should_fail():
def test_update_list_index__set_existing_index():
table_name = 'test_list_index_access'
client = create_table_with_list(table_name)
client.put_item(TableName=table_name,
Item={'id': {'S': 'foo'}, 'itemlist': {'L': [{'S': 'bar1'}, {'S': 'bar2'}, {'S': 'bar3'}]}})
client.update_item(TableName=table_name, Key={'id': {'S': 'foo'}},
UpdateExpression='set itemlist[1]=:Item',
ExpressionAttributeValues={':Item': {'S': 'bar2_update'}})
#
result = client.get_item(TableName=table_name, Key={'id': {'S': 'foo'}})['Item']
assert result['id'] == {'S': 'foo'}
assert result['itemlist'] == {'L': [{'S': 'bar1'}, {'S': 'bar2_update'}, {'S': 'bar3'}]}
result['id'].should.equal({'S': 'foo'})
result['itemlist'].should.equal({'L': [{'S': 'bar1'}, {'S': 'bar2_update'}, {'S': 'bar3'}]})
@mock_dynamodb2
@ -2530,14 +2524,16 @@ def test_update_list_index__set_existing_nested_index():
ExpressionAttributeValues={':Item': {'S': 'bar2_update'}})
#
result = client.get_item(TableName=table_name, Key={'id': {'S': 'foo2'}})['Item']
assert result['id'] == {'S': 'foo2'}
assert result['itemmap']['M']['itemlist']['L'] == [{'S': 'bar1'}, {'S': 'bar2_update'}, {'S': 'bar3'}]
result['id'].should.equal({'S': 'foo2'})
result['itemmap']['M']['itemlist']['L'].should.equal([{'S': 'bar1'}, {'S': 'bar2_update'}, {'S': 'bar3'}])
@mock_dynamodb2
def test_update_list_index__set_index_out_of_range():
table_name = 'test_list_index_access'
client = create_table_with_list(table_name)
client.put_item(TableName=table_name,
Item={'id': {'S': 'foo'}, 'itemlist': {'L': [{'S': 'bar1'}, {'S': 'bar2'}, {'S': 'bar3'}]}})
client.update_item(TableName=table_name, Key={'id': {'S': 'foo'}},
UpdateExpression='set itemlist[10]=:Item',
ExpressionAttributeValues={':Item': {'S': 'bar10'}})
@ -2562,6 +2558,25 @@ def test_update_list_index__set_nested_index_out_of_range():
assert result['itemmap']['M']['itemlist']['L'] == [{'S': 'bar1'}, {'S': 'bar2'}, {'S': 'bar3'}, {'S': 'bar10'}]
@mock_dynamodb2
def test_update_list_index__set_double_nested_index():
table_name = 'test_list_index_access'
client = create_table_with_list(table_name)
client.put_item(TableName=table_name,
Item={'id': {'S': 'foo2'},
'itemmap': {'M': {'itemlist': {'L': [{'M': {'foo': {'S': 'bar11'}, 'foos': {'S': 'bar12'}}},
{'M': {'foo': {'S': 'bar21'}, 'foos': {'S': 'bar21'}}}]}}}})
client.update_item(TableName=table_name, Key={'id': {'S': 'foo2'}},
UpdateExpression='set itemmap.itemlist[1].foos=:Item',
ExpressionAttributeValues={':Item': {'S': 'bar22'}})
#
result = client.get_item(TableName=table_name, Key={'id': {'S': 'foo2'}})['Item']
assert result['id'] == {'S': 'foo2'}
len(result['itemmap']['M']['itemlist']['L']).should.equal(2)
result['itemmap']['M']['itemlist']['L'][0].should.equal({'M': {'foo': {'S': 'bar11'}, 'foos': {'S': 'bar12'}}}) # unchanged
result['itemmap']['M']['itemlist']['L'][1].should.equal({'M': {'foo': {'S': 'bar21'}, 'foos': {'S': 'bar22'}}}) # updated
@mock_dynamodb2
def test_update_list_index__set_index_of_a_string():
table_name = 'test_list_index_access'
@ -2578,15 +2593,29 @@ def test_update_list_index__set_index_of_a_string():
'The document path provided in the update expression is invalid for update')
@mock_dynamodb2
def test_remove_top_level_attribute():
table_name = 'test_remove'
client = create_table_with_list(table_name)
client.put_item(TableName=table_name,
Item={'id': {'S': 'foo'}, 'item': {'S': 'bar'}})
client.update_item(TableName=table_name, Key={'id': {'S': 'foo'}}, UpdateExpression='REMOVE item')
#
result = client.get_item(TableName=table_name, Key={'id': {'S': 'foo'}})['Item']
result.should.equal({'id': {'S': 'foo'}})
@mock_dynamodb2
def test_remove_list_index__remove_existing_index():
table_name = 'test_list_index_access'
client = create_table_with_list(table_name)
client.put_item(TableName=table_name,
Item={'id': {'S': 'foo'}, 'itemlist': {'L': [{'S': 'bar1'}, {'S': 'bar2'}, {'S': 'bar3'}]}})
client.update_item(TableName=table_name, Key={'id': {'S': 'foo'}}, UpdateExpression='REMOVE itemlist[1]')
#
result = client.get_item(TableName=table_name, Key={'id': {'S': 'foo'}})['Item']
assert result['id'] == {'S': 'foo'}
assert result['itemlist'] == {'L': [{'S': 'bar1'}, {'S': 'bar3'}]}
result['id'].should.equal({'S': 'foo'})
result['itemlist'].should.equal({'L': [{'S': 'bar1'}, {'S': 'bar3'}]})
@mock_dynamodb2
@ -2598,8 +2627,8 @@ def test_remove_list_index__remove_existing_nested_index():
client.update_item(TableName=table_name, Key={'id': {'S': 'foo2'}}, UpdateExpression='REMOVE itemmap.itemlist[1]')
#
result = client.get_item(TableName=table_name, Key={'id': {'S': 'foo2'}})['Item']
assert result['id'] == {'S': 'foo2'}
assert result['itemmap']['M']['itemlist']['L'] == [{'S': 'bar1'}]
result['id'].should.equal({'S': 'foo2'})
result['itemmap']['M']['itemlist']['L'].should.equal([{'S': 'bar1'}])
@mock_dynamodb2
@ -2626,6 +2655,8 @@ def test_remove_list_index__remove_existing_double_nested_index():
def test_remove_list_index__remove_index_out_of_range():
table_name = 'test_list_index_access'
client = create_table_with_list(table_name)
client.put_item(TableName=table_name,
Item={'id': {'S': 'foo'}, 'itemlist': {'L': [{'S': 'bar1'}, {'S': 'bar2'}, {'S': 'bar3'}]}})
client.update_item(TableName=table_name, Key={'id': {'S': 'foo'}}, UpdateExpression='REMOVE itemlist[10]')
#
result = client.get_item(TableName=table_name, Key={'id': {'S': 'foo'}})['Item']
@ -2639,8 +2670,6 @@ def create_table_with_list(table_name):
KeySchema=[{'AttributeName': 'id', 'KeyType': 'HASH'}],
AttributeDefinitions=[{'AttributeName': 'id', 'AttributeType': 'S'}],
BillingMode='PAY_PER_REQUEST')
client.put_item(TableName=table_name,
Item={'id': {'S': 'foo'}, 'itemlist': {'L': [{'S': 'bar1'}, {'S': 'bar2'}, {'S': 'bar3'}]}})
return client

View file

@ -214,16 +214,46 @@ def test_update_login_profile():
def test_delete_role():
conn = boto3.client('iam', region_name='us-east-1')
with assert_raises(ClientError):
with assert_raises(conn.exceptions.NoSuchEntityException):
conn.delete_role(RoleName="my-role")
# Test deletion failure with a managed policy
conn.create_role(RoleName="my-role", AssumeRolePolicyDocument="some policy", Path="/my-path/")
role = conn.get_role(RoleName="my-role")
role.get('Role').get('Arn').should.equal('arn:aws:iam::123456789012:role/my-path/my-role')
response = conn.create_policy(PolicyName="my-managed-policy", PolicyDocument=MOCK_POLICY)
conn.attach_role_policy(PolicyArn=response['Policy']['Arn'], RoleName="my-role")
with assert_raises(conn.exceptions.DeleteConflictException):
conn.delete_role(RoleName="my-role")
conn.detach_role_policy(PolicyArn=response['Policy']['Arn'], RoleName="my-role")
conn.delete_policy(PolicyArn=response['Policy']['Arn'])
conn.delete_role(RoleName="my-role")
with assert_raises(conn.exceptions.NoSuchEntityException):
conn.get_role(RoleName="my-role")
with assert_raises(ClientError):
# Test deletion failure with an inline policy
conn.create_role(RoleName="my-role", AssumeRolePolicyDocument="some policy", Path="/my-path/")
conn.put_role_policy(RoleName="my-role", PolicyName="my-role-policy", PolicyDocument=MOCK_POLICY)
with assert_raises(conn.exceptions.DeleteConflictException):
conn.delete_role(RoleName="my-role")
conn.delete_role_policy(RoleName="my-role", PolicyName="my-role-policy")
conn.delete_role(RoleName="my-role")
with assert_raises(conn.exceptions.NoSuchEntityException):
conn.get_role(RoleName="my-role")
# Test deletion failure with attachment to an instance profile
conn.create_role(RoleName="my-role", AssumeRolePolicyDocument="some policy", Path="/my-path/")
conn.create_instance_profile(InstanceProfileName="my-profile")
conn.add_role_to_instance_profile(InstanceProfileName="my-profile", RoleName="my-role")
with assert_raises(conn.exceptions.DeleteConflictException):
conn.delete_role(RoleName="my-role")
conn.remove_role_from_instance_profile(InstanceProfileName="my-profile", RoleName="my-role")
conn.delete_role(RoleName="my-role")
with assert_raises(conn.exceptions.NoSuchEntityException):
conn.get_role(RoleName="my-role")
# Test deletion with no conflicts
conn.create_role(RoleName="my-role", AssumeRolePolicyDocument="some policy", Path="/my-path/")
conn.delete_role(RoleName="my-role")
with assert_raises(conn.exceptions.NoSuchEntityException):
conn.get_role(RoleName="my-role")
@ -992,12 +1022,40 @@ def test_delete_user_deprecated():
@mock_iam()
def test_delete_user():
conn = boto3.client('iam', region_name='us-east-1')
with assert_raises(ClientError):
with assert_raises(conn.exceptions.NoSuchEntityException):
conn.delete_user(UserName='my-user')
# Test deletion failure with a managed policy
conn.create_user(UserName='my-user')
[user['UserName'] for user in conn.list_users()['Users']].should.equal(['my-user'])
response = conn.create_policy(PolicyName="my-managed-policy", PolicyDocument=MOCK_POLICY)
conn.attach_user_policy(PolicyArn=response['Policy']['Arn'], UserName="my-user")
with assert_raises(conn.exceptions.DeleteConflictException):
conn.delete_user(UserName='my-user')
conn.detach_user_policy(PolicyArn=response['Policy']['Arn'], UserName="my-user")
conn.delete_policy(PolicyArn=response['Policy']['Arn'])
conn.delete_user(UserName='my-user')
assert conn.list_users()['Users'].should.be.empty
with assert_raises(conn.exceptions.NoSuchEntityException):
conn.get_user(UserName='my-user')
# Test deletion failure with an inline policy
conn.create_user(UserName='my-user')
conn.put_user_policy(
UserName='my-user',
PolicyName='my-user-policy',
PolicyDocument=MOCK_POLICY
)
with assert_raises(conn.exceptions.DeleteConflictException):
conn.delete_user(UserName='my-user')
conn.delete_user_policy(UserName='my-user', PolicyName='my-user-policy')
conn.delete_user(UserName='my-user')
with assert_raises(conn.exceptions.NoSuchEntityException):
conn.get_user(UserName='my-user')
# Test deletion with no conflicts
conn.create_user(UserName='my-user')
conn.delete_user(UserName='my-user')
with assert_raises(conn.exceptions.NoSuchEntityException):
conn.get_user(UserName='my-user')
@mock_iam_deprecated()

View file

@ -1247,6 +1247,54 @@ def test_website_redirect_location():
resp['WebsiteRedirectLocation'].should.equal(url)
@mock_s3
def test_boto3_list_objects_truncated_response():
s3 = boto3.client('s3', region_name='us-east-1')
s3.create_bucket(Bucket='mybucket')
s3.put_object(Bucket='mybucket', Key='one', Body=b'1')
s3.put_object(Bucket='mybucket', Key='two', Body=b'22')
s3.put_object(Bucket='mybucket', Key='three', Body=b'333')
# First list
resp = s3.list_objects(Bucket='mybucket', MaxKeys=1)
listed_object = resp['Contents'][0]
assert listed_object['Key'] == 'one'
assert resp['MaxKeys'] == 1
assert resp['IsTruncated'] == True
assert resp['Prefix'] == 'None'
assert resp['Delimiter'] == 'None'
assert 'NextMarker' in resp
next_marker = resp["NextMarker"]
# Second list
resp = s3.list_objects(
Bucket='mybucket', MaxKeys=1, Marker=next_marker)
listed_object = resp['Contents'][0]
assert listed_object['Key'] == 'three'
assert resp['MaxKeys'] == 1
assert resp['IsTruncated'] == True
assert resp['Prefix'] == 'None'
assert resp['Delimiter'] == 'None'
assert 'NextMarker' in resp
next_marker = resp["NextMarker"]
# Third list
resp = s3.list_objects(
Bucket='mybucket', MaxKeys=1, Marker=next_marker)
listed_object = resp['Contents'][0]
assert listed_object['Key'] == 'two'
assert resp['MaxKeys'] == 1
assert resp['IsTruncated'] == False
assert resp['Prefix'] == 'None'
assert resp['Delimiter'] == 'None'
assert 'NextMarker' not in resp
@mock_s3
def test_boto3_list_keys_xml_escaped():
s3 = boto3.client('s3', region_name='us-east-1')