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 a7d75eadaa6..a0f2b8be8a1 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 @@ -267,6 +267,56 @@ def user_agent(self) -> str: return self["requestContext"]["http"]["userAgent"] +class RequestContextV2AuthorizerIam(DictWrapper): + @property + def access_key(self) -> Optional[str]: + """The IAM user access key associated with the request.""" + return self.get("accessKey") + + @property + def account_id(self) -> Optional[str]: + """The AWS account ID associated with the request.""" + return self.get("accountId") + + @property + def caller_id(self) -> Optional[str]: + """The principal identifier of the caller making the request.""" + return self.get("callerId") + + @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""" + return self["cognitoIdentity"].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.""" + return self["cognitoIdentity"].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.""" + return self["cognitoIdentity"].get("identityPoolId") + + @property + def principal_org_id(self) -> Optional[str]: + """The AWS organization ID.""" + return self.get("principalOrgId") + + @property + def user_arn(self) -> Optional[str]: + """The Amazon Resource Name (ARN) of the effective user identified after authentication.""" + return self.get("userArn") + + @property + def user_id(self) -> Optional[str]: + """The IAM user ID of the effective user identified after authentication.""" + return self.get("userId") + + class RequestContextV2Authorizer(DictWrapper): @property def jwt_claim(self) -> Dict[str, Any]: @@ -276,6 +326,17 @@ def jwt_claim(self) -> Dict[str, Any]: def jwt_scopes(self) -> List[str]: return self["jwt"]["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.""" + iam = self.get("iam") + return None if iam is None else RequestContextV2AuthorizerIam(iam) + class RequestContextV2(DictWrapper): @property diff --git a/tests/events/apiGatewayProxyV2IamEvent.json b/tests/events/apiGatewayProxyV2IamEvent.json new file mode 100644 index 00000000000..73d50d78a4a --- /dev/null +++ b/tests/events/apiGatewayProxyV2IamEvent.json @@ -0,0 +1,60 @@ +{ + "version": "2.0", + "routeKey": "$default", + "rawPath": "/my/path", + "rawQueryString": "parameter1=value1¶meter1=value2¶meter2=value", + "cookies": [ + "cookie1", + "cookie2" + ], + "headers": { + "Header1": "value1", + "Header2": "value2" + }, + "queryStringParameters": { + "parameter1": "value1,value2", + "parameter2": "value" + }, + "pathParameters": { + "proxy": "hello/world" + }, + "requestContext": { + "routeKey": "$default", + "accountId": "123456789012", + "stage": "$default", + "requestId": "id", + "authorizer": { + "iam": { + "accessKey": "ARIA2ZJZYVUEREEIHAKY", + "accountId": "1234567890", + "callerId": "AROA7ZJZYVRE7C3DUXHH6:CognitoIdentityCredentials", + "cognitoIdentity": { + "amr" : ["foo"], + "identityId": "us-east-1:3f291106-8703-466b-8f2b-3ecee1ca56ce", + "identityPoolId": "us-east-1:4f291106-8703-466b-8f2b-3ecee1ca56ce" + }, + "principalOrgId": "AwsOrgId", + "userArn": "arn:aws:iam::1234567890:user/Admin", + "userId": "AROA2ZJZYVRE7Y3TUXHH6" + } + }, + "apiId": "api-id", + "domainName": "id.execute-api.us-east-1.amazonaws.com", + "domainPrefix": "id", + "time": "12/Mar/2020:19:03:58+0000", + "timeEpoch": 1583348638390, + "http": { + "method": "GET", + "path": "/my/path", + "protocol": "HTTP/1.1", + "sourceIp": "IP", + "userAgent": "agent" + } + }, + "stageVariables": { + "stageVariable1": "value1", + "stageVariable2": "value2" + }, + "body": "{\r\n\t\"a\": 1\r\n}", + "isBase64Encoded": false +} diff --git a/tests/events/apiGatewayProxyV2LambdaAuthorizerEvent.json b/tests/events/apiGatewayProxyV2LambdaAuthorizerEvent.json new file mode 100644 index 00000000000..75d1574f854 --- /dev/null +++ b/tests/events/apiGatewayProxyV2LambdaAuthorizerEvent.json @@ -0,0 +1,50 @@ +{ + "version": "2.0", + "routeKey": "$default", + "rawPath": "/my/path", + "rawQueryString": "parameter1=value1¶meter1=value2¶meter2=value", + "cookies": [ + "cookie1", + "cookie2" + ], + "headers": { + "Header1": "value1", + "Header2": "value2" + }, + "queryStringParameters": { + "parameter1": "value1,value2", + "parameter2": "value" + }, + "pathParameters": { + "proxy": "hello/world" + }, + "requestContext": { + "routeKey": "$default", + "accountId": "123456789012", + "stage": "$default", + "requestId": "id", + "authorizer": { + "lambda": { + "key": "value" + } + }, + "apiId": "api-id", + "domainName": "id.execute-api.us-east-1.amazonaws.com", + "domainPrefix": "id", + "time": "12/Mar/2020:19:03:58+0000", + "timeEpoch": 1583348638390, + "http": { + "method": "GET", + "path": "/my/path", + "protocol": "HTTP/1.1", + "sourceIp": "IP", + "userAgent": "agent" + } + }, + "stageVariables": { + "stageVariable1": "value1", + "stageVariable2": "value2" + }, + "body": "{\r\n\t\"a\": 1\r\n}", + "isBase64Encoded": false +} diff --git a/tests/functional/test_lambda_trigger_events.py b/tests/functional/test_lambda_trigger_events.py index cc104ec8f04..6cfdbc765b1 100644 --- a/tests/functional/test_lambda_trigger_events.py +++ b/tests/functional/test_lambda_trigger_events.py @@ -639,6 +639,32 @@ def test_api_gateway_proxy_v2_event(): assert event.stage_variables == event["stageVariables"] +def test_api_gateway_proxy_v2_lambda_authorizer_event(): + event = APIGatewayProxyEventV2(load_event("apiGatewayProxyV2LambdaAuthorizerEvent.json")) + + request_context = 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["key"] == "value" + + +def test_api_gateway_proxy_v2_iam_event(): + event = APIGatewayProxyEventV2(load_event("apiGatewayProxyV2IamEvent.json")) + + iam = event.request_context.authorizer.iam + assert iam is not None + assert iam.access_key == "ARIA2ZJZYVUEREEIHAKY" + assert iam.account_id == "1234567890" + assert iam.caller_id == "AROA7ZJZYVRE7C3DUXHH6:CognitoIdentityCredentials" + assert iam.cognito_amr == ["foo"] + assert iam.cognito_identity_id == "us-east-1:3f291106-8703-466b-8f2b-3ecee1ca56ce" + assert iam.cognito_identity_pool_id == "us-east-1:4f291106-8703-466b-8f2b-3ecee1ca56ce" + assert iam.principal_org_id == "AwsOrgId" + assert iam.user_arn == "arn:aws:iam::1234567890:user/Admin" + assert iam.user_id == "AROA2ZJZYVRE7Y3TUXHH6" + + def test_base_proxy_event_get_query_string_value(): default_value = "default" set_value = "value"