def delete_alias(self): alias_name = self.parameters['AliasName'] region = self.region if not alias_name.startswith('alias/'): raise JSONResponseError(400, 'Bad Request', body={ 'message': 'Invalid identifier', '__type': 'ValidationException' }) if not self.kms_backend.alias_exists(alias_name): raise NotFoundException( 400, 'Bad Request', body={ 'message': 'Alias arn:aws:kms:{region}:012345678912:{alias_name} is not found.' .format(**locals()), '__type': 'NotFoundException' }) self.kms_backend.delete_alias(alias_name) return json.dumps(None)
def generate_data_key(self, key_id, key_spec=None, number_of_bytes=None, encryption_context=None): if number_of_bytes: raise NotImplementedError if key_spec == 'AES_128': plaintext = os.urandom(16) elif key_spec == 'AES_256': plaintext = os.urandom(32) else: raise JSONResponseError( 400, 'Bad Request', body={ 'message': "Value '{}' at 'keySpec' failed to satisfy constraint: Member " "must satisfy enum value set: " "[AES_256, AES_128]".format(key_spec), '__type': 'InvalidCiphertextException' }) __, ciphertext = self.encrypt(key_id=key_id, plaintext=plaintext, encryption_context=encryption_context) return plaintext, key_id, ciphertext
def test_not_table(self, put_func, count_func, create_func, connect_func): """ Assert that tables that aren't found are created """ # Spit out the resource not found exception we get from AWS count_func.side_effect = [ 5, JSONResponseError( 400, "{'message': 'Requested resource not found: Table: T notfound', " "'__type': 'com.amazonaws.dynamodb.v20120810" "#ResourceNotFoundException'}") ] blk = DynamoDBInsert() self.configure_block(blk, {'log_level': 'DEBUG'}) # Make sure boto didn't create the table that was found blk._get_table('should_be_found') self.assertEqual(count_func.call_count, 1) self.assertEqual(create_func.call_count, 0) # Make sure boto tried to create the table blk._get_table('should_not_be_found') self.assertEqual(count_func.call_count, 2) self.assertEqual(create_func.call_count, 1) # Make sure the two tables are cached now self.assertIn('should_be_found', blk._table_cache) self.assertIn('should_not_be_found', blk._table_cache) # Subsequent get table calls should hit the cache, we shouldn't see # the create function or the count function get called again blk._get_table('should_be_found') blk._get_table('should_not_be_found') self.assertEqual(count_func.call_count, 2) self.assertEqual(create_func.call_count, 1)
def schedule_key_deletion(self): key_id = self.parameters.get('KeyId') if self.parameters.get('PendingWindowInDays') is None: pending_window_in_days = 30 else: pending_window_in_days = self.parameters.get('PendingWindowInDays') _assert_valid_key_id(self.kms_backend.get_key_id(key_id)) try: return json.dumps({ 'KeyId': key_id, 'DeletionDate': self.kms_backend.schedule_key_deletion(key_id, pending_window_in_days) }) except KeyError: raise JSONResponseError( 404, 'Not Found', body={ 'message': "Key 'arn:aws:kms:{region}:012345678912:key/{key_id}' does not exist" .format(region=self.region, key_id=key_id), '__type': 'NotFoundException' })
def _assert_default_policy(policy_name): if policy_name != 'default': raise JSONResponseError(404, 'Not Found', body={ 'message': "No such policy exists", '__type': 'NotFoundException' })
def se_api(foo, language): status = 400 reason = 'Bad Request' body = { 'message': 'AWS Premium Support Subscription is required to ' 'use this service.', '__type': 'SubscriptionRequiredException' } raise JSONResponseError(status, reason, body)
def cancel_key_deletion(self): key_id = self.parameters.get('KeyId') _assert_valid_key_id(self.kms_backend.get_key_id(key_id)) try: self.kms_backend.cancel_key_deletion(key_id) except KeyError: raise JSONResponseError(404, 'Not Found', body={ 'message': "Key 'arn:aws:kms:{region}:012345678912:key/{key_id}' does not exist".format(region=self.region, key_id=key_id), '__type': 'NotFoundException'}) return json.dumps({'KeyId': key_id})
def _assert_valid_key_id(key_id): if not re.match( r'^[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}$', key_id, re.IGNORECASE): raise JSONResponseError(404, 'Not Found', body={ 'message': ' Invalid keyId', '__type': 'NotFoundException' })
def is_not_dryrun(self, action): if 'true' in self.querystring.get('DryRun', ['false']): raise JSONResponseError( 400, 'DryRunOperation', body={ 'message': 'An error occurred (DryRunOperation) when calling the %s operation: Request would have succeeded, but DryRun flag is set' % action }) return True
def list_key_policies(self): key_id = self.parameters.get('KeyId') _assert_valid_key_id(self.kms_backend.get_key_id(key_id)) try: self.kms_backend.describe_key(key_id) except KeyError: raise JSONResponseError(404, 'Not Found', body={ 'message': "Key 'arn:aws:kms:{region}:012345678912:key/{key_id}' does not exist".format(region=self.region, key_id=key_id), '__type': 'NotFoundException'}) return json.dumps({'Truncated': False, 'PolicyNames': ['default']})
def get_key_policy(self): key_id = self.parameters.get('KeyId') policy_name = self.parameters.get('PolicyName') _assert_valid_key_id(self.kms_backend.get_key_id(key_id)) _assert_default_policy(policy_name) try: return json.dumps({'Policy': self.kms_backend.get_key_policy(key_id)}) except KeyError: raise JSONResponseError(404, 'Not Found', body={ 'message': "Key 'arn:aws:kms:{region}:012345678912:key/{key_id}' does not exist".format(region=self.region, key_id=key_id), '__type': 'NotFoundException'})
def create_alias(self): alias_name = self.parameters['AliasName'] target_key_id = self.parameters['TargetKeyId'] region = self.region if not alias_name.startswith('alias/'): raise JSONResponseError(400, 'Bad Request', body={'message': 'Invalid identifier', '__type': 'ValidationException'}) if alias_name in reserved_aliases: raise JSONResponseError(400, 'Bad Request', body={ '__type': 'NotAuthorizedException'}) if ':' in alias_name: raise JSONResponseError(400, 'Bad Request', body={ 'message': '{alias_name} contains invalid characters for an alias'.format(**locals()), '__type': 'ValidationException'}) if not re.match(r'^[a-zA-Z0-9:/_-]+$', alias_name): raise JSONResponseError(400, 'Bad Request', body={ 'message': "1 validation error detected: Value '{alias_name}' at 'aliasName' failed to satisfy constraint: Member must satisfy regular expression pattern: ^[a-zA-Z0-9:/_-]+$" .format(**locals()), '__type': 'ValidationException'}) if self.kms_backend.alias_exists(target_key_id): raise JSONResponseError(400, 'Bad Request', body={ 'message': 'Aliases must refer to keys. Not aliases', '__type': 'ValidationException'}) if self.kms_backend.alias_exists(alias_name): raise AlreadyExistsException(400, 'Bad Request', body={ 'message': 'An alias with the name arn:aws:kms:{region}:012345678912:{alias_name} already exists' .format(**locals()), '__type': 'AlreadyExistsException'}) self.kms_backend.add_alias(target_key_id, alias_name) return json.dumps(None)
def test_message_json_response_error(self): # This test comes from https://forums.aws.amazon.com/thread.jspa?messageID=374936 body = { '__type': 'com.amazon.coral.validate#ValidationException', 'message': 'The attempted filter operation is not supported ' 'for the provided filter argument count'} jre = JSONResponseError('400', 'Bad Request', body=body) self.assertEqual(jre.status, '400') self.assertEqual(jre.reason, 'Bad Request') self.assertEqual(jre.error_message, body['message']) self.assertEqual(jre.error_message, jre.message) self.assertEqual(jre.code, 'ValidationException') self.assertEqual(jre.code, jre.error_code)
def make_request(self, verb, resource, headers=None, data='', expected_status=None, params=None): if headers is None: headers = {} response = AWSAuthConnection.make_request(self, verb, resource, headers=headers, data=data, params=params) body = json.loads(response.read().decode('utf-8')) if response.status == expected_status: return body else: raise JSONResponseError(response.status, response.reason, body)
def decrypt(self): ciphertext = base64.b64decode(self.parameters.get('CiphertextBlob')) encryption_context = self.parameters.get('EncryptionContext') try: key_id, plaintext = self.kms_backend.decrypt( ciphertext, encryption_context) except KeyError: raise JSONResponseError( 400, 'Bad Request', body={ 'message': 'The specified ciphertext has been corrupted or is otherwise invalid.', '__type': 'InvalidCiphertextException' }) return json.dumps({ 'KeyId': key_id, 'Plaintext': base64.b64encode(plaintext) })
def test_table_lock(self, put_func, count_func, create_func, connect_func): """ Make sure that if a table is creating it locks """ # We should return the error that the table is not found. # We should only see this error returned once though, subsequent calls # should use the cached version of the table. count_func.side_effect = [ JSONResponseError( 400, "{'message': 'Requested resource not found: Table: T notfound', " "'__type': 'com.amazonaws.dynamodb.v20120810" "#ResourceNotFoundException'}") ] blk = SaveCounterDynamoDB() self.configure_block(blk, {'log_level': 'DEBUG', 'hash_key': 'hash'}) # Simulate a table that is creating for a while blk._get_table_status = MagicMock( side_effect=['CREATING', 'CREATING', 'ACTIVE']) # Send two threads to process signals at once spawn(blk.process_signals, [Signal({'hash': 'value1'})]) spawn(blk.process_signals, [Signal({'hash': 'value2'})]) # We shouldn't have any save calls until the table creates. # That takes 1.5 seconds, so let's see what we have after some of that. sleep(0.7) self.assertEqual(blk._count, 0) # Give the table time to create... sleep(1) # Make sure the table create function only gets called once. This # should happen due to the presence of the lock around _get_table self.assertEqual(create_func.call_count, 1) # Ok, it's created, we should see both signals get saved self.assertEqual(blk._count, 2)
def se_api(foo, language): status = 400 reason = 'foobar' body = {'message': 'other message', '__type': 'OtherException'} raise JSONResponseError(status, reason, body)