From bfc10417c4fbfa5ecad8f6db7b13704b649e5d5b Mon Sep 17 00:00:00 2001 From: Michael Brewer Date: Sun, 22 Aug 2021 16:33:55 +0000 Subject: [PATCH 1/6] refactor(data-classes): clean up internal logic Clean up the internal logic for `APIGatewayAuthorizerResponse` and update the internal docs. --- .../api_gateway_authorizer_event.py | 49 ++++++++++--------- docs/utilities/data_classes.md | 29 ++++++----- 2 files changed, 42 insertions(+), 36 deletions(-) diff --git a/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py b/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py index 29694eacd97..599df804719 100644 --- a/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py +++ b/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py @@ -374,22 +374,22 @@ def __init__( Optional, context. Note: only names of type string and values of type int, string or boolean are supported """ - self.principal_id = principal_id self.region = region self.aws_account_id = aws_account_id self.api_id = api_id self.stage = stage + self.principal_id = principal_id self.context = context self._allow_routes: List[Dict] = [] self._deny_routes: List[Dict] = [] - def _add_route(self, effect: str, verb: str, resource: str, conditions: List[Dict]): + def _add_route(self, effect: str, http_method: str, resource: str, conditions: Optional[List[Dict]] = None): """Adds a route to the internal lists of allowed or denied routes. Each object in the internal list contains a resource ARN and a condition statement. The condition statement can be null.""" - if verb != "*" and verb not in HttpVerb.__members__: + if http_method != "*" and http_method not in HttpVerb.__members__: allowed_values = [verb.value for verb in HttpVerb] - raise ValueError(f"Invalid HTTP verb: '{verb}'. Use either '{allowed_values}'") + raise ValueError(f"Invalid HTTP verb: '{http_method}'. Use either '{allowed_values}'") resource_pattern = re.compile(self.path_regex) if not resource_pattern.match(resource): @@ -398,7 +398,9 @@ def _add_route(self, effect: str, verb: str, resource: str, conditions: List[Dic if resource[:1] == "/": resource = resource[1:] - resource_arn = APIGatewayRouteArn(self.region, self.aws_account_id, self.api_id, self.stage, verb, resource).arn + resource_arn = APIGatewayRouteArn( + self.region, self.aws_account_id, self.api_id, self.stage, http_method, resource + ).arn route = {"resourceArn": resource_arn, "conditions": conditions} @@ -412,24 +414,27 @@ def _get_empty_statement(effect: str) -> Dict[str, Any]: """Returns an empty statement object prepopulated with the correct action and the desired effect.""" return {"Action": "execute-api:Invoke", "Effect": effect.capitalize(), "Resource": []} - def _get_statement_for_effect(self, effect: str, methods: List) -> List: - """This function loops over an array of objects containing a resourceArn and - conditions statement and generates the array of statements for the policy.""" - if len(methods) == 0: + def _get_statement_for_effect(self, effect: str, routes: List[Dict]) -> List[Dict]: + """This function loops over an array of objects containing a `resourceArn` and + `conditions` statement and generates the array of statements for the policy.""" + if len(routes) == 0: return [] - statements = [] - + statements: List[Dict] = [] statement = self._get_empty_statement(effect) - for method in methods: - if method["conditions"] is None or len(method["conditions"]) == 0: - statement["Resource"].append(method["resourceArn"]) - else: + + for route in routes: + resource_arn = route["resourceArn"] + conditions = route.get("conditions") + if conditions is not None and len(conditions) > 0: conditional_statement = self._get_empty_statement(effect) - conditional_statement["Resource"].append(method["resourceArn"]) - conditional_statement["Condition"] = method["conditions"] + conditional_statement["Resource"].append(resource_arn) + conditional_statement["Condition"] = conditions statements.append(conditional_statement) + else: + statement["Resource"].append(resource_arn) + if len(statement["Resource"]) > 0: statements.append(statement) @@ -442,7 +447,7 @@ def allow_all_routes(self, http_method: str = HttpVerb.ALL.value): ---------- http_method: str """ - self._add_route(effect="Allow", verb=http_method, resource="*", conditions=[]) + self._add_route(effect="Allow", http_method=http_method, resource="*") def deny_all_routes(self, http_method: str = HttpVerb.ALL.value): """Adds a '*' allow to the policy to deny access to all methods of an API @@ -452,7 +457,7 @@ def deny_all_routes(self, http_method: str = HttpVerb.ALL.value): http_method: str """ - self._add_route(effect="Deny", verb=http_method, resource="*", conditions=[]) + self._add_route(effect="Deny", http_method=http_method, resource="*") def allow_route(self, http_method: str, resource: str, conditions: Optional[List[Dict]] = None): """Adds an API Gateway method (Http verb + Resource path) to the list of allowed @@ -460,8 +465,7 @@ def allow_route(self, http_method: str, resource: str, conditions: Optional[List Optionally includes a condition for the policy statement. More on AWS policy conditions here: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements.html#Condition""" - conditions = conditions or [] - self._add_route(effect="Allow", verb=http_method, resource=resource, conditions=conditions) + self._add_route(effect="Allow", http_method=http_method, resource=resource, conditions=conditions) def deny_route(self, http_method: str, resource: str, conditions: Optional[List[Dict]] = None): """Adds an API Gateway method (Http verb + Resource path) to the list of denied @@ -469,8 +473,7 @@ def deny_route(self, http_method: str, resource: str, conditions: Optional[List[ Optionally includes a condition for the policy statement. More on AWS policy conditions here: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements.html#Condition""" - conditions = conditions or [] - self._add_route(effect="Deny", verb=http_method, resource=resource, conditions=conditions) + self._add_route(effect="Deny", http_method=http_method, resource=resource, conditions=conditions) def asdict(self) -> Dict[str, Any]: """Generates the policy document based on the internal lists of allowed and denied diff --git a/docs/utilities/data_classes.md b/docs/utilities/data_classes.md index 6cd487a2092..22361ca6a9f 100644 --- a/docs/utilities/data_classes.md +++ b/docs/utilities/data_classes.md @@ -96,7 +96,7 @@ Use **`APIGatewayAuthorizerRequestEvent`** for type `REQUEST` and **`APIGatewayA When the user is found, it includes the user details in the request context that will be available to the back-end, and returns a full access policy for admin users. - ```python hl_lines="2-5 26-31 36-37 40 44 46" + ```python hl_lines="2-5 29 36-42 47 49" from aws_lambda_powertools.utilities.data_classes import event_source from aws_lambda_powertools.utilities.data_classes.api_gateway_authorizer_event import ( APIGatewayAuthorizerRequestEvent, @@ -106,11 +106,15 @@ Use **`APIGatewayAuthorizerRequestEvent`** for type `REQUEST` and **`APIGatewayA from secrets import compare_digest + class UnAuthorizedError(Exception): + ... + + def get_user_by_token(token): if compare_digest(token, "admin-foo"): - return {"isAdmin": True, "name": "Admin"} + return {"id": 0, "name": "Admin", "isAdmin": True} elif compare_digest(token, "regular-foo"): - return {"name": "Joe"} + return {"id": 1, "name": "Joe"} else: return None @@ -119,25 +123,24 @@ Use **`APIGatewayAuthorizerRequestEvent`** for type `REQUEST` and **`APIGatewayA def handler(event: APIGatewayAuthorizerRequestEvent, context): user = get_user_by_token(event.get_header_value("Authorization")) + if user is None: + # No user was found, so we raised a not authorized error + raise UnAuthorizedError("Not authorized to perform this action") + # parse the `methodArn` as an `APIGatewayRouteArn` arn = event.parsed_arn + # Create the response builder from parts of the `methodArn` + # and set the logged in user id and context policy = APIGatewayAuthorizerResponse( - principal_id="user", + principal_id=user["id"], + context=user, region=arn.region, aws_account_id=arn.aws_account_id, api_id=arn.api_id, - stage=arn.stage + stage=arn.stage, ) - if user is None: - # No user was found, so we return not authorized - policy.deny_all_routes() - return policy.asdict() - - # Found the user and setting the details in the context - policy.context = user - # Conditional IAM Policy if user.get("isAdmin", False): policy.allow_all_routes() From b406365b5fa01ee1e318f62bdecf37925563d8fc Mon Sep 17 00:00:00 2001 From: Michael Brewer Date: Sun, 22 Aug 2021 11:27:10 -0700 Subject: [PATCH 2/6] feat(data-classes): Add a deny all response Update the docs and add a deny all response --- .../data_classes/api_gateway_authorizer_event.py | 15 +++++++++++++++ docs/utilities/data_classes.md | 14 +++++++------- .../data_classes/test_api_gateway_authorizer.py | 12 ++++++++++++ 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py b/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py index 599df804719..c3e068abb35 100644 --- a/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py +++ b/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py @@ -324,6 +324,21 @@ class HttpVerb(enum.Enum): ALL = "*" +DENY_ALL_RESPONSE = { + "principalId": "deny-all-user", + "policyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "execute-api:Invoke", + "Effect": "Deny", + "Resource": ["*"], + } + ], + }, +} + + class APIGatewayAuthorizerResponse: """Api Gateway HTTP API V1 payload or Rest api authorizer response helper diff --git a/docs/utilities/data_classes.md b/docs/utilities/data_classes.md index 22361ca6a9f..f0caeaef24a 100644 --- a/docs/utilities/data_classes.md +++ b/docs/utilities/data_classes.md @@ -96,9 +96,10 @@ Use **`APIGatewayAuthorizerRequestEvent`** for type `REQUEST` and **`APIGatewayA When the user is found, it includes the user details in the request context that will be available to the back-end, and returns a full access policy for admin users. - ```python hl_lines="2-5 29 36-42 47 49" + ```python hl_lines="2-6 29 36-42 47 49" from aws_lambda_powertools.utilities.data_classes import event_source from aws_lambda_powertools.utilities.data_classes.api_gateway_authorizer_event import ( + DENY_ALL_RESPONSE, APIGatewayAuthorizerRequestEvent, APIGatewayAuthorizerResponse, HttpVerb, @@ -106,10 +107,6 @@ Use **`APIGatewayAuthorizerRequestEvent`** for type `REQUEST` and **`APIGatewayA from secrets import compare_digest - class UnAuthorizedError(Exception): - ... - - def get_user_by_token(token): if compare_digest(token, "admin-foo"): return {"id": 0, "name": "Admin", "isAdmin": True} @@ -124,8 +121,11 @@ Use **`APIGatewayAuthorizerRequestEvent`** for type `REQUEST` and **`APIGatewayA user = get_user_by_token(event.get_header_value("Authorization")) if user is None: - # No user was found, so we raised a not authorized error - raise UnAuthorizedError("Not authorized to perform this action") + # No user was found + # to return 401 - `{"message":"Unauthorized"}`, but polutes lambda metrics + # raise Exception("Unauthorized") + # to return 403 - `{"message":"Forbidden"}` + return DENY_ALL_RESPONSE # parse the `methodArn` as an `APIGatewayRouteArn` arn = event.parsed_arn diff --git a/tests/functional/data_classes/test_api_gateway_authorizer.py b/tests/functional/data_classes/test_api_gateway_authorizer.py index 7dac6cb7791..8e19763d672 100644 --- a/tests/functional/data_classes/test_api_gateway_authorizer.py +++ b/tests/functional/data_classes/test_api_gateway_authorizer.py @@ -1,6 +1,7 @@ import pytest from aws_lambda_powertools.utilities.data_classes.api_gateway_authorizer_event import ( + DENY_ALL_RESPONSE, APIGatewayAuthorizerResponse, HttpVerb, ) @@ -145,3 +146,14 @@ def test_authorizer_response_deny_route_with_conditions(builder: APIGatewayAutho ], }, } + + +def test_deny_all(): + # CHECK we always explicitly deny all + statements = DENY_ALL_RESPONSE["policyDocument"]["Statement"] + assert len(statements) == 1 + assert statements[0] == { + "Action": "execute-api:Invoke", + "Effect": "Deny", + "Resource": ["*"], + } From f267736593b935a9d3fb12e375da75a5a70e4350 Mon Sep 17 00:00:00 2001 From: Michael Brewer Date: Sun, 22 Aug 2021 13:30:11 -0700 Subject: [PATCH 3/6] feat(data-classes): add missing usageIdentifierKey --- .../api_gateway_authorizer_event.py | 18 ++++++++++++++-- .../test_api_gateway_authorizer.py | 21 ++++++++++++++++++- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py b/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py index c3e068abb35..84623d8ae3f 100644 --- a/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py +++ b/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py @@ -340,10 +340,15 @@ class HttpVerb(enum.Enum): class APIGatewayAuthorizerResponse: - """Api Gateway HTTP API V1 payload or Rest api authorizer response helper + """The IAM Policy Response required for API Gateway REST APIs and HTTP APIs. Based on: - https://github.com/awslabs/aws-apigateway-lambda-authorizer-blueprints/blob/\ master/blueprints/python/api-gateway-authorizer-python.py + + Documentation: + ------------- + - https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-lambda-authorizer.html + - https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-lambda-authorizer-output.html """ version = "2012-10-17" @@ -360,6 +365,7 @@ def __init__( api_id: str, stage: str, context: Optional[Dict] = None, + usage_identifier_key: Optional[str] = None, ): """ Parameters @@ -388,13 +394,18 @@ def __init__( context : Dict, optional Optional, context. Note: only names of type string and values of type int, string or boolean are supported + usage_identifier_key: str, optional + If the API uses a usage plan (the apiKeySource is set to `AUTHORIZER`), the Lambda authorizer function + must return one of the usage plan's API keys as the usageIdentifierKey property value. + > **Note:** This only applies for REST APIs. """ + self.principal_id = principal_id self.region = region self.aws_account_id = aws_account_id self.api_id = api_id self.stage = stage - self.principal_id = principal_id self.context = context + self.usage_identifier_key = usage_identifier_key self._allow_routes: List[Dict] = [] self._deny_routes: List[Dict] = [] @@ -506,6 +517,9 @@ def asdict(self) -> Dict[str, Any]: response["policyDocument"]["Statement"].extend(self._get_statement_for_effect("Allow", self._allow_routes)) response["policyDocument"]["Statement"].extend(self._get_statement_for_effect("Deny", self._deny_routes)) + if self.usage_identifier_key: + response["usageIdentifierKey"] = self.usage_identifier_key + if self.context: response["context"] = self.context diff --git a/tests/functional/data_classes/test_api_gateway_authorizer.py b/tests/functional/data_classes/test_api_gateway_authorizer.py index 8e19763d672..449675c4720 100644 --- a/tests/functional/data_classes/test_api_gateway_authorizer.py +++ b/tests/functional/data_classes/test_api_gateway_authorizer.py @@ -37,7 +37,7 @@ def test_authorizer_response_invalid_resource(builder: APIGatewayAuthorizerRespo def test_authorizer_response_allow_all_routes_with_context(): - builder = APIGatewayAuthorizerResponse("foo", "us-west-1", "123456789", "fantom", "dev", {"name": "Foo"}) + builder = APIGatewayAuthorizerResponse("foo", "us-west-1", "123456789", "fantom", "dev", context={"name": "Foo"}) builder.allow_all_routes() assert builder.asdict() == { "principalId": "foo", @@ -55,6 +55,25 @@ def test_authorizer_response_allow_all_routes_with_context(): } +def test_authorizer_response_allow_all_routes_with_usage_identifier_key(): + builder = APIGatewayAuthorizerResponse("cow", "us-east-1", "1111111111", "api", "dev", usage_identifier_key="key") + builder.allow_all_routes() + assert builder.asdict() == { + "principalId": "cow", + "policyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "execute-api:Invoke", + "Effect": "Allow", + "Resource": ["arn:aws:execute-api:us-east-1:1111111111:api/dev/*/*"], + } + ], + }, + "usageIdentifierKey": "key", + } + + def test_authorizer_response_deny_all_routes(builder: APIGatewayAuthorizerResponse): builder.deny_all_routes() assert builder.asdict() == { From 2654d73e98de5bf53e34f8fbb3701a17ec480568 Mon Sep 17 00:00:00 2001 From: Michael Brewer Date: Sun, 22 Aug 2021 16:55:31 -0700 Subject: [PATCH 4/6] chore: minor optimizations --- .../data_classes/api_gateway_authorizer_event.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py b/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py index 84623d8ae3f..40a5425657e 100644 --- a/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py +++ b/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py @@ -351,9 +351,6 @@ class APIGatewayAuthorizerResponse: - https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-lambda-authorizer-output.html """ - version = "2012-10-17" - """The policy version used for the evaluation. This should always be '2012-10-17'""" - path_regex = r"^[/.a-zA-Z0-9-\*]+$" """The regular expression used to validate resource paths for the policy""" @@ -408,6 +405,7 @@ def __init__( self.usage_identifier_key = usage_identifier_key self._allow_routes: List[Dict] = [] self._deny_routes: List[Dict] = [] + self.resource_pattern = re.compile(self.path_regex) def _add_route(self, effect: str, http_method: str, resource: str, conditions: Optional[List[Dict]] = None): """Adds a route to the internal lists of allowed or denied routes. Each object in @@ -417,8 +415,7 @@ def _add_route(self, effect: str, http_method: str, resource: str, conditions: O allowed_values = [verb.value for verb in HttpVerb] raise ValueError(f"Invalid HTTP verb: '{http_method}'. Use either '{allowed_values}'") - resource_pattern = re.compile(self.path_regex) - if not resource_pattern.match(resource): + if not self.resource_pattern.match(resource): raise ValueError(f"Invalid resource path: {resource}. Path should match {self.path_regex}") if resource[:1] == "/": @@ -443,7 +440,7 @@ def _get_empty_statement(effect: str) -> Dict[str, Any]: def _get_statement_for_effect(self, effect: str, routes: List[Dict]) -> List[Dict]: """This function loops over an array of objects containing a `resourceArn` and `conditions` statement and generates the array of statements for the policy.""" - if len(routes) == 0: + if not routes: return [] statements: List[Dict] = [] @@ -511,7 +508,7 @@ def asdict(self) -> Dict[str, Any]: response: Dict[str, Any] = { "principalId": self.principal_id, - "policyDocument": {"Version": self.version, "Statement": []}, + "policyDocument": {"Version": "2012-10-17", "Statement": []}, } response["policyDocument"]["Statement"].extend(self._get_statement_for_effect("Allow", self._allow_routes)) From fd306fae9ea35e7666deda5a511fc9addf4e4f1f Mon Sep 17 00:00:00 2001 From: Michael Brewer Date: Sun, 22 Aug 2021 17:35:35 -0700 Subject: [PATCH 5/6] feat(data-classes): add from_route_arn helper Add `from_route_arn` to build APIGatewayAuthorizerResponse Add a relaxed pylintrc --- .pylintrc | 12 +++++++++ .../api_gateway_authorizer_event.py | 26 +++++++++++++++++-- .../test_api_gateway_authorizer.py | 6 +++-- 3 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 .pylintrc diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 00000000000..cf0445d7d27 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,12 @@ +[MESSAGES CONTROL] +disable= + too-many-arguments, + too-many-instance-attributes, + too-few-public-methods, + anomalous-backslash-in-string, + missing-class-docstring, + missing-module-docstring, + missing-function-docstring, + +[FORMAT] +max-line-length=120 diff --git a/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py b/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py index 40a5425657e..4682711af92 100644 --- a/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py +++ b/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py @@ -234,10 +234,12 @@ def raw_query_string(self) -> str: @property def cookies(self) -> List[str]: + """Cookies""" return self["cookies"] @property def headers(self) -> Dict[str, str]: + """Http headers""" return self["headers"] @property @@ -314,6 +316,8 @@ def asdict(self) -> dict: class HttpVerb(enum.Enum): + """Enum of http methods / verbs""" + GET = "GET" POST = "POST" PUT = "PUT" @@ -405,7 +409,25 @@ def __init__( self.usage_identifier_key = usage_identifier_key self._allow_routes: List[Dict] = [] self._deny_routes: List[Dict] = [] - self.resource_pattern = re.compile(self.path_regex) + self._resource_pattern = re.compile(self.path_regex) + + @staticmethod + def from_route_arn( + arn: str, + principal_id: str, + context: Optional[Dict] = None, + usage_identifier_key: Optional[str] = None, + ) -> "APIGatewayAuthorizerResponse": + parsed_arn = parse_api_gateway_arn(arn) + return APIGatewayAuthorizerResponse( + principal_id, + parsed_arn.region, + parsed_arn.aws_account_id, + parsed_arn.api_id, + parsed_arn.stage, + context, + usage_identifier_key, + ) def _add_route(self, effect: str, http_method: str, resource: str, conditions: Optional[List[Dict]] = None): """Adds a route to the internal lists of allowed or denied routes. Each object in @@ -415,7 +437,7 @@ def _add_route(self, effect: str, http_method: str, resource: str, conditions: O allowed_values = [verb.value for verb in HttpVerb] raise ValueError(f"Invalid HTTP verb: '{http_method}'. Use either '{allowed_values}'") - if not self.resource_pattern.match(resource): + if not self._resource_pattern.match(resource): raise ValueError(f"Invalid resource path: {resource}. Path should match {self.path_regex}") if resource[:1] == "/": diff --git a/tests/functional/data_classes/test_api_gateway_authorizer.py b/tests/functional/data_classes/test_api_gateway_authorizer.py index 449675c4720..b7584ccc4a8 100644 --- a/tests/functional/data_classes/test_api_gateway_authorizer.py +++ b/tests/functional/data_classes/test_api_gateway_authorizer.py @@ -37,7 +37,8 @@ def test_authorizer_response_invalid_resource(builder: APIGatewayAuthorizerRespo def test_authorizer_response_allow_all_routes_with_context(): - builder = APIGatewayAuthorizerResponse("foo", "us-west-1", "123456789", "fantom", "dev", context={"name": "Foo"}) + arn = "arn:aws:execute-api:us-west-1:123456789:fantom/dev/GET/foo" + builder = APIGatewayAuthorizerResponse.from_route_arn(arn, principal_id="foo", context={"name": "Foo"}) builder.allow_all_routes() assert builder.asdict() == { "principalId": "foo", @@ -56,7 +57,8 @@ def test_authorizer_response_allow_all_routes_with_context(): def test_authorizer_response_allow_all_routes_with_usage_identifier_key(): - builder = APIGatewayAuthorizerResponse("cow", "us-east-1", "1111111111", "api", "dev", usage_identifier_key="key") + arn = "arn:aws:execute-api:us-east-1:1111111111:api/dev/ANY/y" + builder = APIGatewayAuthorizerResponse.from_route_arn(arn, principal_id="cow", usage_identifier_key="key") builder.allow_all_routes() assert builder.asdict() == { "principalId": "cow", From 236caff6f9eb8d054bdbf38775e46dc2c6e2afb0 Mon Sep 17 00:00:00 2001 From: Michael Brewer Date: Sun, 22 Aug 2021 17:55:26 -0700 Subject: [PATCH 6/6] chore: fix typos --- docs/utilities/data_classes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/utilities/data_classes.md b/docs/utilities/data_classes.md index f0caeaef24a..9c1d4676777 100644 --- a/docs/utilities/data_classes.md +++ b/docs/utilities/data_classes.md @@ -122,7 +122,7 @@ Use **`APIGatewayAuthorizerRequestEvent`** for type `REQUEST` and **`APIGatewayA if user is None: # No user was found - # to return 401 - `{"message":"Unauthorized"}`, but polutes lambda metrics + # to return 401 - `{"message":"Unauthorized"}`, but pollutes lambda error count metrics # raise Exception("Unauthorized") # to return 403 - `{"message":"Forbidden"}` return DENY_ALL_RESPONSE