# # All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or # its licensors. # # For complete copyright and license terms please see the LICENSE at the root of this # distribution (the "License"). All use of this software is governed by the License, # or, if provided, by the license below or the license accompanying this file. Do not # remove or modify any license notices. This file is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # import resource_manager_common.constant as constant import boto3 from botocore.exceptions import ClientError from copy import deepcopy import datetime import json from resource_manager.test import lmbr_aws_test_support from resource_manager.test import base_stack_test import os from random import randint from requests_aws4auth import AWS4Auth import requests from six import iteritems # Python 2.7/3.7 Compatibility import subprocess import time import uuid REGION='us-east-1' class IntegrationTest_CloudGemPlayerAccount_EndToEnd(base_stack_test.BaseStackTestCase): # Fails in cleanup to keep the deployment stack intact for the next test rerun. FAST_TEST_RERUN = False # Upload lambda code if the deployment stack is re-used. UPLOAD_LAMBDA_CODE_FOR_EXISTING_STACK = True GEM_NAME = 'CloudGemPlayerAccount' TEST_USERNAME_PREFIX = 'TestUser' TEST_PASSWORD = '$Password1' TEST_EMAIL = 'nobody-{}@example.com'.format(datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S')) IDP_COGNITO = 'Cognito' COGNITO_ATTRIBUTES = set(["address", "birthdate", "email", "family_name", "gender", "given_name", "locale", "middle_name", "nickname", "phone_number", "picture", "profile", "website", "zoneinfo"]) TEST_ATTRIBUTES = { 'address': 'test_address2', 'birthdate': 'birthdate2', 'email': 'test_email@example.com', 'family_name': 'test_family_name', 'gender': 'test_gender', 'given_name': 'test_given_name', 'locale': 'test_locale', 'middle_name': 'test_middle_name', 'nickname': 'test_nickname', 'phone_number': '+14325551212', 'picture': 'test_picture', 'website': 'test_website', 'zoneinfo': 'test_zoneinfo' } maxDiff = None def __init__(self, *args, **kwargs): super(IntegrationTest_CloudGemPlayerAccount_EndToEnd, self).__init__(*args, **kwargs) def setUp(self): self.prepare_test_environment("cloud_gem_player_account_test") self.register_for_shared_resources() self.enable_shared_gem(self.GEM_NAME) def test_end_to_end(self): self.run_all_tests() def __000_create_stacks(self): new_proj_created, new_deploy_created = self.setup_base_stack() if not new_deploy_created and self.UPLOAD_LAMBDA_CODE_FOR_EXISTING_STACK: self.lmbr_aws('function', 'upload-code', '--resource-group', self.GEM_NAME, '-d', self.TEST_DEPLOYMENT_NAME) self.context['user_pool_id'] = self.get_stack_resource_physical_id(self.get_resource_group_stack_arn(self.TEST_DEPLOYMENT_NAME, self.GEM_NAME), 'PlayerUserPool') clients_response = self.aws_cognito_idp.list_user_pool_clients(UserPoolId=self.context['user_pool_id'], MaxResults=1) self.context['user_pool_client_id'] = clients_response['UserPoolClients'][0]['ClientId'] self.context['identity_pool_id'] = self.get_stack_resource_physical_id(self.get_deployment_access_stack_arn(self.TEST_DEPLOYMENT_NAME), 'PlayerAccessIdentityPool') self.context['user_pool_provider_id'] = 'cognito-idp.' + self.TEST_REGION + '.amazonaws.com/' + self.context['user_pool_id'] self.context['accounts_table'] = self.get_stack_resource_physical_id(self.get_resource_group_stack_arn(self.TEST_DEPLOYMENT_NAME, self.GEM_NAME), 'PlayerAccounts') self.context['test_run_id'] = datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S') self.context['generator_sequence'] = 0 # ------------------------------------------------ Create player account, get auth tokens, custom auth flow ------------------------------------------------ def __010_create_test_user_and_sign_in(self): self.context['test_username'] = self.TEST_USERNAME_PREFIX + '5-' + self.__generate_id() print('Creating user {} in pool {}'.format(self.context['test_username'], self.context['user_pool_id'])) self.__signup(self.context['test_username'], self.TEST_PASSWORD, self.TEST_EMAIL) authResult = self.__signin(self.context['test_username'], self.TEST_PASSWORD) self.context['auth_tokens'] = authResult self.context['account_id'] = self.__get_account_id(self.context['test_username']) print('Account ID: {}'.format(self.context['account_id'])) self.context['identity_id'] = self.__get_identity_id(authResult) self.context['aws_credentials'] = self.__get_aws_credentials(self.context['identity_id'], authResult) def __020_create_blacklist_user(self): self.context['test_username_blacklisted_true'] = self.TEST_USERNAME_PREFIX + '-' + self.__generate_id() print('Creating user {} in pool {}'.format(self.context['test_username_blacklisted_true'], self.context['user_pool_id'])) self.__signup(self.context['test_username_blacklisted_true'], self.TEST_PASSWORD, self.TEST_EMAIL) authResult = self.__signin(self.context['test_username_blacklisted_true'], self.TEST_PASSWORD) self.context['account_id_blacklisted_true'] = self.__get_account_id(self.context['test_username_blacklisted_true']) print('Account ID: {}'.format(self.context['account_id_blacklisted_true'])) self.context['identity_id_blacklisted_true'] = self.__get_identity_id(authResult) self.context['aws_credentials_blacklisted_true'] = self.__get_aws_credentials(self.context['identity_id_blacklisted_true'], authResult) # Blacklist the user self.__service_put('/admin/accounts/{}'.format(self.context['account_id_blacklisted_true']), {'AccountBlacklisted': True}, admin_auth=True) # Existing access tokens should now be invalid. with self.assertRaisesRegex(ClientError, 'NotAuthorizedException') as context_manager: self.aws_cognito_idp.get_user(AccessToken=authResult['AccessToken']) def __030_create_no_longer_blacklisted_user(self): self.context['test_username_blacklisted_false'] = self.TEST_USERNAME_PREFIX + '-' + self.__generate_id() print('Creating user {} in pool {}'.format(self.context['test_username_blacklisted_false'], self.context['user_pool_id'])) self.__signup(self.context['test_username_blacklisted_false'], self.TEST_PASSWORD, self.TEST_EMAIL) authResult = self.__signin(self.context['test_username_blacklisted_false'], self.TEST_PASSWORD) self.context['account_id_blacklisted_false'] = self.__get_account_id(self.context['test_username_blacklisted_false']) print('Account ID: {}'.format(self.context['account_id_blacklisted_false'])) # Blacklist/unblacklist the user self.__service_put('/admin/accounts/{}'.format(self.context['account_id_blacklisted_false']), {'AccountBlacklisted': True}, admin_auth=True) self.__service_put('/admin/accounts/{}'.format(self.context['account_id_blacklisted_false']), {'AccountBlacklisted': False}, admin_auth=True) # Sign in after unblacklist authResult = self.__signin(self.context['test_username_blacklisted_false'], self.TEST_PASSWORD) self.context['identity_id_blacklisted_false'] = self.__get_identity_id(authResult) self.context['aws_credentials_blacklisted_false'] = self.__get_aws_credentials(self.context['identity_id_blacklisted_false'], authResult) def __040_custom_auth_flow_fails_when_wrong_password(self): with self.assertRaisesRegex(ClientError, 'Authentication failed') as context_manager: self.__signin(self.context['test_username'], 'InvalidPassword') def __050_get_anonymous_aws_credentials(self): identity_response = self.aws_cognito_identity.get_id(IdentityPoolId=self.context['identity_pool_id'], Logins={}) response = self.aws_cognito_identity.get_credentials_for_identity(IdentityId=identity_response['IdentityId'], Logins={}) self.context['anonymous_aws_credentials'] = { 'AccessKeyId': response['Credentials']['AccessKeyId'], 'SecretKey': response['Credentials']['SecretKey'], 'SessionToken': response['Credentials']['SessionToken'] } def __060_custom_auth_flow_rejects_blacklisted_accounts(self): with self.assertRaisesRegex(ClientError, 'blacklist') as context_manager: self.__signin(self.context['test_username_blacklisted_true'], self.TEST_PASSWORD) def __070_custom_auth_flow_allows_no_longer_blacklisted(self): self.__signin(self.context['test_username_blacklisted_false'], self.TEST_PASSWORD) def __080_custom_auth_flow_with_force_change_password(self): username = self.TEST_USERNAME_PREFIX + '-' + self.__generate_id() # admin_create_user always creates users with the force change password status. self.aws_cognito_idp.admin_create_user( UserPoolId=self.context['user_pool_id'], Username=username, UserAttributes=[{'Name': 'email', 'Value': self.TEST_ATTRIBUTES['email']}], MessageAction='SUPPRESS', TemporaryPassword=self.TEST_PASSWORD ) challenge_response = self.aws_cognito_idp.initiate_auth( AuthFlow='CUSTOM_AUTH', AuthParameters={'USERNAME': username}, ClientId=self.context['user_pool_client_id'] ) self.assertEqual('ForceChangePassword', challenge_response.get('ChallengeParameters').get('type')) new_password = self.TEST_PASSWORD + '2' auth_response = self.aws_cognito_idp.respond_to_auth_challenge( ClientId=self.context['user_pool_client_id'], ChallengeName='CUSTOM_CHALLENGE', Session=challenge_response['Session'], ChallengeResponses={'USERNAME': username, 'ANSWER': json.dumps({'password': self.TEST_PASSWORD, 'newPassword': new_password})} ) self.assertIsNotNone(auth_response.get('AuthenticationResult').get('AccessToken')) # Check that the new password is valid. self.__signin(username, new_password) # ------------------------------------------------ Service status ------------------------------------------------ def __100_call_status_with_player_credentials(self): result = self.__service_get('/service/status', player_auth=True) status = result.get('status', None) self.assertIsNotNone(status, "Missing 'status' in result: {}".format(result)) self.assertEqual(status, 'online') def __105_call_status_with_admin_credentials(self): result = self.__service_get('/service/status', admin_auth=True) status = result.get('status', None) self.assertIsNotNone(status, "Missing 'status' in result: {}".format(result)) self.assertEqual(status, 'online') def __110_call_status_with_no_credentials(self): self.__service_get('/service/status', expected_status_code=403) # ------------------------------------------------ Player APIs ------------------------------------------------ def __200_call_get_account(self): result = self.__service_get('/account', player_auth=True) self.assertIn('AccountId', result) self.assertNotIn('CognitoIdentityId', result) self.assertNotIn('CognitoUsername', result) self.assertNotIn('IndexedPlayerName', result) self.assertNotIn('PlayerNameSortKey', result) def __205_call_get_account_with_admin_credentials(self): self.__service_get('/account', admin_auth=True, expected_status_code=403) def __210_call_get_account_with_no_credentials(self): self.__service_get('/account', expected_status_code=403) def __215_call_get_account_for_blacklisted_user(self): self.__service_get('/account', player_credentials=self.context['aws_credentials_blacklisted_true'], expected_status_code=403) def __220_call_get_account_for_no_longer_blacklisted_user(self): self.__service_get('/account', player_credentials=self.context['aws_credentials_blacklisted_false']) def __225_call_put_account(self): name = 'TestName' + str(randint(0,1000)) result = self.__service_put('/account', {'PlayerName': name}, player_auth=True) self.assertIn('AccountId', result) self.assertNotIn('CognitoIdentityId', result) self.assertNotIn('CognitoUsername', result) self.assertNotIn('IndexedPlayerName', result) self.assertNotIn('PlayerNameSortKey', result) self.assertEqual(result.get('PlayerName', None), name) result = self.__service_get('/account', player_auth=True) self.assertIn('AccountId', result) self.assertNotIn('CognitoIdentityId', result) self.assertNotIn('CognitoUsername', result) self.assertNotIn('IndexedPlayerName', result) self.assertNotIn('PlayerNameSortKey', result) self.assertEqual(result.get('PlayerName', None), name) def __230_call_put_account_to_create_anonymous_account(self): name = 'TestName' + str(randint(0,1000)) result = self.__service_put('/account', {'PlayerName': name}, anonymous_auth=True) self.assertIn('AccountId', result) self.assertNotIn('CognitoIdentityId', result) self.assertNotIn('CognitoUsername', result) self.assertNotIn('IndexedPlayerName', result) self.assertNotIn('PlayerNameSortKey', result) self.assertEqual(result.get('PlayerName', None), name) result = self.__service_get('/account', anonymous_auth=True) self.assertIn('AccountId', result) self.assertNotIn('CognitoIdentityId', result) self.assertNotIn('CognitoUsername', result) self.assertNotIn('IndexedPlayerName', result) self.assertNotIn('PlayerNameSortKey', result) self.assertEqual(result.get('PlayerName', None), name) def __235_call_put_account_with_admin_credentials(self): self.__service_put('/account', {'PlayerName': 'TestName'}, admin_auth=True, expected_status_code=403) def __240_call_put_account_with_no_credentials(self): self.__service_put('/account', {'PlayerName': 'TestName'}, expected_status_code=403) def __245_call_put_account_with_long_player_name(self): self.__service_put('/account', {'PlayerName': 'Test' * 100}, player_auth=True, expected_status_code=400) def __250_call_put_account_for_blacklisted_user(self): self.__service_put('/account', {'PlayerName': 'TestName2'}, player_credentials=self.context['aws_credentials_blacklisted_true'], expected_status_code=403) def __255_call_put_account_for_no_longer_blacklisted_user(self): self.__service_put('/account', {'PlayerName': 'TestName3'}, player_credentials=self.context['aws_credentials_blacklisted_false'], player_auth=True) # ------------------------------------------------ Admin Account APIs ------------------------------------------------ def __300_call_admin_get_account(self): result = self.__service_get('/admin/accounts/{}'.format(self.context['account_id']), admin_auth=True) self.__assert_username_is_correct(result) self.__assert_cognito_user_equals(result.get('IdentityProviders', {}).get(self.IDP_COGNITO, {}), {'email': self.TEST_EMAIL}, self.context['test_username']) self.assertEqual(result.get('AccountId'), self.context['account_id']) self.assertFalse(result.get('AccountBlacklisted')) self.assertEqual(result.get('CognitoIdentityId'), self.context['identity_id']) def __305_call_admin_get_account_for_non_existent_account(self): self.__service_get('/admin/accounts/non-existent', admin_auth=True, expected_status_code=400) def __310_call_admin_get_account_with_player_credentials(self): self.__service_get('/admin/accounts/{}'.format(self.context['account_id']), player_auth=True, expected_status_code=403) def __315_call_admin_get_account_with_no_credentials(self): self.__service_get('/admin/accounts/{}'.format(self.context['account_id']), expected_status_code=403) def __320_call_admin_get_account_without_cognito(self): accountId = self.__service_post('/admin/accounts', {'PlayerName': "test"}, admin_auth=True).get('AccountId') result = self.__service_get('/admin/accounts/{}'.format(accountId), admin_auth=True) self.assertNotIn('CognitoUsername', result) self.assertNotIn('IdentityProviders', result) self.assertEqual(result.get('AccountId'), accountId) self.assertFalse(result.get('AccountBlacklisted')) self.assertNotIn('CognitoIdentityId', result) def __325_call_admin_put_account(self): name = 'TestName' + str(randint(0,1000)) result = self.__service_put('/admin/accounts/{}'.format(self.context['account_id']), {'AccountBlacklisted': True, 'PlayerName': name}, admin_auth=True) self.__assert_username_is_correct(result) self.__assert_cognito_user_equals(result.get('IdentityProviders', {}).get(self.IDP_COGNITO, {}), {'email': self.TEST_EMAIL}, self.context['test_username']) self.assertEqual(result.get('AccountId'), self.context['account_id']) self.assertTrue(result.get('AccountBlacklisted')) self.assertEqual(result.get('CognitoIdentityId'), self.context['identity_id']) self.assertEqual(result.get('PlayerName'), name) result = self.__service_get('/admin/accounts/{}'.format(self.context['account_id']), admin_auth=True) self.__assert_username_is_correct(result) self.__assert_cognito_user_equals(result.get('IdentityProviders', {}).get(self.IDP_COGNITO, {}), {'email': self.TEST_EMAIL}, self.context['test_username']) self.assertEqual(result.get('AccountId'), self.context['account_id']) self.assertTrue(result.get('AccountBlacklisted')) self.assertEqual(result.get('CognitoIdentityId'), self.context['identity_id']) self.assertEqual(result.get('PlayerName'), name) def __330_call_admin_put_account_blacklist(self): name = 'TestName' + str(randint(0,1000)) # Blacklist stays true result = self.__service_put('/admin/accounts/{}'.format(self.context['account_id']), {'PlayerName': name}, admin_auth=True) self.assertTrue(result.get('AccountBlacklisted')) self.assertEqual(result.get('PlayerName'), name) result = self.__service_get('/admin/accounts/{}'.format(self.context['account_id']), admin_auth=True) self.assertTrue(result.get('AccountBlacklisted')) self.assertEqual(result.get('PlayerName'), name) # Change blacklist to false, no player name given. result = self.__service_put('/admin/accounts/{}'.format(self.context['account_id']), {'AccountBlacklisted': False}, admin_auth=True) self.assertFalse(result.get('AccountBlacklisted')) self.assertEqual(result.get('PlayerName'), name) result = self.__service_get('/admin/accounts/{}'.format(self.context['account_id']), admin_auth=True) self.assertFalse(result.get('AccountBlacklisted')) self.assertEqual(result.get('PlayerName'), name) def __335_call_admin_put_account_with_player_credentials(self): self.__service_put('/admin/accounts/{}'.format(self.context['account_id']), {'PlayerName': 'TestName'}, player_auth=True, expected_status_code=403) def __340_call_admin_put_account_with_no_credentials(self): self.__service_put('/admin/accounts/{}'.format(self.context['account_id']), {'PlayerName': 'TestName'}, expected_status_code=403) def __345_call_admin_put_with_empty_cognito_request(self): request = { 'IdentityProviders': { self.IDP_COGNITO: { } } } result = self.__service_put('/admin/accounts/{}'.format(self.context['account_id']), request, admin_auth=True) self.__assert_username_is_correct(result) self.__assert_cognito_user_equals(result.get('IdentityProviders', {}).get(self.IDP_COGNITO, {}), {'email': self.TEST_EMAIL}, self.context['test_username']) self.assertEqual(result.get('AccountId'), self.context['account_id']) self.assertEqual(result.get('CognitoIdentityId'), self.context['identity_id']) def __350_call_admin_put_identity_provider_partial_update(self): request = { 'IdentityProviders': { self.IDP_COGNITO: { 'address': 'test_address' } } } result = self.__service_put('/admin/accounts/{}'.format(self.context['account_id']), request, admin_auth=True) self.__assert_username_is_correct(result) expectedAttributes = { 'email': self.TEST_EMAIL, 'address': request['IdentityProviders'][self.IDP_COGNITO]['address'] } self.__assert_cognito_user_equals(result.get('IdentityProviders', {}).get(self.IDP_COGNITO, {}), expectedAttributes, self.context['test_username']) self.assertEqual(result.get('AccountId'), self.context['account_id']) self.assertEqual(result.get('CognitoIdentityId'), self.context['identity_id']) def __355_call_admin_put_identity_provider_full_update(self): request = { 'IdentityProviders': { self.IDP_COGNITO: self.TEST_ATTRIBUTES } } result = self.__service_put('/admin/accounts/{}'.format(self.context['account_id']), request, admin_auth=True) self.__assert_username_is_correct(result) self.__assert_cognito_user_equals(result.get('IdentityProviders', {}).get(self.IDP_COGNITO, {}), self.TEST_ATTRIBUTES, self.context['test_username']) self.assertEqual(result.get('AccountId'), self.context['account_id']) self.assertEqual(result.get('CognitoIdentityId'), self.context['identity_id']) result = self.__service_get('/admin/accounts/{}'.format(self.context['account_id']), admin_auth=True) self.__assert_username_is_correct(result) self.__assert_cognito_user_equals(result.get('IdentityProviders', {}).get(self.IDP_COGNITO, {}), self.TEST_ATTRIBUTES, self.context['test_username']) self.assertEqual(result.get('AccountId'), self.context['account_id']) self.assertEqual(result.get('CognitoIdentityId'), self.context['identity_id']) def __360_call_admin_put_identity_provider_fail_and_undo_playername(self): account = self.__create_account({'PlayerName': 'OriginalPlayerName', 'CognitoUsername': 'invalid'}, None) request = { 'PlayerName': 'PlayerNameInBadRequest', 'IdentityProviders': { self.IDP_COGNITO: {'address': 'test'} } } self.__service_put('/admin/accounts/{}'.format(account['AccountId']), request, admin_auth=True, expected_status_code=400) result = self.__service_get('/admin/accounts/{}'.format(account['AccountId']), admin_auth=True) self.assertEqual(result.get('PlayerName'), 'OriginalPlayerName') def __365_call_admin_put_identity_provider_fail_and_delete_playername(self): account = self.__create_account({'CognitoUsername': 'invalid'}, None) request = { 'IdentityProviders': { self.IDP_COGNITO: {'address': 'test'} } } self.__service_put('/admin/accounts/{}'.format(account['AccountId']), request, admin_auth=True, expected_status_code=400) result = self.__service_get('/admin/accounts/{}'.format(account['AccountId']), admin_auth=True) self.assertIsNone(result.get('PlayerName')) def __370_call_admin_put_account_with_long_player_name(self): self.__service_put('/admin/accounts/{}'.format(self.context['account_id']), {'PlayerName': 'Test' * 100}, admin_auth=True, expected_status_code=400) def __375_call_admin_put_account_with_long_attributes(self): long_value = 'x' * 3000 for key,value in iteritems(self.TEST_ATTRIBUTES): request = { 'IdentityProviders': { self.IDP_COGNITO: {key: long_value} } } result = self.__service_put('/admin/accounts/{}'.format(self.context['account_id']), request, admin_auth=True, expected_status_code=400) def __380_call_admin_create_account_without_user(self): name = 'TestName' + str(randint(0,1000)) result = self.__service_post('/admin/accounts', {'PlayerName': name}, admin_auth=True) self.assertNotIn('CognitoUsername', result) self.assertNotIn('IdentityProviders', result) self.assertIsNotNone(result.get('AccountId')) self.assertFalse(result.get('AccountBlacklisted')) self.assertNotIn('CognitoIdentityId', result) self.assertEqual(result.get('PlayerName'), name) account_id = result.get('AccountId') result = self.__service_get('/admin/accounts/{}'.format(account_id), admin_auth=True) self.assertNotIn('CognitoUsername', result) self.assertNotIn('IdentityProviders', result) self.assertEqual(result.get('AccountId'), account_id) self.assertFalse(result.get('AccountBlacklisted')) self.assertNotIn('CognitoIdentityId', result) self.assertEqual(result.get('PlayerName'), name) def __385_call_admin_create_account_with_user(self): name = 'TestName' + str(randint(0,1000)) username = self.TEST_USERNAME_PREFIX + '-' + self.__generate_id() request = { 'CognitoUsername': username, 'PlayerName': name, 'IdentityProviders': { self.IDP_COGNITO: self.TEST_ATTRIBUTES } } result = self.__service_post('/admin/accounts', request, admin_auth=True) self.assertEqual(result.get('CognitoUsername'), username) self.__assert_cognito_user_equals(result.get('IdentityProviders', {}).get(self.IDP_COGNITO, {}), self.TEST_ATTRIBUTES, username) self.assertIsNotNone(result.get('AccountId')) self.assertFalse(result.get('AccountBlacklisted')) self.assertNotIn('CognitoIdentityId', result) self.assertEqual(result.get('PlayerName'), name) account_id = result.get('AccountId') result = self.__service_get('/admin/accounts/{}'.format(account_id), admin_auth=True) self.assertEqual(result.get('CognitoUsername'), username) self.__assert_cognito_user_equals(result.get('IdentityProviders', {}).get(self.IDP_COGNITO, {}), self.TEST_ATTRIBUTES, username) self.assertEqual(result.get('AccountId'), account_id) self.assertFalse(result.get('AccountBlacklisted')) self.assertNotIn('CognitoIdentityId', result) self.assertEqual(result.get('PlayerName'), name) def __390_call_admin_create_account_with_existing_user(self): name = 'TestName' + str(randint(0,1000)) username = self.TEST_USERNAME_PREFIX + '-' + self.__generate_id() request = { 'CognitoUsername': username, 'PlayerName': name, 'IdentityProviders': { self.IDP_COGNITO: self.TEST_ATTRIBUTES } } self.aws_cognito_idp.admin_create_user( UserPoolId=self.context['user_pool_id'], Username=username, UserAttributes=[{'Name': 'email', 'Value': self.TEST_ATTRIBUTES['email']}], MessageAction='SUPPRESS' ) response = self.__service_post('/admin/accounts', request, admin_auth=True, expected_status_code=400) self.assertRegex(response, 'username already exists') def __395_cleanup_user_attributes(self): self.aws_cognito_idp.admin_delete_user_attributes( UserPoolId = self.context['user_pool_id'], Username = self.context['test_username'], UserAttributeNames = ["address", "birthdate", "family_name", "gender", "given_name", "locale", "middle_name", "nickname", "phone_number", "picture", "profile", "website", "zoneinfo"] ) self.aws_cognito_idp.admin_update_user_attributes( UserPoolId = self.context['user_pool_id'], Username = self.context['test_username'], UserAttributes=[ { 'Name': 'email', 'Value': self.TEST_EMAIL } ] ) # ------------------------------------------------ Admin Identity Provider User APIs ------------------------------------------------ def __400_call_admin_get_identity_provider_user(self): result = self.__service_get('/admin/identityProviders/{}/users/{}'.format(self.IDP_COGNITO, self.context['test_username']), admin_auth=True) self.__assert_cognito_user_equals(result, {'email': self.TEST_EMAIL}, self.context['test_username']) def __405_call_admin_get_identity_provider_user_for_non_exitent_account(self): self.__service_get('/admin/identityProviders/{}/users/{}'.format(self.IDP_COGNITO, 'non-existent'), admin_auth=True, expected_status_code=400) def __410_call_admin_get_identity_provider_user_for_invalid_provider(self): self.__service_get('/admin/identityProviders/{}/users/{}'.format('invalid', self.context['test_username']), admin_auth=True, expected_status_code=404) def __415_call_admin_get_identity_provider_user_without_identity(self): username = self.TEST_USERNAME_PREFIX + '-' + self.__generate_id() print('Creating user {} in pool {}'.format(username, self.context['user_pool_id'])) self.aws_cognito_idp.admin_create_user( UserPoolId=self.context['user_pool_id'], Username=username, UserAttributes=[{'Name': 'email', 'Value': self.TEST_EMAIL}], MessageAction='SUPPRESS' ) result = self.__service_get('/admin/identityProviders/{}/users/{}'.format(self.IDP_COGNITO, username), admin_auth=True) self.__assert_cognito_user_equals(result, {'email': self.TEST_EMAIL}, username) def __420_call_admin_get_identity_provider_user_with_player_credentials(self): self.__service_get('/admin/identityProviders/{}/users/{}'.format(self.IDP_COGNITO, self.context['test_username']), player_auth=True, expected_status_code=403) def __425_call_admin_get_identity_provider_user_with_no_credentials(self): self.__service_get('/admin/identityProviders/{}/users/{}'.format(self.IDP_COGNITO, self.context['test_username']), expected_status_code=403) def __430_call_admin_put_identity_provider_user_empty_request(self): request = { } result = self.__service_put('/admin/identityProviders/{}/users/{}'.format(self.IDP_COGNITO, self.context['test_username']), request, admin_auth=True) self.__assert_cognito_user_equals(result, {'email': self.TEST_EMAIL}, self.context['test_username']) self.assertFalse('address' in result) def __435_call_admin_put_identity_provider_user_partial_update(self): request = { 'address': 'test_address' } result = self.__service_put('/admin/identityProviders/{}/users/{}'.format(self.IDP_COGNITO, self.context['test_username']), request, admin_auth=True) self.__assert_cognito_user_equals(result, {'email': self.TEST_EMAIL, 'address': request['address']}, self.context['test_username']) def __440_call_admin_put_identity_provider_user_full_update(self): request = self.TEST_ATTRIBUTES result = self.__service_put('/admin/identityProviders/{}/users/{}'.format(self.IDP_COGNITO, self.context['test_username']), request, admin_auth=True) self.__assert_cognito_user_equals(result, request, self.context['test_username']) result = self.__service_get('/admin/identityProviders/{}/users/{}'.format(self.IDP_COGNITO, self.context['test_username']), admin_auth=True) self.__assert_cognito_user_equals(result, request, self.context['test_username']) def __445_call_admin_put_identity_provider_user_with_player_credentials(self): self.__service_put('/admin/identityProviders/{}/users/{}'.format(self.IDP_COGNITO, self.context['test_username']), {}, player_auth=True, expected_status_code=403) def __450_call_admin_put_identity_provider_user_with_no_credentials(self): self.__service_put('/admin/identityProviders/{}/users/{}'.format(self.IDP_COGNITO, self.context['test_username']), {}, expected_status_code=403) def __455_call_admin_confirm_signup(self): username = self.TEST_USERNAME_PREFIX + '-' + self.__generate_id() print('Creating user {} in pool {}'.format(username, self.context['user_pool_id'])) self.aws_cognito_idp.sign_up( ClientId=self.context['user_pool_client_id'], Username=username, Password=self.TEST_PASSWORD, UserAttributes=[ {'Name': 'email', 'Value': self.TEST_EMAIL} ] ) result = self.__service_get('/admin/identityProviders/{}/users/{}'.format(self.IDP_COGNITO, username), admin_auth=True) self.assertEqual('UNCONFIRMED', result.get('status')) self.__service_post('/admin/identityProviders/{}/users/{}/confirmSignUp'.format(self.IDP_COGNITO, username), {}, admin_auth=True) result = self.__service_get('/admin/identityProviders/{}/users/{}'.format(self.IDP_COGNITO, username), admin_auth=True) self.assertEqual('CONFIRMED', result.get('status')) def __460_call_admin_confirm_signup_with_player_credentials(self): self.__service_put('/admin/identityProviders/{}/users/{}/confirmSignUp'.format(self.IDP_COGNITO, self.context['test_username']), {}, player_auth=True, expected_status_code=403) def __465_call_admin_confirm_signup_with_no_credentials(self): self.__service_put('/admin/identityProviders/{}/users/{}/confirmSignUp'.format(self.IDP_COGNITO, self.context['test_username']), {}, expected_status_code=403) def __470_call_admin_reset_user_password(self): # Reset user password will only work on a user with a verified email address. # This test does not support reading email, so instead this test checks that it's not a 500 response. self.__service_post('/admin/identityProviders/{}/users/{}/resetUserPassword'.format(self.IDP_COGNITO, self.context['test_username']), {}, admin_auth=True, expected_status_code=400) def __475_call_admin_reset_user_password_with_player_credentials(self): self.__service_put('/admin/identityProviders/{}/users/{}/resetUserPassword'.format(self.IDP_COGNITO, self.context['test_username']), {}, player_auth=True, expected_status_code=403) def __480_call_admin_reset_user_password_with_no_credentials(self): self.__service_put('/admin/identityProviders/{}/users/{}/resetUserPassword'.format(self.IDP_COGNITO, self.context['test_username']), {}, expected_status_code=403) # ------------------------------------------------ Admin Identity Provider APIs ------------------------------------------------ def __500_call_admin_get_identity_provider(self): result = self.__service_get('/admin/identityProviders/{}'.format(self.IDP_COGNITO), admin_auth=True) self.assertIn('EstimatedNumberOfUsers', result) self.assertTrue(result['EstimatedNumberOfUsers'] > 0) def __505_call_admin_get_identity_provider_for_invalid_provider(self): self.__service_get('/admin/identityProviders/{}'.format('invalid'), admin_auth=True, expected_status_code=400) def __510_call_admin_get_identity_providerwith_player_credentials(self): self.__service_get('/admin/identityProviders/{}'.format(self.IDP_COGNITO), player_auth=True, expected_status_code=403) def __515_call_admin_get_identity_provider_with_no_credentials(self): self.__service_get('/admin/identityProviders/{}'.format(self.IDP_COGNITO), expected_status_code=403) # ------------------------------------------------ Admin Search API ------------------------------------------------ def __600_setup_search_test_data(self): self.__delete_all_users() self.__delete_all_accounts() # Add test accounts testAccounts = {} testAccounts['accountWithIdentity1'] = self.__create_account({'AccountId': 'accountWithIdentity1', 'CognitoIdentityId': 'identity1', 'AccountBlacklisted': True}, None) testAccounts['accountWithIdentity2'] = self.__create_account({'AccountId': 'accountWithIdentity2', 'CognitoIdentityId': 'identity2'}, None) testAccounts['accountWithInvalidUser1'] = self.__create_account({'AccountId': 'accountWithInvalidUser1', 'CognitoUsername': 'invalid1'}, None) testAccounts['accountWithInvalidUser2'] = self.__create_account({'AccountId': 'accountWithInvalidUser2', 'CognitoUsername': 'invalid2'}, None) testAccounts['accountWithPlayerName1'] = self.__create_account({'AccountId': 'accountWithPlayerName1', 'PlayerName': 'TestName1'}, None) testAccounts['accountWithPlayerName2'] = self.__create_account({'AccountId': 'accountWithPlayerName2', 'PlayerName': 'TestName2'}, None) testAccounts['accountWithUser1'] = self.__create_account({'AccountId': 'accountWithUser1'}, {'email': self.TEST_EMAIL}) testAccounts['accountWithUser2'] = self.__create_account({'AccountId': 'accountWithUser2'}, {'email': self.TEST_EMAIL}) testAccounts['duplicateUsername1'] = self.__create_account({'AccountId': 'duplicateUsername1', 'CognitoUsername': 'duplicate'}, {'email': self.TEST_EMAIL}) testAccounts['duplicateUsername2'] = self.__create_account({'AccountId': 'duplicateUsername2', 'CognitoUsername': 'duplicate'}, None) testAccounts['duplicateUsername2']['IdentityProviders'] = deepcopy(testAccounts['duplicateUsername1']['IdentityProviders']) testAccounts['emptyAccount'] = self.__create_account({'AccountId': 'emptyAccount'}, None) testAccounts['user1'] = self.__create_account(None, {'email': self.TEST_EMAIL}) testAccounts['user2'] = self.__create_account(None, {'email': self.TEST_EMAIL}) self.context['testAccounts'] = testAccounts time.sleep(10) # wait for cloud state to stabalize def __605_call_admin_account_search_no_parameters(self): result = self.__service_get('/admin/accountSearch', admin_auth=True) self.__assert_search_results_equal(result, [account for name, account in iteritems(self.context['testAccounts'])]) def __610_call_admin_account_search_with_start_name(self): result = self.__service_get('/admin/accountSearch', {'StartPlayerName': 'a'}, admin_auth=True) self.__assert_search_results_equal(result, [account for name, account in iteritems(self.context['testAccounts']) if 'PlayerName' in account]) def __615_call_admin_account_search_with_username(self): username = self.context['testAccounts']['accountWithUser1']['CognitoUsername'] result = self.__service_get('/admin/accountSearch', {'CognitoUsername': username}, admin_auth=True) self.__assert_search_results_equal(result, [account for name, account in iteritems(self.context['testAccounts']) if account.get('CognitoUsername') == username]) def __616_call_admin_account_search_with_username_prefix(self): username = self.context['testAccounts']['accountWithUser1']['CognitoUsername'][:4] result = self.__service_get('/admin/accountSearch', {'CognitoUsername': username}, admin_auth=True) self.__assert_search_results_equal(result, [account for name, account in iteritems(self.context['testAccounts']) if account.get('IdentityProviders', {}).get(self.IDP_COGNITO, {}).get('username', '').startswith(username)]) def __620_call_admin_account_search_with_invalid_username(self): username = self.context['testAccounts']['accountWithInvalidUser1']['CognitoUsername'] result = self.__service_get('/admin/accountSearch', {'CognitoUsername': username}, admin_auth=True) self.__assert_search_results_equal(result, []) def __625_call_admin_account_search_with_duplicate_username(self): username = self.context['testAccounts']['duplicateUsername1']['CognitoUsername'] result = self.__service_get('/admin/accountSearch', {'CognitoUsername': username}, admin_auth=True) self.__assert_search_results_equal(result, [self.context['testAccounts']['duplicateUsername1']]) def __630_call_admin_account_search_with_email(self): # The double quote should be stripped by the lambda. result = self.__service_get('/admin/accountSearch', {'Email': self.TEST_EMAIL + '"'}, admin_auth=True) self.__assert_search_results_equal(result, [account for name, account in iteritems(self.context['testAccounts']) if account.get('IdentityProviders', {}).get(self.IDP_COGNITO, {}).get('email') == self.TEST_EMAIL and name != 'duplicateUsername2']) def __631_call_admin_account_search_with_email_prefix(self): result = self.__service_get('/admin/accountSearch', {'Email': 'nobody'}, admin_auth=True) self.__assert_search_results_equal(result, [account for name, account in iteritems(self.context['testAccounts']) if account.get('IdentityProviders', {}).get(self.IDP_COGNITO, {}).get('email') == self.TEST_EMAIL and name != 'duplicateUsername2']) def __635_call_admin_account_search_with_identity_id(self): result = self.__service_get('/admin/accountSearch', {'CognitoIdentityId': 'identity1'}, admin_auth=True) self.__assert_search_results_equal(result, [account for name, account in iteritems(self.context['testAccounts']) if account.get('CognitoIdentityId') == 'identity1']) def __640_call_admin_account_search_with_player_credentials(self): self.__service_get('/admin/accountSearch', player_auth=True, expected_status_code=403) def __645_call_admin_account_search_with_no_credentials(self): self.__service_get('/admin/accountSearch', expected_status_code=403) def __650_create_pagination_test_accounts(self): self.__delete_all_accounts() for index in range(50): self.__create_account({'AccountId': 'testAccount{}'.format(index), 'PlayerName': 'Test{}'.format(str(index).rjust(2,'0'))}, None) def __655_player_name_search_pagination(self): def check_page_results(results, page_size, page_offset, has_next, has_previous): print(results) self.assertEqual('next' in results, has_next) self.assertEqual('previous' in results, has_previous) self.assertEqual(len(results['Accounts']), page_size) for index in range(page_size): self.assertEqual(results['Accounts'][index]['PlayerName'], 'Test{}'.format(str(index + page_offset).rjust(2,'0'))) # Get the first page. result1 = self.__service_get('/admin/accountSearch', {'StartPlayerName': ' '}, admin_auth=True) check_page_results(result1, 20, 0, has_next=True, has_previous=True) # Get the next two pages using next tokens. result2 = self.__service_get('/admin/accountSearch', {'PageToken': result1['next']}, admin_auth=True) check_page_results(result2, 20, 20, has_next=True, has_previous=True) result3 = self.__service_get('/admin/accountSearch', {'PageToken': result2['next']}, admin_auth=True) check_page_results(result3, 10, 40, has_next=False, has_previous=True) # Check the previous tokens. result2_previous = self.__service_get('/admin/accountSearch', {'PageToken': result2['previous']}, admin_auth=True) check_page_results(result2_previous, 20, 0, has_next=True, has_previous=False) result3_previous = self.__service_get('/admin/accountSearch', {'PageToken': result3['previous']}, admin_auth=True) check_page_results(result3_previous, 20, 20, has_next=True, has_previous=True) # ------------------------------------------------ C++ ------------------------------------------------ def __900_run_cpp_tests(self): if not os.environ.get("ENABLE_CLOUD_CANVAS_CPP_INTEGRATION_TESTS", None): print('\n*** SKIPPING cpp tests because the ENABLE_CLOUD_CANVAS_CPP_INTEGRATION_TESTS envionment variable is not set.\n') else: self.lmbr_aws('update-mappings', '--release', '-d', self.TEST_DEPLOYMENT_NAME) mappings_file = os.path.join(self.GAME_DIR, 'Config', self.TEST_DEPLOYMENT_NAME + '.player.awsLogicalMappings.json') print('Using mappings from {}'.format(mappings_file)) os.environ["cc_override_resource_map"] = mappings_file lmbr_test_cmd = os.path.join(self.REAL_ROOT_DIR, 'lmbr_test.cmd') args =[ lmbr_test_cmd, 'scan', # '--wait-for-debugger', # uncomment if the tests are failing and you want to debug them. '--integ', '--only', 'Gem.CloudGemPlayerAccount.fd4ea4ff80a64bb9a90e55b46e9539ef.v0.1.0.dll', '--dir', os.environ.get("TEST_BUILD_DIR", "Bin64vc141.Debug.Test") ] print('EXECUTING {}'.format(' '.join(args))) result = subprocess.call(args, shell=True) # Currently lmbr_test blows up when exiting. The tests all pass. # lbmr_test fails even if our tests do absolutely nothing, so it # seems to be an issue with the test infrastructure itself. # self.assertEquals(result, 0) # ------------------------------------------------ Logging ------------------------------------------------ def __950_check_logs_for_prohibited_content(self): prohibited_strings = [ self.TEST_EMAIL, self.TEST_ATTRIBUTES['email'], self.context['auth_tokens']['IdToken'], self.TEST_PASSWORD, self.context['anonymous_aws_credentials']['AccessKeyId'], self.context['anonymous_aws_credentials']['SecretKey'], self.context['anonymous_aws_credentials']['SessionToken'] ] print('Checking logs') found = False for log_group in self.__get_log_groups(): log_group_name = log_group['logGroupName'] print(' Log group: {}'.format(log_group_name)) for log_stream in self.__get_log_streams(log_group_name): log_stream_name = log_stream['logStreamName'] print(' Log stream: {}'.format(log_stream_name)) for event in GetLogEvents(self.aws_logs, log_group_name, log_stream_name): for value in prohibited_strings: find_result = event.get('message', '').find(value) if find_result >= 0: found = True print('Found "{}" that should not be logged in log group {} stream {} at {} position {}: {}'.format( value, log_group_name, log_stream_name, event.get('timestamp'), find_result, event.get('message') )) self.assertFalse(found, "Found strings in the logs that should not have been logged, see above.") # ------------------------------------------------ Cleanup ------------------------------------------------ def __999_cleanup(self): if self.FAST_TEST_RERUN: print('Tests passed enough to reach cleanup, failing in cleanup to prevent stack deletion since FAST_TEST_RERUN is true.') self.assertFalse(self.FAST_TEST_RERUN) self.teardown_base_stack() # ------------------------------------------------ Helpers ------------------------------------------------ def __get_service_url(self, path): base_url = self.get_stack_output(self.get_resource_group_stack_arn(self.TEST_DEPLOYMENT_NAME, self.GEM_NAME), 'ServiceUrl') self.assertIsNotNone(base_url, "Missing ServiceUrl stack output.") return base_url + path def __service_get(self, path, params=None, anonymous_auth=False, player_auth=False, player_credentials=None, admin_auth=False, expected_status_code=200): return self.__service_call('GET', path, params=params, anonymous_auth=anonymous_auth, player_auth=player_auth, player_credentials=player_credentials, admin_auth=admin_auth, expected_status_code=expected_status_code) def __service_put(self, path, body=None, anonymous_auth=False, player_auth=False, player_credentials=None, admin_auth=False, expected_status_code=200): return self.__service_call('PUT', path, body=body, anonymous_auth=anonymous_auth, player_auth=player_auth, player_credentials=player_credentials, admin_auth=admin_auth, expected_status_code=expected_status_code) def __service_post(self, path, body=None, anonymous_auth=False, player_auth=False, player_credentials=None, admin_auth=False, expected_status_code=200): return self.__service_call('POST', path, body=body, anonymous_auth=anonymous_auth, player_auth=player_auth, player_credentials=player_credentials, admin_auth=admin_auth, expected_status_code=expected_status_code) def __service_call(self, method, path, body=None, params=None, anonymous_auth=False, player_auth=False, player_credentials=None, admin_auth=False, assumed_role=None, expected_status_code=200): url = self.__get_service_url(path) if admin_auth: session_credentials = self.session.get_credentials().get_frozen_credentials() auth = AWS4Auth(session_credentials.access_key, session_credentials.secret_key, self.TEST_REGION, 'execute-api') elif anonymous_auth: creds = self.context['anonymous_aws_credentials'] auth = AWS4Auth(creds['AccessKeyId'], creds['SecretKey'], self.TEST_REGION, 'execute-api', session_token=creds['SessionToken']) elif player_credentials: auth = AWS4Auth(player_credentials['AccessKeyId'], player_credentials['SecretKey'], self.TEST_REGION, 'execute-api', session_token=player_credentials['SessionToken']) elif player_auth: creds = self.context['aws_credentials'] auth = AWS4Auth(creds['AccessKeyId'], creds['SecretKey'], self.TEST_REGION, 'execute-api', session_token=creds['SessionToken']) elif assumed_role: if assumed_role.startswith('Project'): role_arn = self.get_stack_resource_arn(self.get_project_stack_arn(), assumed_role) else: role_arn = self.get_stack_resource_arn(self.get_deployment_access_stack_arn(self.TEST_DEPLOYMENT_NAME), assumed_role) sts = self.session.client('sts') res = sts.assume_role(RoleArn=role_arn, RoleSessionName='CloudGemFrameworkTest') access_key = res['Credentials']['AccessKeyId'] secret_key = res['Credentials']['SecretAccessKey'] session_token = res['Credentials']['SessionToken'] auth = AWS4Auth(access_key, secret_key, self.TEST_REGION, 'execute-api', session_token=session_token) else: auth = None response = requests.request(method, url, auth=auth, json=body, params=params) self.assertEqual(response.status_code, expected_status_code, 'Expected status code {} but got {}, response: {}'.format(expected_status_code, response.status_code, response.text)) if response.status_code == 200: result = response.json().get('result', None) self.assertIsNotNone(result, "Missing 'result' in response: {}".format(response)) return result else: return response.text def __signup(self, username, password, email): self.aws_cognito_idp.sign_up( ClientId=self.context['user_pool_client_id'], Username=username, Password=password, UserAttributes=[ {'Name': 'email', 'Value': email} ] ) self.aws_cognito_idp.admin_confirm_sign_up(UserPoolId=self.context['user_pool_id'], Username=username) def __signin(self, username, password): challenge_response = self.aws_cognito_idp.initiate_auth( AuthFlow='CUSTOM_AUTH', AuthParameters={'USERNAME': username}, ClientId=self.context['user_pool_client_id'] ) self.assertEqual('BasicAuth', challenge_response.get('ChallengeParameters').get('type')) auth_response = self.aws_cognito_idp.respond_to_auth_challenge( ClientId=self.context['user_pool_client_id'], ChallengeName='CUSTOM_CHALLENGE', Session=challenge_response['Session'], ChallengeResponses={'USERNAME': username, 'ANSWER': password} ) self.assertIsNotNone(auth_response.get('AuthenticationResult').get('AccessToken')) return auth_response['AuthenticationResult'] def __create_account(self, account, user): result = {} username = None if user != None: if account and 'CognitoUsername' in account: username = account['CognitoUsername'] elif 'username' in user: username = user['username'] else: username = self.TEST_USERNAME_PREFIX + '-' + self.__generate_id() print('Creating user {} in pool {}'.format(username, self.context['user_pool_id'])) resultUser = user.copy() resultUser['username'] = username result['IdentityProviders'] = { self.IDP_COGNITO: resultUser } result['CognitoUsername'] = username updates = [] for key, value in iteritems(user): if key in self.COGNITO_ATTRIBUTES: updates.append({'Name': key, 'Value': value}) self.aws_cognito_idp.admin_create_user( UserPoolId=self.context['user_pool_id'], Username=username, UserAttributes=updates, MessageAction='SUPPRESS' ) accountId = None if account != None: accountId = account.get('AccountId', str(uuid.uuid4())) dynamoItem = { 'AccountId': {'S': accountId}, } result['AccountId'] = accountId if 'CognitoUsername' in account: dynamoItem['CognitoUsername'] = {'S': account['CognitoUsername']} result['CognitoUsername'] = account['CognitoUsername'] if 'CognitoIdentityId' in account: dynamoItem['CognitoIdentityId'] = {'S': account['CognitoIdentityId']} result['CognitoIdentityId'] = account['CognitoIdentityId'] if 'AccountBlacklisted' in account: dynamoItem['AccountBlacklisted'] = {'BOOL': account['AccountBlacklisted']} result['AccountBlacklisted'] = account['AccountBlacklisted'] elif username: dynamoItem['CognitoUsername'] = {'S': username} if 'PlayerName' in account: dynamoItem['PlayerName'] = {'S': account['PlayerName']} dynamoItem['IndexedPlayerName'] = {'S': account['PlayerName'].lower()} dynamoItem['PlayerNameSortKey'] = {'N': str(randint(1, 3))} result['PlayerName'] = account['PlayerName'] print('Creating account {}'.format(accountId)) self.aws_dynamo.put_item(TableName=self.context['accounts_table'], Item=dynamoItem) return result def __delete_all_users(self): listUsersResponse = self.aws_cognito_idp.list_users(UserPoolId=self.context['user_pool_id']) for user in listUsersResponse['Users']: self.aws_cognito_idp.admin_delete_user(UserPoolId=self.context['user_pool_id'], Username=user['Username']) print('Deleted user {}'.format(user['Username'])) def __delete_all_accounts(self): scanResponse = self.aws_dynamo.scan(TableName=self.context['accounts_table']) for account in scanResponse['Items']: self.aws_dynamo.delete_item(TableName=self.context['accounts_table'], Key={'AccountId': account['AccountId']}) print('Deleted account {}'.format(account['AccountId'])) def __get_identity_id(self, auth_tokens): logins = {self.context['user_pool_provider_id']: auth_tokens['IdToken']} identity_response = self.aws_cognito_identity.get_id(IdentityPoolId=self.context['identity_pool_id'], Logins=logins) return identity_response['IdentityId'] def __get_aws_credentials(self, identity_id, auth_tokens): logins = {self.context['user_pool_provider_id']: auth_tokens['IdToken']} response = self.aws_cognito_identity.get_credentials_for_identity(IdentityId=identity_id, Logins=logins) return { 'AccessKeyId': response['Credentials']['AccessKeyId'], 'SecretKey': response['Credentials']['SecretKey'], 'SessionToken': response['Credentials']['SessionToken'] } def __get_account_id(self, username): accounts = self.__service_get('/admin/accountSearch', {'CognitoUsername': username}, admin_auth=True).get('Accounts', []) self.assertEqual(len(accounts), 1) return accounts[0]['AccountId'] def __assert_username_is_correct(self, account): username = account.get('CognitoUsername') self.assertIsNotNone(username, "Missing 'CognitoUsername' in account, it should have been populated by the custom auth flow: {}".format(account)) self.assertEqual(username, self.context['test_username'], 'Expected username {} but got {}, it should have been populated by the custom auth flow'.format(self.context['test_username'], username)) def __assert_search_results_equal(self, actual, expectedResults): expected = deepcopy(expectedResults) expectedAccounts = {account['AccountId']:account for account in expected if 'AccountId' in account} expectedUsers = {account['CognitoUsername']:account for account in expected if 'AccountId' not in account and 'CognitoUsername' in account} for account in actual.get('Accounts', []): print('Checking account: {}'.format(account)) accountId = account.get('AccountId') if accountId: expectedAccount = expectedAccounts.get(accountId) self.assertFalse(expectedAccount.get('matched')) print('Expected: {}'.format(expectedAccount)) self.assertEqual(account.get('CognitoIdentityId'), expectedAccount.get('CognitoIdentityId')) self.assertEqual(account.get('PlayerName'), expectedAccount.get('PlayerName')) if 'CognitoUsername' in account: actualAttributes = account.get('IdentityProviders', {}).get(self.IDP_COGNITO, {}) expectedAttributes = expectedAccount.get('IdentityProviders', {}).get(self.IDP_COGNITO, {}) self.__assert_cognito_user_equals(actualAttributes, expectedAttributes, expectedAttributes.get('username')) expectedAccount['matched'] = True else: username = account.get('CognitoUsername') expectedUser = expectedUsers.get(username) self.assertIsNotNone(expectedUser, 'User {} should not have been in the search results.'.format(username)) self.assertFalse(expectedUser.get('matched')) print('Expected: {}'.format(expectedUser)) actualAttributes = account.get('IdentityProviders', {}).get(self.IDP_COGNITO, {}) expectedAttributes = expectedUser.get('IdentityProviders', {}).get(self.IDP_COGNITO, {}) self.__assert_cognito_user_equals(actualAttributes, expectedAttributes, expectedAttributes.get('username')) expectedUser['matched'] = True for accountId, account in iteritems(expectedAccounts): self.assertTrue(account.get('matched'), 'Account {} should have been in the search results'.format(accountId)) for username, user in iteritems(expectedUsers): self.assertTrue(user.get('matched'), 'User {} should have been in the search results'.format(username)) def __assert_cognito_user_equals(self, actual, expectedAttributes, username): time.sleep(3) # wait to allow cognito to refresh if not username: self.assertFalse(actual) else: self.assertEqual(actual['username'], username) self.assertTrue('status' in actual) self.assertTrue(actual['create_date'] > 0) self.assertTrue(actual['last_modified_date'] > 0) self.assertTrue(actual['enabled']) self.assertEqual(actual['IdentityProviderId'], self.IDP_COGNITO) for key, value in iteritems(expectedAttributes): self.assertEqual(actual[key], value) # Check that the standard cognito attributes were not present in the request if they were not expected. for attribute in self.COGNITO_ATTRIBUTES: if attribute not in expectedAttributes: self.assertNotIn(attribute, actual) def __generate_id(self): self.context['generator_sequence'] = self.context['generator_sequence'] + 1 return self.context['test_run_id'] + '-' + str(self.context['generator_sequence']) def __get_log_groups(self): log_prefix = '/aws/lambda/' + self.context['ProjectStackName'] response = self.aws_logs.describe_log_groups(logGroupNamePrefix=log_prefix) log_groups = response.get('logGroups', []) while 'nextToken' in response: response = self.aws_logs.describe_log_groups(logGroupNamePrefix=log_prefix, nextToken=response['nextToken']) log_groups.extend(response.get('logGroups', [])) return log_groups def __get_log_streams(self, log_group): response = self.aws_logs.describe_log_streams(logGroupName=log_group) log_streams = response.get('logStreams', []) while 'nextToken' in response: response = self.aws_logs.describe_log_streams(logGroupName=log_group, nextToken=response['nextToken']) log_streams.extend(response.get('logStreams', [])) return log_streams @classmethod def isrunnable(self, methodname, dict): if self.FAST_TEST_RERUN: return True return lmbr_aws_test_support.lmbr_aws_TestCase.isrunnable(methodname, dict) class GetLogEvents: def __init__(self, logs_client, log_group, log_stream): self.__logs_client = logs_client self.__log_group = log_group self.__log_stream = log_stream self.__initialized = False def __iter__(self): return self def __next__(self): if not self.__initialized: response = self.__logs_client.get_log_events(logGroupName=self.__log_group, logStreamName=self.__log_stream) self.__next_token = response.get('nextBackwardToken') self.__events = response.get('events', []) self.__initialized = True if not self.__events: response = self.__logs_client.get_log_events(logGroupName=self.__log_group, logStreamName=self.__log_stream, nextToken=self.__next_token) self.__next_token = response.get('nextBackwardToken') self.__events = response.get('events', []) if self.__events: return self.__events.pop() raise StopIteration