def return_response(self, method, path, data, headers, response): # fix backend issue (missing support for API documentation) if re.match(r'/restapis/[^/]+/documentation/versions', path): if response.status_code == 404: return requests_response({'position': '1', 'items': []}) # add missing implementations if response.status_code == 404: data = data and json.loads(to_str(data)) result = None if path == '/account': result = handle_accounts(method, path, data, headers) if re.match(PATH_REGEX_PATH_MAPPINGS, path): result = hande_base_path_mappings(method, path, data, headers) if result is not None: response.status_code = 200 aws_responses.set_response_content(response, result) # publish event if method == 'POST' and path == '/restapis': content = json.loads(to_str(response.content)) event_publisher.fire_event(event_publisher.EVENT_APIGW_CREATE_API, payload={'a': event_publisher.get_hash(content['id'])}) api_regex = r'^/restapis/([a-zA-Z0-9\-]+)$' if method == 'DELETE' and re.match(api_regex, path): api_id = re.sub(api_regex, r'\1', path) event_publisher.fire_event(event_publisher.EVENT_APIGW_DELETE_API, payload={'a': event_publisher.get_hash(api_id)})
def search_key_pair(data, response): key_pairs = KMSBackend.get().key_pairs key = key_pairs.get(data.get("KeyId")) if not key: return response key_object = Key(key["Policy"], key["KeyUsage"], key["KeySpec"], key["Description"], key["Region"]) key_object.id = key["KeyId"] response.status_code = 200 set_response_content(response, json.dumps(key_object.to_dict())) return response
def add_key_pairs(response): key_pairs = KMSBackend.get().key_pairs response.status_code = 200 content = json.loads(to_str(response.content)) prev_keys = content["Keys"] for id in key_pairs: prev_keys.append({ "KeyId": key_pairs[id]["KeyId"], "KeyArn": key_pairs[id]["Arn"], }) content["Keys"] = prev_keys set_response_content(response, json.dumps(content)) return response
def handle_get_public_key(data, response): key_pairs = _get_key_pairs() result = key_pairs.get(data.get("KeyId", "")) if not result: return 404 attrs = [ "KeyId", "PublicKey", "KeySpec", "KeyUsage", "EncryptionAlgorithms", "SigningAlgorithms", ] result = select_attributes(result, attrs) set_response_content(response, result) response.status_code = 200 return response
def return_response(self, method, path, data, headers, response): # fix backend issue (missing support for API documentation) if re.match(r"/restapis/[^/]+/documentation/versions", path): if response.status_code == 404: return requests_response({"position": "1", "items": []}) # add missing implementations if response.status_code == 404: data = data and json.loads(to_str(data)) result = None if path == "/account": result = handle_accounts(method, path, data, headers) elif path.startswith("/vpclinks"): result = handle_vpc_links(method, path, data, headers) elif re.match(PATH_REGEX_PATH_MAPPINGS, path): result = handle_base_path_mappings(method, path, data, headers) elif re.match(PATH_REGEX_CLIENT_CERTS, path): result = handle_client_certificates(method, path, data, headers) if result is not None: response.status_code = 200 aws_responses.set_response_content( response, result, getattr(result, "headers", {})) # keep track of API regions for faster lookup later on if method == "POST" and path == "/restapis": content = json.loads(to_str(response.content)) api_id = content["id"] region = aws_stack.extract_region_from_auth_header(headers) API_REGIONS[api_id] = region # publish event if method == "POST" and path == "/restapis": content = json.loads(to_str(response.content)) event_publisher.fire_event( event_publisher.EVENT_APIGW_CREATE_API, payload={"a": event_publisher.get_hash(content["id"])}, ) api_regex = r"^/restapis/([a-zA-Z0-9\-]+)$" if method == "DELETE" and re.match(api_regex, path): api_id = re.sub(api_regex, r"\1", path) event_publisher.fire_event( event_publisher.EVENT_APIGW_DELETE_API, payload={"a": event_publisher.get_hash(api_id)}, )
def add_vpc_info_to_response(path: str, response: Response): content = to_str(response.content or "") if "<HostedZone>" not in content: return if "GetHostedZoneResponse" not in content and "CreateHostedZoneResponse" not in content: return content = clone(xmltodict.parse(content)) region_details = Route53Backend.get() def _insert(obj, **_): if not isinstance(obj, dict) or "HostedZone" not in obj or "VPCs" in obj: return obj zone_id = obj["HostedZone"].get("Id", "").replace("/hostedzone/", "") zone_details = region_details.vpc_hosted_zone_associations.get(zone_id) or [] vpcs = [zone["VPC"] for zone in zone_details if zone.get("VPC")] if vpcs: obj["VPCs"] = [{"VPC": vpc} for vpc in vpcs] return obj recurse_object(content, _insert) set_response_content(response, xmltodict.unparse(content))
def sign(data, response): region_details = KMSBackend.get() response.status_code = 200 algo = data.get("SigningAlgorithm") key_id = data.get("KeyId") message = base64.b64decode(to_bytes(data.get("Message"))) key_pair = region_details.key_pairs.get(key_id) kwargs = {} if algo.startswith("RSA"): if "PKCS" in algo: kwargs["padding"] = padding.PKCS1v15() elif "PSS" in algo: kwargs["padding"] = padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH) else: LOG.warning("Unsupported padding in SigningAlgorithm '%s'", algo) if "SHA_256" in algo: kwargs["algorithm"] = hashes.SHA256() elif "SHA_384" in algo: kwargs["algorithm"] = hashes.SHA384() elif "SHA_512" in algo: kwargs["algorithm"] = hashes.SHA512() else: LOG.warning("Unsupported hash type in SigningAlgorithm '%s'", algo) if algo.startswith("ECDSA"): kwargs["signature_algorithm"] = ec.ECDSA( algorithm=kwargs.pop("algorithm", None)) # generate signature signature = key_pair["_key_"].sign(data=message, **kwargs) result = { "KeyId": key_id, "Signature": to_str(base64.b64encode(signature)), "SigningAlgorithm": algo, } set_response_content(response, json.dumps(result)) return response
def return_response(self, method, path, data, headers, response): data = json.loads(to_str(data or "{}")) name = data.get("name") or (data.get("stateMachineArn") or "").split(":")[-1] target = headers.get("X-Amz-Target", "").split(".")[-1] # publish event if target == "CreateStateMachine": event_publisher.fire_event( event_publisher.EVENT_STEPFUNCTIONS_CREATE_SM, payload={"m": event_publisher.get_hash(name)}, ) elif target == "DeleteStateMachine": event_publisher.fire_event( event_publisher.EVENT_STEPFUNCTIONS_DELETE_SM, payload={"m": event_publisher.get_hash(name)}, ) content = to_str(response.content or "") or "{}" replace = r"\1:\7:\3:\8" content = re.sub(SM_ARN_REGEX, replace, content) content = json.loads(content) def fix_name(obj): if obj.get("name"): obj["name"] = re.sub(r"^([^_]+)_(.*)", r"\2", obj["name"]) fix_name(content) machines = content.get("stateMachines") if machines: region_part = ":%s:" % aws_stack.get_region() machines = [sm for sm in machines if region_part in sm["stateMachineArn"]] for machine in machines: fix_name(machine) content["stateMachines"] = machines content = json.dumps(content) set_response_content(response, content)
def generate_data_key_pair_without_plaintext(data, response): result = _generate_data_key_pair(data) result.pop("PrivateKeyPlaintext", None) set_response_content(response, result) response.status_code = 200 return response
def generate_data_key_pair(data, response): result = _generate_data_key_pair(data) set_response_content(response, result) response.status_code = 200 return response
def update_response_content(response, content, status_code=None): aws_responses.set_response_content(response, content) if status_code: response.status_code = status_code fix_headers_for_updated_response(response)