Skip to content

Commit 297e291

Browse files
committed
feat: implement requester_user validation and integration across user-related controllers
1 parent c276775 commit 297e291

27 files changed

Lines changed: 400 additions & 338 deletions

iac/iac/iac_stack.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import os
22

33
from aws_cdk import (
4-
Duration,
54
Stack,
65
# aws_sqs as sqs,
76
)
@@ -56,8 +55,8 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
5655

5756

5857
self.lambda_stack = LambdaStack(self, api_gateway_resource=api_gateway_resource,
59-
environment_variables=ENVIRONMENT_VARIABLES)
58+
environment_variables=ENVIRONMENT_VARIABLES,
59+
user_pool=self.cognito_stack.user_pool)
6060

6161
for function in self.lambda_stack.functions_that_need_dynamo_permissions:
6262
self.dynamo_table.table.grant_read_write_data(function)
63-

iac/iac/lambda_stack.py

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,23 @@
22
aws_lambda as lambda_,
33
Duration
44
)
5-
from aws_cdk.aws_apigateway import Resource, LambdaIntegration
5+
from aws_cdk.aws_apigateway import Resource, LambdaIntegration, AuthorizationType, CognitoUserPoolsAuthorizer
66
from constructs import Construct
77

88

99
class LambdaStack(Construct):
1010
functions_that_need_dynamo_permissions = []
1111

12-
def __init__(self, scope: Construct, api_gateway_resource: Resource, environment_variables: dict) -> None:
12+
def __init__(self, scope: Construct, api_gateway_resource: Resource, environment_variables: dict, user_pool) -> None:
1313
super().__init__(scope, "KnowlyApiLambdas")
1414

15+
# Authorizer Cognito (User Pool)
16+
self.authorizer = CognitoUserPoolsAuthorizer(
17+
self,
18+
"KnowlyCognitoAuthorizer",
19+
cognito_user_pools=[user_pool]
20+
)
21+
1522
self.lambda_layer = lambda_.LayerVersion(self, "Knowly_Layer",
1623
code=lambda_.Code.from_asset("./lambda_layer_out_temp"),
1724
compatible_runtimes=[lambda_.Runtime.PYTHON_3_13]
@@ -24,7 +31,8 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment
2431
module_name="get_user",
2532
http_method="GET",
2633
target_resource=user_resource,
27-
environment_variables=environment_variables
34+
environment_variables=environment_variables,
35+
requires_authorizer=True
2836
)
2937

3038
self.create_user_function = self._add_method_to_resource(
@@ -38,14 +46,16 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment
3846
module_name="delete_user",
3947
http_method="DELETE",
4048
target_resource=user_resource,
41-
environment_variables=environment_variables
49+
environment_variables=environment_variables,
50+
requires_authorizer=True
4251
)
4352

4453
self.update_user_function = self._add_method_to_resource(
4554
module_name="update_user",
4655
http_method="PATCH",
4756
target_resource=user_resource,
48-
environment_variables=environment_variables
57+
environment_variables=environment_variables,
58+
requires_authorizer=True
4959
)
5060

5161
# ---- Auth Resource ----
@@ -65,7 +75,8 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment
6575
module_name="get_transactions_by_user",
6676
http_method="GET",
6777
target_resource=transactions_resource,
68-
environment_variables=environment_variables
78+
environment_variables=environment_variables,
79+
requires_authorizer=True
6980
)
7081

7182
# ---- Subscriptions Resource ----
@@ -75,14 +86,16 @@ def __init__(self, scope: Construct, api_gateway_resource: Resource, environment
7586
module_name="get_subscriptions_by_user",
7687
http_method="GET",
7788
target_resource=subscriptions_resource,
78-
environment_variables=environment_variables
89+
environment_variables=environment_variables,
90+
requires_authorizer=True
7991
)
8092

8193
self.update_subscription_function = self._add_method_to_resource(
8294
module_name="update_subscription",
8395
http_method="PUT",
8496
target_resource=subscriptions_resource,
85-
environment_variables=environment_variables
97+
environment_variables=environment_variables,
98+
requires_authorizer=True
8699
)
87100

88101
self.functions_that_need_dynamo_permissions = [self.get_user_function, self.create_user_function,
@@ -96,7 +109,8 @@ def _add_method_to_resource(
96109
module_name: str,
97110
http_method: str,
98111
target_resource: Resource,
99-
environment_variables: dict
112+
environment_variables: dict,
113+
requires_authorizer: bool = False
100114
) -> lambda_.Function:
101115
fn = lambda_.Function(
102116
self,
@@ -109,5 +123,14 @@ def _add_method_to_resource(
109123
timeout=Duration.seconds(15),
110124
)
111125

112-
target_resource.add_method(http_method, LambdaIntegration(fn))
126+
integration = LambdaIntegration(fn)
127+
if requires_authorizer:
128+
target_resource.add_method(
129+
http_method,
130+
integration,
131+
authorization_type=AuthorizationType.COGNITO,
132+
authorizer=self.authorizer
133+
)
134+
else:
135+
target_resource.add_method(http_method, integration)
113136
return fn

src/modules/delete_user/app/delete_user_controller.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from src.shared.helpers.errors.usecase_errors import NoItemsFound
44
from src.shared.helpers.external_interfaces.external_interface import IRequest, IResponse
55
from src.shared.helpers.external_interfaces.http_codes import OK, NotFound, BadRequest, InternalServerError
6+
from src.shared.infra.dto.user_api_gateway_dto import UserApiGatewayDTO
67
from .delete_user_usecase import DeleteUserUseCase
78

89

@@ -13,18 +14,21 @@ def __init__(self, usecase: DeleteUserUseCase):
1314

1415
def __call__(self, request: IRequest) -> IResponse:
1516
try:
16-
if request.data.get('user_id') is None:
17-
raise MissingParameters('user_id')
17+
# Authorizer obrigatório
18+
if request.data.get('requester_user') is None:
19+
raise MissingParameters('requester_user')
1820

19-
if type(request.data.get('user_id')) != str:
21+
requester_user = UserApiGatewayDTO.from_api_gateway(request.data.get('requester_user'))
22+
23+
if type(requester_user.user_id) != str:
2024
raise WrongTypeParameter(
21-
field_name="user_id",
22-
field_type_expected="str",
23-
field_type_received=request.data.get('user_id').__class__.__name__
25+
field_name='user_id',
26+
field_type_expected='str',
27+
field_type_received=type(requester_user.user_id)
2428
)
2529

2630
user = self.DeleteUserUsecase(
27-
user_id=request.data.get('user_id')
31+
user_id=requester_user.user_id
2832
)
2933

3034
viewmodel = {

src/modules/delete_user/app/delete_user_presenter.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
def lambda_handler(event, context):
1212
http_request = LambdaHttpRequest(data=event)
13+
# Injeta o usuário autenticado vindo do API Gateway/Cognito para o controller
14+
http_request.data['requester_user'] = event.get('requestContext', {}).get('authorizer', {}).get('claims', None)
1315
response = controller(http_request)
1416
http_response = LambdaHttpResponse(status_code=response.status_code, body=response.body, headers=response.headers)
1517

src/modules/get_subscriptions_by_user/app/get_subscriptions_by_user_controller.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from src.shared.helpers.errors.usecase_errors import NoItemsFound
44
from src.shared.helpers.external_interfaces.external_interface import IRequest, IResponse
55
from src.shared.helpers.external_interfaces.http_codes import OK, NotFound, BadRequest, InternalServerError
6+
from src.shared.infra.dto.user_api_gateway_dto import UserApiGatewayDTO
67
from .get_subscriptions_by_user_usecase import GetUserSubscriptionsUseCase
78

89

@@ -12,14 +13,18 @@ def __init__(self, usecase: GetUserSubscriptionsUseCase):
1213

1314
def __call__(self, request: IRequest) -> IResponse:
1415
try:
15-
user_id = request.data.get("user_id")
16-
if user_id is None:
17-
raise MissingParameters("user_id")
18-
if not isinstance(user_id, str):
16+
# Authorizer obrigatório
17+
if request.data.get('requester_user') is None:
18+
raise MissingParameters('requester_user')
19+
20+
requester_user = UserApiGatewayDTO.from_api_gateway(request.data.get('requester_user'))
21+
22+
user_id = requester_user.user_id
23+
if type(user_id) != str:
1924
raise WrongTypeParameter(
2025
field_name="user_id",
2126
field_type_expected="str",
22-
field_type_received=type(user_id).__name__,
27+
field_type_received=type(user_id)
2328
)
2429
if not user_id.strip():
2530
raise EntityError("user_id")

src/modules/get_subscriptions_by_user/app/get_subscriptions_by_user_presenter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
def lambda_handler(event, context):
1111
http_request = LambdaHttpRequest(data=event)
12-
12+
http_request.data['requester_user'] = event.get('requestContext', {}).get('authorizer', {}).get('claims', None)
1313
response = controller(http_request)
1414
http_response = LambdaHttpResponse(
1515
status_code=response.status_code,

src/modules/get_transactions_by_user/app/get_transactions_by_user_controller.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from src.shared.helpers.errors.usecase_errors import NoItemsFound
44
from src.shared.helpers.external_interfaces.external_interface import IRequest, IResponse
55
from src.shared.helpers.external_interfaces.http_codes import OK, NotFound, BadRequest, InternalServerError
6+
from src.shared.infra.dto.user_api_gateway_dto import UserApiGatewayDTO
67
from .get_transactions_by_user_usecase import GetTransactionsByUserUseCase
78

89

@@ -12,17 +13,20 @@ def __init__(self, usecase: GetTransactionsByUserUseCase):
1213

1314
def __call__(self, request: IRequest) -> IResponse:
1415
try:
15-
user_id = request.data.get("user_id")
16-
if user_id is None:
17-
raise MissingParameters("user_id")
18-
if not isinstance(user_id, str):
16+
if request.data.get('requester_user') is None:
17+
raise MissingParameters('requester_user')
18+
19+
requester_user = UserApiGatewayDTO.from_api_gateway(request.data.get('requester_user'))
20+
user_id = requester_user.user_id
21+
22+
if type(user_id) != str:
1923
raise WrongTypeParameter(
20-
field_name="user_id",
21-
field_type_expected="str",
22-
field_type_received=type(user_id).__name__
24+
field_name='user_id',
25+
field_type_expected='str',
26+
field_type_received=type(user_id)
2327
)
2428
if not user_id.strip():
25-
raise EntityError("user_id")
29+
raise EntityError('user_id')
2630

2731
transactions = self.get_transactions_by_user_usecase(user_id=user_id)
2832

src/modules/get_transactions_by_user/app/get_transactions_by_user_presenter.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
def lambda_handler(event, context):
1111
http_request = LambdaHttpRequest(data=event)
12+
http_request.data['requester_user'] = event.get('requestContext', {}).get('authorizer', {}).get('claims', None)
1213
response = controller(request=http_request)
1314
http_response = LambdaHttpResponse(
1415
status_code=response.status_code,

src/modules/get_user/app/get_user_controller.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from src.shared.helpers.errors.usecase_errors import NoItemsFound
44
from src.shared.helpers.external_interfaces.external_interface import IRequest, IResponse
55
from src.shared.helpers.external_interfaces.http_codes import OK, NotFound, BadRequest, InternalServerError
6+
from src.shared.infra.dto.user_api_gateway_dto import UserApiGatewayDTO
67
from .get_user_usecase import GetUserUseCase
78

89

@@ -13,21 +14,23 @@ def __init__(self, usecase: GetUserUseCase):
1314

1415
def __call__(self, request: IRequest) -> IResponse:
1516
try:
16-
if request.data.get('user_id') is None:
17-
raise MissingParameters('user_id')
17+
if request.data.get('requester_user') is None:
18+
raise MissingParameters('requester_user')
1819

19-
if type(request.data.get('user_id')) != str:
20-
raise WrongTypeParameter('user_id', 'str', type(request.data.get('user_id')))
20+
requester_user = UserApiGatewayDTO.from_api_gateway(request.data.get('requester_user'))
21+
22+
if type(requester_user.user_id) != str:
23+
raise WrongTypeParameter('user_id', 'str', type(requester_user.user_id))
2124

2225
user = self.GetUserUsecase(
23-
user_id=request.data.get('user_id')
26+
user_id=requester_user.user_id,
2427
)
2528

2629
viewmodel = {
2730
'user': user.__to_dict__(),
2831
'message': 'Usuário encontrado com sucesso'
2932
}
30-
33+
3134
response = OK(viewmodel)
3235
return response
3336

src/modules/get_user/app/get_user_presenter.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
def lambda_handler(event, context):
1313
http_request = LambdaHttpRequest(data=event)
14+
http_request.data['requester_user'] = event.get('requestContext', {}).get('authorizer', {}).get('claims', None)
1415
response = controller(http_request)
1516
http_response = LambdaHttpResponse(status_code=response.status_code, body=response.body, headers=response.headers)
1617
return http_response.toDict()

0 commit comments

Comments
 (0)