From ab9465494edf29e0ba89fc7dea694d865e0badcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=BAben=20Fonseca?= Date: Fri, 5 Aug 2022 12:11:20 +0200 Subject: [PATCH 1/3] fix(event_sources): add test for Function URL AuthZ --- .../data_classes/api_gateway_proxy_event.py | 12 +-- tests/events/lambdaFunctionUrlEvent.json | 95 +++++++++---------- tests/events/lambdaFunctionUrlIAMEvent.json | 52 ++++++++++ .../data_classes/test_lambda_function_url.py | 45 +++++++++ .../event_handler/test_lambda_function_url.py | 4 +- 5 files changed, 150 insertions(+), 58 deletions(-) create mode 100644 tests/events/lambdaFunctionUrlIAMEvent.json diff --git a/aws_lambda_powertools/utilities/data_classes/api_gateway_proxy_event.py b/aws_lambda_powertools/utilities/data_classes/api_gateway_proxy_event.py index 57c62f46b1a..efa15657670 100644 --- a/aws_lambda_powertools/utilities/data_classes/api_gateway_proxy_event.py +++ b/aws_lambda_powertools/utilities/data_classes/api_gateway_proxy_event.py @@ -123,26 +123,26 @@ def caller_id(self) -> Optional[str]: """The principal identifier of the caller making the request.""" return self.get("callerId") + def _cognito_identity(self) -> Dict: + return self.get("cognitoIdentity", {}) or {} + @property def cognito_amr(self) -> Optional[List[str]]: """This represents how the user was authenticated. AMR stands for Authentication Methods References as per the openid spec""" - cognito_identity = self["cognitoIdentity"] or {} # not available in FunctionURL - return cognito_identity.get("amr") + return self._cognito_identity().get("amr") @property def cognito_identity_id(self) -> Optional[str]: """The Amazon Cognito identity ID of the caller making the request. Available only if the request was signed with Amazon Cognito credentials.""" - cognito_identity = self.get("cognitoIdentity") or {} # not available in FunctionURL - return cognito_identity.get("identityId") + return self._cognito_identity().get("identityId") @property def cognito_identity_pool_id(self) -> Optional[str]: """The Amazon Cognito identity pool ID of the caller making the request. Available only if the request was signed with Amazon Cognito credentials.""" - cognito_identity = self.get("cognitoIdentity") or {} # not available in FunctionURL - return cognito_identity.get("identityPoolId") + return self._cognito_identity().get("identityPoolId") @property def principal_org_id(self) -> Optional[str]: diff --git a/tests/events/lambdaFunctionUrlEvent.json b/tests/events/lambdaFunctionUrlEvent.json index bf52342b66d..da5c133e6f8 100644 --- a/tests/events/lambdaFunctionUrlEvent.json +++ b/tests/events/lambdaFunctionUrlEvent.json @@ -1,52 +1,47 @@ { - "version": "2.0", - "routeKey": "$default", - "rawPath": "/my/path", - "rawQueryString": "parameter1=value1¶meter1=value2¶meter2=value", - "cookies": [ - "cookie1", - "cookie2" - ], - "headers": { - "header1": "value1", - "header2": "value1,value2" - }, - "queryStringParameters": { - "parameter1": "value1,value2", - "parameter2": "value" - }, - "requestContext": { - "accountId": "123456789012", - "apiId": "", - "authentication": null, - "authorizer": { - "iam": { - "accessKey": "AKIA...", - "accountId": "111122223333", - "callerId": "AIDA...", - "cognitoIdentity": null, - "principalOrgId": null, - "userArn": "arn:aws:iam::111122223333:user/example-user", - "userId": "AIDA..." - } - }, - "domainName": ".lambda-url.us-west-2.on.aws", - "domainPrefix": "", - "http": { - "method": "POST", - "path": "/my/path", - "protocol": "HTTP/1.1", - "sourceIp": "123.123.123.123", - "userAgent": "agent" - }, - "requestId": "id", - "routeKey": "$default", - "stage": "$default", - "time": "12/Mar/2020:19:03:58 +0000", - "timeEpoch": 1583348638390 - }, - "body": "Hello from client!", - "pathParameters": null, - "isBase64Encoded": false, - "stageVariables": null + "version":"2.0", + "routeKey":"$default", + "rawPath":"/", + "rawQueryString":"", + "headers":{ + "sec-fetch-mode":"navigate", + "x-amzn-tls-version":"TLSv1.2", + "sec-fetch-site":"cross-site", + "accept-language":"pt-BR,pt;q=0.9", + "x-forwarded-proto":"https", + "x-forwarded-port":"443", + "x-forwarded-for":"123.123.123.123", + "sec-fetch-user":"?1", + "accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", + "x-amzn-tls-cipher-suite":"ECDHE-RSA-AES128-GCM-SHA256", + "sec-ch-ua":"\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"102\", \"Google Chrome\";v=\"102\"", + "sec-ch-ua-mobile":"?0", + "x-amzn-trace-id":"Root=1-62ecd163-5f302e550dcde3b12402207d", + "sec-ch-ua-platform":"\"Linux\"", + "host":".lambda-url.us-east-1.on.aws", + "upgrade-insecure-requests":"1", + "cache-control":"max-age=0", + "accept-encoding":"gzip, deflate, br", + "sec-fetch-dest":"document", + "user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36" + }, + "requestContext":{ + "accountId":"anonymous", + "apiId":"", + "domainName":".lambda-url.us-east-1.on.aws", + "domainPrefix":"", + "http":{ + "method":"GET", + "path":"/", + "protocol":"HTTP/1.1", + "sourceIp":"123.123.123.123", + "userAgent":"agent" + }, + "requestId":"id", + "routeKey":"$default", + "stage":"$default", + "time":"05/Aug/2022:08:14:39 +0000", + "timeEpoch":1659687279885 + }, + "isBase64Encoded":false } diff --git a/tests/events/lambdaFunctionUrlIAMEvent.json b/tests/events/lambdaFunctionUrlIAMEvent.json new file mode 100644 index 00000000000..bf52342b66d --- /dev/null +++ b/tests/events/lambdaFunctionUrlIAMEvent.json @@ -0,0 +1,52 @@ +{ + "version": "2.0", + "routeKey": "$default", + "rawPath": "/my/path", + "rawQueryString": "parameter1=value1¶meter1=value2¶meter2=value", + "cookies": [ + "cookie1", + "cookie2" + ], + "headers": { + "header1": "value1", + "header2": "value1,value2" + }, + "queryStringParameters": { + "parameter1": "value1,value2", + "parameter2": "value" + }, + "requestContext": { + "accountId": "123456789012", + "apiId": "", + "authentication": null, + "authorizer": { + "iam": { + "accessKey": "AKIA...", + "accountId": "111122223333", + "callerId": "AIDA...", + "cognitoIdentity": null, + "principalOrgId": null, + "userArn": "arn:aws:iam::111122223333:user/example-user", + "userId": "AIDA..." + } + }, + "domainName": ".lambda-url.us-west-2.on.aws", + "domainPrefix": "", + "http": { + "method": "POST", + "path": "/my/path", + "protocol": "HTTP/1.1", + "sourceIp": "123.123.123.123", + "userAgent": "agent" + }, + "requestId": "id", + "routeKey": "$default", + "stage": "$default", + "time": "12/Mar/2020:19:03:58 +0000", + "timeEpoch": 1583348638390 + }, + "body": "Hello from client!", + "pathParameters": null, + "isBase64Encoded": false, + "stageVariables": null +} diff --git a/tests/functional/data_classes/test_lambda_function_url.py b/tests/functional/data_classes/test_lambda_function_url.py index cbd4a64eb45..e2ff1805226 100644 --- a/tests/functional/data_classes/test_lambda_function_url.py +++ b/tests/functional/data_classes/test_lambda_function_url.py @@ -8,6 +8,51 @@ def test_lambda_function_url_event(): assert event.version == "2.0" assert event.route_key == "$default" + assert event.path == "/" + assert event.raw_query_string == "" + + assert event.cookies is None + + headers = event.headers + assert len(headers) == 20 + + assert event.query_string_parameters is None + + assert event.is_base64_encoded is False + assert event.body is None + assert event.path_parameters is None + assert event.stage_variables is None + assert event.http_method == "GET" + + request_context = event.request_context + + assert request_context.account_id == "anonymous" + assert request_context.api_id is not None + assert request_context.domain_name == ".lambda-url.us-east-1.on.aws" + assert request_context.domain_prefix == "" + assert request_context.request_id == "id" + assert request_context.route_key == "$default" + assert request_context.stage == "$default" + assert request_context.time is not None + assert request_context.time_epoch == 1659687279885 + assert request_context.authentication is None + + http = request_context.http + assert http.method == "GET" + assert http.path == "/" + assert http.protocol == "HTTP/1.1" + assert http.source_ip == "123.123.123.123" + assert http.user_agent == "agent" + + assert request_context.authorizer is None + + +def test_lambda_function_url_event_iam(): + event = LambdaFunctionUrlEvent(load_event("lambdaFunctionUrlIAMEvent.json")) + + assert event.version == "2.0" + assert event.route_key == "$default" + assert event.path == "/my/path" assert event.raw_query_string == "parameter1=value1¶meter1=value2¶meter2=value" diff --git a/tests/functional/event_handler/test_lambda_function_url.py b/tests/functional/event_handler/test_lambda_function_url.py index e4831754856..dc00c535580 100644 --- a/tests/functional/event_handler/test_lambda_function_url.py +++ b/tests/functional/event_handler/test_lambda_function_url.py @@ -15,7 +15,7 @@ def foo(): return Response(200, content_types.TEXT_HTML, "foo") # WHEN calling the event handler - result = app(load_event("lambdaFunctionUrlEvent.json"), {}) + result = app(load_event("lambdaFunctionUrlIAMEvent.json"), {}) # THEN process event correctly # AND set the current_event type as LambdaFunctionUrlEvent @@ -33,7 +33,7 @@ def foo(): raise RuntimeError() # WHEN calling the event handler - result = app(load_event("lambdaFunctionUrlEvent.json"), {}) + result = app(load_event("lambdaFunctionUrlIAMEvent.json"), {}) # THEN process event correctly # AND return 404 because the event doesn't match any known route From 4fdf74e1d43141c073fa1aa0d3d00e04cf8fa8b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=BAben=20Fonseca?= Date: Fri, 5 Aug 2022 12:14:17 +0200 Subject: [PATCH 2/3] chore(event_sources): re-add deleted comment about function urls. --- .../utilities/data_classes/api_gateway_proxy_event.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws_lambda_powertools/utilities/data_classes/api_gateway_proxy_event.py b/aws_lambda_powertools/utilities/data_classes/api_gateway_proxy_event.py index efa15657670..be374aba398 100644 --- a/aws_lambda_powertools/utilities/data_classes/api_gateway_proxy_event.py +++ b/aws_lambda_powertools/utilities/data_classes/api_gateway_proxy_event.py @@ -124,7 +124,7 @@ def caller_id(self) -> Optional[str]: return self.get("callerId") def _cognito_identity(self) -> Dict: - return self.get("cognitoIdentity", {}) or {} + return self.get("cognitoIdentity", {}) or {} # not available in FunctionURL @property def cognito_amr(self) -> Optional[List[str]]: From c6b5a3b025c353b8f68301d337d479183285f26d Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Fri, 5 Aug 2022 14:04:04 +0200 Subject: [PATCH 3/3] fix(tests): missing cognito_amr property --- tests/functional/data_classes/test_lambda_function_url.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/functional/data_classes/test_lambda_function_url.py b/tests/functional/data_classes/test_lambda_function_url.py index e2ff1805226..c27920c3392 100644 --- a/tests/functional/data_classes/test_lambda_function_url.py +++ b/tests/functional/data_classes/test_lambda_function_url.py @@ -105,6 +105,7 @@ def test_lambda_function_url_event_iam(): assert iam.access_key is not None assert iam.account_id == "111122223333" assert iam.caller_id is not None + assert iam.cognito_amr is None assert iam.cognito_identity_id is None assert iam.cognito_identity_pool_id is None assert iam.principal_org_id is None