From 721fbaf0d3e52ed9148a820a80223be1fc0e6f57 Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Tue, 5 Dec 2023 10:56:29 +0000 Subject: [PATCH 1/7] Removing unecessary code --- .../data_classes/api_gateway_proxy_event.py | 5 ----- .../utilities/parser/models/apigwv2.py | 3 +-- .../apiGatewayProxyV2LambdaAuthorizerEvent.json | 14 ++++++++++---- .../data_classes/test_api_gateway_proxy_event.py | 11 ++++++++--- .../unit/data_classes/test_lambda_function_url.py | 1 - tests/unit/parser/test_apigwv2.py | 11 ++++++++--- tests/unit/parser/test_lambda_function_url.py | 1 - 7 files changed, 27 insertions(+), 19 deletions(-) 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 030d9739fa4..38ae970334b 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 @@ -179,11 +179,6 @@ def jwt_scopes(self) -> Optional[List[str]]: jwt = self.get("jwt") or {} # not available in FunctionURL return jwt.get("scopes") - @property - def get_lambda(self) -> Optional[Dict[str, Any]]: - """Lambda authorization context details""" - return self.get("lambda") - @property def iam(self) -> Optional[RequestContextV2AuthorizerIam]: """IAM authorization details used for making the request.""" diff --git a/aws_lambda_powertools/utilities/parser/models/apigwv2.py b/aws_lambda_powertools/utilities/parser/models/apigwv2.py index 8f0f8dbf50c..9d40b63fa4c 100644 --- a/aws_lambda_powertools/utilities/parser/models/apigwv2.py +++ b/aws_lambda_powertools/utilities/parser/models/apigwv2.py @@ -1,7 +1,7 @@ from datetime import datetime from typing import Any, Dict, List, Optional, Type, Union -from pydantic import BaseModel, Field +from pydantic import BaseModel from pydantic.networks import IPvAnyNetwork from aws_lambda_powertools.utilities.parser.types import Literal @@ -31,7 +31,6 @@ class RequestContextV2AuthorizerJwt(BaseModel): class RequestContextV2Authorizer(BaseModel): jwt: Optional[RequestContextV2AuthorizerJwt] = None iam: Optional[RequestContextV2AuthorizerIam] = None - lambda_value: Optional[Dict[str, Any]] = Field(None, alias="lambda") class RequestContextV2Http(BaseModel): diff --git a/tests/events/apiGatewayProxyV2LambdaAuthorizerEvent.json b/tests/events/apiGatewayProxyV2LambdaAuthorizerEvent.json index cae3130de80..2df1321d63f 100644 --- a/tests/events/apiGatewayProxyV2LambdaAuthorizerEvent.json +++ b/tests/events/apiGatewayProxyV2LambdaAuthorizerEvent.json @@ -24,10 +24,16 @@ "stage": "$default", "requestId": "id", "authorizer": { - "lambda": { - "key": "value" + "jwt": { + "claims": { + "claim1": "value1" + }, + "scopes": [ + "scope1", + "scope2" + ] } - }, + }, "apiId": "api-id", "domainName": "id.execute-api.us-east-1.amazonaws.com", "domainPrefix": "id", @@ -47,4 +53,4 @@ }, "body": "{\r\n\t\"a\": 1\r\n}", "isBase64Encoded": false -} \ No newline at end of file +} diff --git a/tests/unit/data_classes/test_api_gateway_proxy_event.py b/tests/unit/data_classes/test_api_gateway_proxy_event.py index 197b8676613..ee2ad820f49 100644 --- a/tests/unit/data_classes/test_api_gateway_proxy_event.py +++ b/tests/unit/data_classes/test_api_gateway_proxy_event.py @@ -200,9 +200,14 @@ def test_api_gateway_proxy_v2_lambda_authorizer_event(): request_context = parsed_event.request_context assert request_context is not None - lambda_props = request_context.authorizer.get_lambda - assert lambda_props is not None - assert lambda_props.get("key") == "value" + jwt_claims = request_context.authorizer.jwt_claim + assert jwt_claims is not None + assert jwt_claims.get("claim1") == raw_event["requestContext"]["authorizer"]["jwt"]["claims"]["claim1"] + + jwt_scopes = request_context.authorizer.jwt_scopes + assert jwt_scopes is not None + assert jwt_scopes[0] == raw_event["requestContext"]["authorizer"]["jwt"]["scopes"][0] + assert jwt_scopes[1] == raw_event["requestContext"]["authorizer"]["jwt"]["scopes"][1] def test_api_gateway_proxy_v2_iam_event(): diff --git a/tests/unit/data_classes/test_lambda_function_url.py b/tests/unit/data_classes/test_lambda_function_url.py index b7e8003d6c7..374383cd415 100644 --- a/tests/unit/data_classes/test_lambda_function_url.py +++ b/tests/unit/data_classes/test_lambda_function_url.py @@ -104,7 +104,6 @@ def test_lambda_function_url_event_iam(): assert authorizer is not None assert authorizer.jwt_claim is None assert authorizer.jwt_scopes is None - assert authorizer.get_lambda is None iam = authorizer.iam iam_raw = raw_event["requestContext"]["authorizer"]["iam"] diff --git a/tests/unit/parser/test_apigwv2.py b/tests/unit/parser/test_apigwv2.py index b52bad28b40..399267eab2b 100644 --- a/tests/unit/parser/test_apigwv2.py +++ b/tests/unit/parser/test_apigwv2.py @@ -77,9 +77,14 @@ def test_api_gateway_proxy_v2_event_lambda_authorizer(): request_context: RequestContextV2 = parsed_event.requestContext assert request_context is not None - lambda_props: RequestContextV2Authorizer = request_context.authorizer.lambda_value - assert lambda_props is not None - assert lambda_props["key"] == raw_event["requestContext"]["authorizer"]["lambda"]["key"] + jwt_claims: RequestContextV2Authorizer = request_context.authorizer.jwt.claims + assert jwt_claims is not None + assert jwt_claims["claim1"] == raw_event["requestContext"]["authorizer"]["jwt"]["claims"]["claim1"] + + jwt_scopes: RequestContextV2Authorizer = request_context.authorizer.jwt.scopes + assert jwt_scopes is not None + assert jwt_scopes[0] == raw_event["requestContext"]["authorizer"]["jwt"]["scopes"][0] + assert jwt_scopes[1] == raw_event["requestContext"]["authorizer"]["jwt"]["scopes"][1] def test_api_gateway_proxy_v2_event_iam_authorizer(): diff --git a/tests/unit/parser/test_lambda_function_url.py b/tests/unit/parser/test_lambda_function_url.py index 3b1a7f259ec..a9148659134 100644 --- a/tests/unit/parser/test_lambda_function_url.py +++ b/tests/unit/parser/test_lambda_function_url.py @@ -113,7 +113,6 @@ def test_lambda_function_url_event_iam(): authorizer = request_context.authorizer assert authorizer is not None assert authorizer.jwt is None - assert authorizer.lambda_value is None iam = authorizer.iam iam_raw = raw_event["requestContext"]["authorizer"]["iam"] From 2ea8114349602cb79ae6d653baffd3b76a12e28a Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Wed, 6 Dec 2023 15:16:11 +0000 Subject: [PATCH 2/7] Reverting deletion + adding get_context function --- .../data_classes/api_gateway_proxy_event.py | 25 +++++++++++++++++++ .../utilities/parser/models/apigwv2.py | 3 ++- ...piGatewayProxyV2LambdaAuthorizerEvent.json | 3 +++ .../test_api_gateway_proxy_event.py | 5 ++++ .../data_classes/test_lambda_function_url.py | 1 + tests/unit/parser/test_apigwv2.py | 4 +++ 6 files changed, 40 insertions(+), 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 38ae970334b..37797632422 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 @@ -74,6 +74,16 @@ def route_key(self) -> Optional[str]: def authorizer(self) -> APIGatewayEventAuthorizer: return APIGatewayEventAuthorizer(self._data["requestContext"]["authorizer"]) + def get_context(self) -> Optional[Dict[str, Any]]: + """Retrieve the authorization context details for Lambda. + + Returns: + -------- + Optional[Dict[str, Any]] + A dictionary containing Lambda authorization context details, or None if the information is not available. + """ + return self.get("requestContext", {}).get("authorizer", {}) + class APIGatewayProxyEvent(BaseProxyEvent): """AWS Lambda proxy V1 @@ -179,6 +189,21 @@ def jwt_scopes(self) -> Optional[List[str]]: jwt = self.get("jwt") or {} # not available in FunctionURL return jwt.get("scopes") + @property + def get_lambda(self) -> Optional[Dict[str, Any]]: + """Lambda authorization context details""" + return self.get("lambda") + + def get_context(self) -> Optional[Dict[str, Any]]: + """Retrieve the authorization context details for Lambda. + + Returns: + -------- + Optional[Dict[str, Any]] + A dictionary containing Lambda authorization context details, or None if the information is not available. + """ + return self.get("lambda") + @property def iam(self) -> Optional[RequestContextV2AuthorizerIam]: """IAM authorization details used for making the request.""" diff --git a/aws_lambda_powertools/utilities/parser/models/apigwv2.py b/aws_lambda_powertools/utilities/parser/models/apigwv2.py index 9d40b63fa4c..8f0f8dbf50c 100644 --- a/aws_lambda_powertools/utilities/parser/models/apigwv2.py +++ b/aws_lambda_powertools/utilities/parser/models/apigwv2.py @@ -1,7 +1,7 @@ from datetime import datetime from typing import Any, Dict, List, Optional, Type, Union -from pydantic import BaseModel +from pydantic import BaseModel, Field from pydantic.networks import IPvAnyNetwork from aws_lambda_powertools.utilities.parser.types import Literal @@ -31,6 +31,7 @@ class RequestContextV2AuthorizerJwt(BaseModel): class RequestContextV2Authorizer(BaseModel): jwt: Optional[RequestContextV2AuthorizerJwt] = None iam: Optional[RequestContextV2AuthorizerIam] = None + lambda_value: Optional[Dict[str, Any]] = Field(None, alias="lambda") class RequestContextV2Http(BaseModel): diff --git a/tests/events/apiGatewayProxyV2LambdaAuthorizerEvent.json b/tests/events/apiGatewayProxyV2LambdaAuthorizerEvent.json index 2df1321d63f..63fd226c730 100644 --- a/tests/events/apiGatewayProxyV2LambdaAuthorizerEvent.json +++ b/tests/events/apiGatewayProxyV2LambdaAuthorizerEvent.json @@ -32,6 +32,9 @@ "scope1", "scope2" ] + }, + "lambda": { + "tenantId": "123-456-789-012" } }, "apiId": "api-id", diff --git a/tests/unit/data_classes/test_api_gateway_proxy_event.py b/tests/unit/data_classes/test_api_gateway_proxy_event.py index ee2ad820f49..be6591ad814 100644 --- a/tests/unit/data_classes/test_api_gateway_proxy_event.py +++ b/tests/unit/data_classes/test_api_gateway_proxy_event.py @@ -200,6 +200,11 @@ def test_api_gateway_proxy_v2_lambda_authorizer_event(): request_context = parsed_event.request_context assert request_context is not None + + lambda_props = request_context.authorizer.get_lambda + assert lambda_props is not None + assert lambda_props.get("tenantId") == raw_event["requestContext"]["authorizer"]["lambda"]["tenantId"] + jwt_claims = request_context.authorizer.jwt_claim assert jwt_claims is not None assert jwt_claims.get("claim1") == raw_event["requestContext"]["authorizer"]["jwt"]["claims"]["claim1"] diff --git a/tests/unit/data_classes/test_lambda_function_url.py b/tests/unit/data_classes/test_lambda_function_url.py index 374383cd415..b7e8003d6c7 100644 --- a/tests/unit/data_classes/test_lambda_function_url.py +++ b/tests/unit/data_classes/test_lambda_function_url.py @@ -104,6 +104,7 @@ def test_lambda_function_url_event_iam(): assert authorizer is not None assert authorizer.jwt_claim is None assert authorizer.jwt_scopes is None + assert authorizer.get_lambda is None iam = authorizer.iam iam_raw = raw_event["requestContext"]["authorizer"]["iam"] diff --git a/tests/unit/parser/test_apigwv2.py b/tests/unit/parser/test_apigwv2.py index 399267eab2b..5a0f627b3cd 100644 --- a/tests/unit/parser/test_apigwv2.py +++ b/tests/unit/parser/test_apigwv2.py @@ -77,6 +77,10 @@ def test_api_gateway_proxy_v2_event_lambda_authorizer(): request_context: RequestContextV2 = parsed_event.requestContext assert request_context is not None + lambda_props: RequestContextV2Authorizer = request_context.authorizer.lambda_value + assert lambda_props is not None + assert lambda_props["tenantId"] == raw_event["requestContext"]["authorizer"]["lambda"]["tenantId"] + jwt_claims: RequestContextV2Authorizer = request_context.authorizer.jwt.claims assert jwt_claims is not None assert jwt_claims["claim1"] == raw_event["requestContext"]["authorizer"]["jwt"]["claims"]["claim1"] From d2958cc74ab53904b1bd277bd64ddd17e1fa7aca Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Wed, 6 Dec 2023 15:17:53 +0000 Subject: [PATCH 3/7] Reverting deletion --- tests/unit/parser/test_lambda_function_url.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/parser/test_lambda_function_url.py b/tests/unit/parser/test_lambda_function_url.py index a9148659134..3b1a7f259ec 100644 --- a/tests/unit/parser/test_lambda_function_url.py +++ b/tests/unit/parser/test_lambda_function_url.py @@ -113,6 +113,7 @@ def test_lambda_function_url_event_iam(): authorizer = request_context.authorizer assert authorizer is not None assert authorizer.jwt is None + assert authorizer.lambda_value is None iam = authorizer.iam iam_raw = raw_event["requestContext"]["authorizer"]["iam"] From bb226af813ee26e74356577d8f6669fd0dfd370f Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Wed, 6 Dec 2023 15:35:05 +0000 Subject: [PATCH 4/7] Adding tests --- .../data_classes/api_gateway_proxy_event.py | 20 +++++++++---------- .../test_api_gateway_proxy_event.py | 8 ++++++++ 2 files changed, 18 insertions(+), 10 deletions(-) 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 37797632422..2c605ffaa0e 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 @@ -33,6 +33,16 @@ def integration_latency(self) -> Optional[int]: """The authorizer latency in ms.""" return self.get("integrationLatency") + def get_context(self) -> Optional[Dict[str, Any]]: + """Retrieve the authorization context details for Lambda. + + Returns: + -------- + Optional[Dict[str, Any]] + A dictionary containing Lambda authorization context details, or None if the information is not available. + """ + return self + class APIGatewayEventRequestContext(BaseRequestContext): @property @@ -74,16 +84,6 @@ def route_key(self) -> Optional[str]: def authorizer(self) -> APIGatewayEventAuthorizer: return APIGatewayEventAuthorizer(self._data["requestContext"]["authorizer"]) - def get_context(self) -> Optional[Dict[str, Any]]: - """Retrieve the authorization context details for Lambda. - - Returns: - -------- - Optional[Dict[str, Any]] - A dictionary containing Lambda authorization context details, or None if the information is not available. - """ - return self.get("requestContext", {}).get("authorizer", {}) - class APIGatewayProxyEvent(BaseProxyEvent): """AWS Lambda proxy V1 diff --git a/tests/unit/data_classes/test_api_gateway_proxy_event.py b/tests/unit/data_classes/test_api_gateway_proxy_event.py index be6591ad814..7d464372135 100644 --- a/tests/unit/data_classes/test_api_gateway_proxy_event.py +++ b/tests/unit/data_classes/test_api_gateway_proxy_event.py @@ -150,6 +150,10 @@ def test_api_gateway_proxy_event_with_principal_id(): assert authorizer.integration_latency == raw_event["requestContext"]["authorizer"]["integrationLatency"] assert authorizer.get("integrationStatus", "failed") == "failed" + # Accessing context with direct function + context_variables = request_context.authorizer.get_context() + assert context_variables.get("user_id") == raw_event["requestContext"]["authorizer"]["user_id"] + def test_api_gateway_proxy_v2_event(): raw_event = load_event("apiGatewayProxyV2Event.json") @@ -205,6 +209,10 @@ def test_api_gateway_proxy_v2_lambda_authorizer_event(): assert lambda_props is not None assert lambda_props.get("tenantId") == raw_event["requestContext"]["authorizer"]["lambda"]["tenantId"] + # Accessing context with direct function + context_variables = request_context.authorizer.get_context() + assert context_variables.get("tenantId") == raw_event["requestContext"]["authorizer"]["lambda"]["tenantId"] + jwt_claims = request_context.authorizer.jwt_claim assert jwt_claims is not None assert jwt_claims.get("claim1") == raw_event["requestContext"]["authorizer"]["jwt"]["claims"]["claim1"] From 9f5dee04521dd6b3b39ee4de117f109b18b1d7b7 Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Wed, 6 Dec 2023 15:49:13 +0000 Subject: [PATCH 5/7] Addressing Heitor's feedback --- .../data_classes/api_gateway_proxy_event.py | 36 ++++++++++++++----- 1 file changed, 27 insertions(+), 9 deletions(-) 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 2c605ffaa0e..ee1053cb4ae 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 @@ -33,15 +33,24 @@ def integration_latency(self) -> Optional[int]: """The authorizer latency in ms.""" return self.get("integrationLatency") - def get_context(self) -> Optional[Dict[str, Any]]: - """Retrieve the authorization context details for Lambda. + def get_context(self) -> Dict[str, Any]: + """Retrieve the authorization context details injected by a Lambda Authorizer. + + Example + -------- + + ```python + ctx: dict = ...request_context.authorizer.get_context() + + tenant_id = ctx.get("tenant_id") + ``` Returns: -------- - Optional[Dict[str, Any]] - A dictionary containing Lambda authorization context details, or None if the information is not available. + Dict[str, Any] + A dictionary containing Lambda authorization context details. """ - return self + return self._data class APIGatewayEventRequestContext(BaseRequestContext): @@ -195,14 +204,23 @@ def get_lambda(self) -> Optional[Dict[str, Any]]: return self.get("lambda") def get_context(self) -> Optional[Dict[str, Any]]: - """Retrieve the authorization context details for Lambda. + """Retrieve the authorization context details injected by a Lambda Authorizer. + + Example + -------- + + ```python + ctx: dict = ...request_context.authorizer.get_context() + + tenant_id = ctx.get("tenant_id") + ``` Returns: -------- - Optional[Dict[str, Any]] - A dictionary containing Lambda authorization context details, or None if the information is not available. + Dict[str, Any] + A dictionary containing Lambda authorization context details. """ - return self.get("lambda") + return self.get("lambda", {}) @property def iam(self) -> Optional[RequestContextV2AuthorizerIam]: From 08aaff414d604868bd8f3cc0572b384a2032fe62 Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Wed, 6 Dec 2023 15:54:37 +0000 Subject: [PATCH 6/7] Addressing Heitor's feedback --- .../data_classes/api_gateway_proxy_event.py | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) 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 ee1053cb4ae..88a2da53bde 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 @@ -36,14 +36,14 @@ def integration_latency(self) -> Optional[int]: def get_context(self) -> Dict[str, Any]: """Retrieve the authorization context details injected by a Lambda Authorizer. - Example - -------- + Example + -------- ```python - ctx: dict = ...request_context.authorizer.get_context() + ctx: dict = ...request_context.authorizer.get_context() - tenant_id = ctx.get("tenant_id") - ``` + tenant_id = ctx.get("tenant_id") + ``` Returns: -------- @@ -203,24 +203,24 @@ def get_lambda(self) -> Optional[Dict[str, Any]]: """Lambda authorization context details""" return self.get("lambda") - def get_context(self) -> Optional[Dict[str, Any]]: + def get_context(self) -> Dict[str, Any]: """Retrieve the authorization context details injected by a Lambda Authorizer. - Example - -------- + Example + -------- ```python - ctx: dict = ...request_context.authorizer.get_context() + ctx: dict = ...request_context.authorizer.get_context() - tenant_id = ctx.get("tenant_id") - ``` + tenant_id = ctx.get("tenant_id") + ``` Returns: -------- Dict[str, Any] A dictionary containing Lambda authorization context details. """ - return self.get("lambda", {}) + return self.get("lambda", {}) or {} @property def iam(self) -> Optional[RequestContextV2AuthorizerIam]: From 8d6588977f86fe09a0f90dfcf2a3a49ae85ae00f Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Wed, 6 Dec 2023 15:57:15 +0000 Subject: [PATCH 7/7] Addressing Heitor's feedback --- .../utilities/data_classes/api_gateway_proxy_event.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 88a2da53bde..5c2ef12e62c 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 @@ -40,7 +40,7 @@ def get_context(self) -> Dict[str, Any]: -------- ```python - ctx: dict = ...request_context.authorizer.get_context() + ctx: dict = request_context.authorizer.get_context() tenant_id = ctx.get("tenant_id") ``` @@ -210,7 +210,7 @@ def get_context(self) -> Dict[str, Any]: -------- ```python - ctx: dict = ...request_context.authorizer.get_context() + ctx: dict = request_context.authorizer.get_context() tenant_id = ctx.get("tenant_id") ```