add better auth

This commit is contained in:
2025-03-25 11:45:09 -03:00
parent 2218a6f867
commit 317c79cee2
11 changed files with 912 additions and 46 deletions

View File

@@ -6,3 +6,7 @@ deploy: build
start-api: build start-api: build
sam local start-api sam local start-api
openapi:
uv run openapi.py && \
uv run python -m http.server 80 -d swagger

View File

@@ -5,28 +5,16 @@ from aws_lambda_powertools.event_handler.api_gateway import (
content_types, content_types,
) )
from aws_lambda_powertools.event_handler.exceptions import ServiceError from aws_lambda_powertools.event_handler.exceptions import ServiceError
from aws_lambda_powertools.event_handler.openapi.models import (
HTTPBearer,
Server,
)
from aws_lambda_powertools.logging import correlation_paths from aws_lambda_powertools.logging import correlation_paths
from aws_lambda_powertools.utilities.typing import LambdaContext from aws_lambda_powertools.utilities.typing import LambdaContext
from middlewares import CorrelationIdMiddleware
from routes import courses, enrollments, orders, users, webhooks from routes import courses, enrollments, orders, users, webhooks
tracer = Tracer() tracer = Tracer()
logger = Logger(__name__) logger = Logger(__name__)
app = APIGatewayHttpResolver(enable_validation=True) app = APIGatewayHttpResolver(enable_validation=True)
app.enable_swagger( app.use(middlewares=[CorrelationIdMiddleware('workspace')])
servers=[Server(url='https://api.saladeaula.digital/v2')],
title='EDUSEG® Public API',
path='/_swagger',
compress=True,
security_schemes={'bearerAuth': HTTPBearer()},
security=[{'bearerAuth': []}],
persist_authorization=True,
)
app.include_router(users.router, prefix='/users') app.include_router(users.router, prefix='/users')
app.include_router(enrollments.router, prefix='/enrollments') app.include_router(enrollments.router, prefix='/enrollments')
app.include_router(orders.router, prefix='/orders') app.include_router(orders.router, prefix='/orders')
@@ -50,9 +38,3 @@ def exc_error(exc: ServiceError):
@tracer.capture_lambda_handler @tracer.capture_lambda_handler
def lambda_handler(event: dict, context: LambdaContext) -> dict: def lambda_handler(event: dict, context: LambdaContext) -> dict:
return app.resolve(event, context) return app.resolve(event, context)
# if __name__ == '__main__':
# print(
# app.get_openapi_json_schema(),
# )

View File

@@ -1,3 +1,5 @@
from dataclasses import dataclass
import boto3 import boto3
from aws_lambda_powertools import Logger, Tracer from aws_lambda_powertools import Logger, Tracer
from aws_lambda_powertools.utilities.data_classes import event_source from aws_lambda_powertools.utilities.data_classes import event_source
@@ -6,9 +8,12 @@ from aws_lambda_powertools.utilities.data_classes.api_gateway_authorizer_event i
APIGatewayAuthorizerResponseV2, APIGatewayAuthorizerResponseV2,
) )
from aws_lambda_powertools.utilities.typing import LambdaContext from aws_lambda_powertools.utilities.typing import LambdaContext
from botocore.endpoint_provider import Enum
from cognito import get_user from cognito import get_user
APIKEY_PREFIX = 'edxg'
tracer = Tracer() tracer = Tracer()
logger = Logger(__name__) logger = Logger(__name__)
idp_client = boto3.client('cognito-idp') idp_client = boto3.client('cognito-idp')
@@ -18,18 +23,49 @@ idp_client = boto3.client('cognito-idp')
@logger.inject_lambda_context @logger.inject_lambda_context
@event_source(data_class=APIGatewayAuthorizerEventV2) @event_source(data_class=APIGatewayAuthorizerEventV2)
def lambda_handler(event: APIGatewayAuthorizerEventV2, context: LambdaContext): def lambda_handler(event: APIGatewayAuthorizerEventV2, context: LambdaContext):
auth_header = event.get_header_value('authorization', default_value='') bearer = _parse_bearer_token(event.headers.get('authorization', ''))
try: if not bearer:
_, bearer_token = auth_header.split(' ')
user = get_user(bearer_token, idp_client=idp_client)
except ValueError:
return APIGatewayAuthorizerResponseV2(authorize=False).asdict() return APIGatewayAuthorizerResponseV2(authorize=False).asdict()
if not user: if bearer.auth_type == TokenType.USER_TOKEN:
return APIGatewayAuthorizerResponseV2(authorize=False).asdict() user = get_user(bearer.token, idp_client=idp_client)
if user:
return APIGatewayAuthorizerResponseV2( return APIGatewayAuthorizerResponseV2(
authorize=True, authorize=True,
context=dict(user=user), context=dict(user=user),
).asdict() ).asdict()
return APIGatewayAuthorizerResponseV2(authorize=False).asdict()
class TokenType(str, Enum):
API_KEY = 'API_KEY'
USER_TOKEN = 'USER_TOKEN'
@dataclass
class BearerToken:
auth_type: TokenType
token: str
def _parse_bearer_token(
s: str,
*,
apikey_prefix: str = APIKEY_PREFIX,
) -> BearerToken | None:
"""Parses and identifies a bearer token as either an API key or a user token."""
try:
_, bearer_token = s.split(' ')
if bearer_token.startswith(f'{apikey_prefix}-'):
return BearerToken(
TokenType.API_KEY,
bearer_token.removeprefix(f'{apikey_prefix}-'),
)
except ValueError:
return None
else:
return BearerToken(TokenType.USER_TOKEN, bearer_token)

29
http-api/middlewares.py Normal file
View File

@@ -0,0 +1,29 @@
from aws_lambda_powertools.event_handler.api_gateway import (
APIGatewayHttpResolver,
Response,
)
from aws_lambda_powertools.event_handler.middlewares import (
BaseMiddlewareHandler,
NextMiddleware,
)
class CorrelationIdMiddleware(BaseMiddlewareHandler):
def __init__(self, header: str):
super().__init__()
self.header = header
def handler(
self, app: APIGatewayHttpResolver, next_middleware: NextMiddleware
) -> Response:
# BEFORE logic
request_id = app.current_event.request_context.request_id
correlation_id = app.current_event.headers.get(self.header, request_id)
# Call next middleware or route handler ('/todos')
response = next_middleware(app)
# AFTER logic
response.headers[self.header] = correlation_id
return response

View File

@@ -29,7 +29,6 @@ class User(BaseModel):
class Cert(BaseModel): class Cert(BaseModel):
id: UUID4 | str = Field(default_factory=uuid4)
exp_interval: int exp_interval: int

32
http-api/openapi.py Normal file
View File

@@ -0,0 +1,32 @@
from aws_lambda_powertools.event_handler.openapi.models import (
HTTPBearer,
Server,
)
from aws_lambda_powertools.event_handler.openapi.swagger_ui.html import (
generate_swagger_html,
)
from app import app
title = 'EDUSEG® Public API'
swagger_base_url = 'https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.20.1'
if __name__ == '__main__':
spec = app.get_openapi_json_schema(
servers=[Server(url='https://api.saladeaula.digital/v2')],
title=title,
security_schemes={'bearerAuth': HTTPBearer()},
security=[{'bearerAuth': []}],
)
body = generate_swagger_html(
spec=spec,
swagger_base_url=swagger_base_url,
swagger_js=f'{swagger_base_url}/swagger-ui-bundle.js',
swagger_css=f'{swagger_base_url}/swagger-ui.css',
oauth2_config=None,
persist_authorization=True,
)
with open('swagger/index.html', 'w') as fp:
fp.write(body)

View File

@@ -6,7 +6,7 @@ from aws_lambda_powertools.event_handler import Response, content_types
from aws_lambda_powertools.event_handler.api_gateway import Router from aws_lambda_powertools.event_handler.api_gateway import Router
from elasticsearch import Elasticsearch from elasticsearch import Elasticsearch
from layercake.dynamodb import DynamoDBPersistenceLayer from layercake.dynamodb import DynamoDBPersistenceLayer
from pydantic.main import BaseModel from pydantic import BaseModel
import elastic import elastic
from course import create_course from course import create_course
@@ -34,16 +34,17 @@ def get_courses():
) )
class Payload(BaseModel): class CoursePayload(BaseModel):
course: Course course: Course
org: Org
@router.post('/', compress=True, tags=['Course']) @router.post('/', compress=True, tags=['Course'])
def post_course(payload: Payload): def post_course(payload: CoursePayload):
org = Org(id='*', name='EDUSEG')
create_course( create_course(
course=payload.course, course=payload.course,
org=payload.org, org=org,
persistence_layer=course_layer, persistence_layer=course_layer,
) )

760
http-api/swagger/index.html Normal file
View File

@@ -0,0 +1,760 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<meta
http-equiv="Cache-control"
content="no-cache, no-store, must-revalidate"
/>
<link rel='stylesheet' type='text/css' href='https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.20.1/swagger-ui.css'>
</head>
<body>
<div id="swagger-ui">
Loading...
</div>
</body>
<script src='https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.20.1/swagger-ui-bundle.js'></script>
<script>
var currentUrl = new URL(window.location.href);
var baseUrl = currentUrl.protocol + "//" + currentUrl.host + currentUrl.pathname;
var swaggerUIOptions = {
dom_id: "#swagger-ui",
docExpansion: "list",
deepLinking: true,
filter: true,
layout: "BaseLayout",
showExtensions: true,
showCommonExtensions: true,
spec: {
"openapi": "3.1.0",
"info": {
"title": "EDUSEG® Public API",
"version": "1.0.0"
},
"servers": [
{
"url": "https://api.saladeaula.digital/v2"
}
],
"paths": {
"/users/{id}": {
"patch": {
"tags": [
"User"
],
"summary": "PATCH /users/{id}",
"operationId": "patch_reset_users__id__patch",
"parameters": [
{
"required": true,
"schema": {
"type": "string",
"title": "Id"
},
"name": "id",
"in": "path"
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/NewPasswordPayload"
}
}
},
"required": true
},
"responses": {
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
},
"200": {
"description": "Successful Response",
"content": {
"application/json": {}
}
}
}
}
},
"/users/{id}/emails": {
"get": {
"tags": [
"User"
],
"summary": "Get user emails",
"operationId": "get_emails_users__id__emails_get",
"parameters": [
{
"required": true,
"schema": {
"type": "string",
"title": "Id"
},
"name": "id",
"in": "path"
}
],
"responses": {
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
},
"200": {
"description": "Successful Response",
"content": {
"application/json": {}
}
}
}
}
},
"/users/{id}/logs": {
"get": {
"tags": [
"User"
],
"summary": "Get user logs",
"operationId": "get_logs_users__id__logs_get",
"parameters": [
{
"required": true,
"schema": {
"type": "string",
"title": "Id"
},
"name": "id",
"in": "path"
}
],
"responses": {
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
},
"200": {
"description": "Successful Response",
"content": {
"application/json": {}
}
}
}
}
},
"/users/{id}/orgs": {
"get": {
"tags": [
"User"
],
"summary": "Get user orgs",
"operationId": "get_orgs_users__id__orgs_get",
"parameters": [
{
"required": true,
"schema": {
"type": "string",
"title": "Id"
},
"name": "id",
"in": "path"
}
],
"responses": {
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
},
"200": {
"description": "Successful Response",
"content": {
"application/json": {}
}
}
}
}
},
"/enrollments/{id}": {
"get": {
"tags": [
"Enrollment"
],
"summary": "GET /enrollments/{id}",
"operationId": "get_enrollment_enrollments__id__get",
"parameters": [
{
"required": true,
"schema": {
"type": "string",
"title": "Id"
},
"name": "id",
"in": "path"
}
],
"responses": {
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
},
"200": {
"description": "Successful Response",
"content": {
"application/json": {}
}
}
}
},
"patch": {
"tags": [
"Enrollment"
],
"summary": "PATCH /enrollments/{id}",
"operationId": "cancel_enrollments__id__patch",
"parameters": [
{
"required": true,
"schema": {
"type": "string",
"title": "Id"
},
"name": "id",
"in": "path"
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CancelPayload"
}
}
},
"required": true
},
"responses": {
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
},
"200": {
"description": "Successful Response",
"content": {
"application/json": {}
}
}
}
}
},
"/courses/{id}": {
"get": {
"tags": [
"Course"
],
"summary": "GET /courses/{id}",
"operationId": "get_course_courses__id__get",
"parameters": [
{
"required": true,
"schema": {
"type": "string",
"title": "Id"
},
"name": "id",
"in": "path"
}
],
"responses": {
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
},
"200": {
"description": "Successful Response",
"content": {
"application/json": {}
}
}
}
}
},
"/users": {
"get": {
"tags": [
"User"
],
"summary": "Get users",
"operationId": "get_users_users_get",
"responses": {
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
},
"200": {
"description": "Successful Response",
"content": {
"application/json": {}
}
}
}
},
"post": {
"tags": [
"User"
],
"summary": "POST /users",
"description": "Create user",
"operationId": "post_user_users_post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
}
},
"required": true
},
"responses": {
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
},
"200": {
"description": "Successful Response",
"content": {
"application/json": {}
}
}
}
}
},
"/enrollments": {
"get": {
"tags": [
"Enrollment"
],
"summary": "GET /enrollments",
"operationId": "get_enrollments_enrollments_get",
"responses": {
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
},
"200": {
"description": "Successful Response",
"content": {
"application/json": {}
}
}
}
},
"post": {
"tags": [
"Enrollment"
],
"summary": "POST /enrollments",
"operationId": "enroll_enrollments_post",
"responses": {
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
},
"200": {
"description": "Successful Response",
"content": {
"application/json": {}
}
}
}
}
},
"/orders": {
"get": {
"tags": [
"Order"
],
"summary": "GET /orders",
"operationId": "get_orders_orders_get",
"responses": {
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
},
"200": {
"description": "Successful Response",
"content": {
"application/json": {}
}
}
}
}
},
"/courses": {
"get": {
"tags": [
"Course"
],
"summary": "GET /courses",
"operationId": "get_courses_courses_get",
"responses": {
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
},
"200": {
"description": "Successful Response",
"content": {
"application/json": {}
}
}
}
},
"post": {
"tags": [
"Course"
],
"summary": "POST /courses",
"operationId": "post_course_courses_post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CoursePayload"
}
}
},
"required": true
},
"responses": {
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
},
"200": {
"description": "Successful Response",
"content": {
"application/json": {}
}
}
}
}
}
},
"components": {
"schemas": {
"CancelPayload": {
"properties": {
"status": {
"type": "string",
"const": "CANCELED",
"title": "Status",
"default": "CANCELED"
}
},
"type": "object",
"title": "CancelPayload"
},
"Cert": {
"properties": {
"exp_interval": {
"type": "integer",
"title": "Exp Interval"
}
},
"type": "object",
"required": [
"exp_interval"
],
"title": "Cert"
},
"Course": {
"properties": {
"id": {
"anyOf": [
{
"type": "string",
"format": "uuid4"
},
{
"type": "string"
}
],
"title": "Id"
},
"name": {
"type": "string",
"title": "Name"
},
"cert": {
"anyOf": [
{
"$ref": "#/components/schemas/Cert"
},
{
"type": "null"
}
]
},
"access_period": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"title": "Access Period"
}
},
"type": "object",
"required": [
"name"
],
"title": "Course"
},
"CoursePayload": {
"properties": {
"course": {
"$ref": "#/components/schemas/Course"
}
},
"type": "object",
"required": [
"course"
],
"title": "CoursePayload"
},
"HTTPValidationError": {
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
},
"NewPasswordPayload": {
"properties": {
"cognito_sub": {
"type": "string",
"format": "uuid4",
"title": "Cognito Sub"
},
"new_password": {
"type": "string",
"minLength": 6,
"title": "New Password"
}
},
"type": "object",
"required": [
"cognito_sub",
"new_password"
],
"title": "NewPasswordPayload"
},
"User": {
"properties": {
"id": {
"anyOf": [
{
"type": "string",
"format": "uuid4"
},
{
"type": "string"
}
],
"title": "Id"
},
"name": {
"type": "string",
"format": "name",
"title": "Name"
},
"email": {
"type": "string",
"format": "email",
"title": "Email"
},
"email_verified": {
"type": "boolean",
"title": "Email Verified",
"default": false
},
"cpf": {
"anyOf": [
{
"type": "string",
"format": "cpf"
},
{
"type": "null"
}
],
"title": "Cpf"
}
},
"type": "object",
"required": [
"name",
"email"
],
"title": "User"
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
}
},
"securitySchemes": {
"bearerAuth": {
"type": "http",
"scheme": "bearer"
}
}
},
"security": [
{
"bearerAuth": []
}
]
},
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIBundle.SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
withCredentials: true,
persistAuthorization: true,
oauth2RedirectUrl: baseUrl + "?format=oauth2-redirect",
}
var ui = SwaggerUIBundle(swaggerUIOptions)
ui.specActions.updateUrl(currentUrl.pathname + "?format=json");
</script>
</html>

View File

@@ -18,19 +18,21 @@ def test_post_course(
http_api_proxy( http_api_proxy(
raw_path='/courses', raw_path='/courses',
method=HTTPMethod.POST, method=HTTPMethod.POST,
headers={'Tenant': '*'},
body={ body={
'course': { 'course': {
'name': 'pytest', 'name': 'pytest',
'access_period': 365, 'access_period': 365,
'cert': {
'exp_interval': 730, # 2 years
}, },
'org': { }
'id': '6RQuJ7koa9Gz4ZXTA4NeGR',
'name': 'EDUSEG',
},
}, },
), ),
lambda_context, lambda_context,
) )
print(r)
assert 'id' in json.loads(r['body']) assert 'id' in json.loads(r['body'])
assert r['statusCode'] == HTTPStatus.CREATED assert r['statusCode'] == HTTPStatus.CREATED

View File

@@ -1,4 +1,5 @@
{"id": {"S": "5OxmMjL-ujoR5IMGegQz"}, "sk": {"S": "0"}, "update_date": {"S": "2024-02-08T16:42:33.776409-03:00"}, "create_date": {"S": "2019-03-25T00:00:00-03:00"}, "email_verified": {"BOOL": true}, "cognito:sub": {"S": "58efed8d-d276-41a8-8502-4ab8b5a6415e"}, "cpf": {"S": "07879819908"}, "email": {"S": "sergio@somosbeta.com.br"}, "name": {"S": "S\u00e9rgio Rafael de Siqueira"}, "last_login": {"S": "2024-02-08T20:53:45.818126-03:00"}, "tenant:org_id": {"L": [{"S": "cJtK9SsnJhKPyxESe7g3DG"}, {"S": "edp8njvgQuzNkLx2ySNfAD"}, {"S": "8TVSi5oACLxTiT8ycKPmaQ"}]}} {"id": {"S": "5OxmMjL-ujoR5IMGegQz"}, "sk": {"S": "0"}, "update_date": {"S": "2024-02-08T16:42:33.776409-03:00"}, "create_date": {"S": "2019-03-25T00:00:00-03:00"}, "email_verified": {"BOOL": true}, "cognito:sub": {"S": "58efed8d-d276-41a8-8502-4ab8b5a6415e"}, "cpf": {"S": "07879819908"}, "email": {"S": "sergio@somosbeta.com.br"}, "name": {"S": "S\u00e9rgio Rafael de Siqueira"}, "last_login": {"S": "2024-02-08T20:53:45.818126-03:00"}, "tenant:org_id": {"L": [{"S": "cJtK9SsnJhKPyxESe7g3DG"}, {"S": "edp8njvgQuzNkLx2ySNfAD"}, {"S": "8TVSi5oACLxTiT8ycKPmaQ"}]}}
{"id": {"S": "5OxmMjL-ujoR5IMGegQz"}, "sk": {"S": "emails#sergio@somosbeta.com.br"}, "email_verified": {"BOOL": true}, "update_date": {"S": "2024-02-08T16:42:33.776409-03:00"}, "create_date": {"S": "2019-03-25T00:00:00-03:00"}, "email_primary": {"BOOL": true}, "mx_record_exists": {"BOOL": true}, "update_date": {"S": "2023-11-09T12:13:04.308986-03:00"}} {"id": {"S": "5OxmMjL-ujoR5IMGegQz"}, "sk": {"S": "emails#sergio@somosbeta.com.br"}, "email_verified": {"BOOL": true}, "update_date": {"S": "2024-02-08T16:42:33.776409-03:00"}, "create_date": {"S": "2019-03-25T00:00:00-03:00"}, "email_primary": {"BOOL": true}, "mx_record_exists": {"BOOL": true}, "update_date": {"S": "2023-11-09T12:13:04.308986-03:00"}}
{"id": {"S": "5OxmMjL-ujoR5IMGegQz"}, "sk": {"S": "acls#*"}, "create_date": {"S": "2022-06-13T15:00:24.309410-03:00"}, "roles": {"L": [{"S": "ADMIN"}]}}
{"id": {"S": "logs#5OxmMjL-ujoR5IMGegQz"}, "sk": {"S": "2024-02-08T16:42:33.776409-03:00"}, "action": {"S": "OPEN_EMAIL"}} {"id": {"S": "logs#5OxmMjL-ujoR5IMGegQz"}, "sk": {"S": "2024-02-08T16:42:33.776409-03:00"}, "action": {"S": "OPEN_EMAIL"}}
{"id": {"S": "logs#5OxmMjL-ujoR5IMGegQz"}, "sk": {"S": "2019-03-25T00:00:00-03:00"}, "action": {"S": "CLICK_EMAIL"}} {"id": {"S": "logs#5OxmMjL-ujoR5IMGegQz"}, "sk": {"S": "2019-03-25T00:00:00-03:00"}, "action": {"S": "CLICK_EMAIL"}}

View File

@@ -1,17 +1,19 @@
import auth as app import auth as app
from auth import _parse_bearer_token
from .conftest import LambdaContext from .conftest import LambdaContext
def test_bearer_jwt(lambda_context: LambdaContext): def test_bearer_jwt(lambda_context: LambdaContext, dynamodb_seeds):
# You should mock the Cognito user to pass the test
app.get_user = lambda *args, **kwargs: { app.get_user = lambda *args, **kwargs: {
'sub': '58efed8d-d276-41a8-8502-4ab8b5a6415e', 'sub': '58efed8d-d276-41a8-8502-4ab8b5a6415e',
'name': 'pytest', 'name': 'pytest',
'custom:user_id': '5OxmMjL-ujoR5IMGegQz',
} }
bearer_token = 'eyJraWQiOiJiSkZaSlNkMjhIeUtJNEQ0bG84SlkxSzk5NEdSUGhYU3YwV1BNczZ3aGVzPSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiI1OGVmZWQ4ZC1kMjc2LTQxYTgtODUwMi00YWI4YjVhNjQxNWUiLCJldmVudF9pZCI6IjJhNjlmOWE5LWQ2N2MtNDU0Ny04YzJlLWU5N2U2YzI5MzY4YSIsInRva2VuX3VzZSI6ImFjY2VzcyIsInNjb3BlIjoiYXdzLmNvZ25pdG8uc2lnbmluLnVzZXIuYWRtaW4iLCJhdXRoX3RpbWUiOjE3NDIzOTMxNjMsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC5zYS1lYXN0LTEuYW1hem9uYXdzLmNvbVwvc2EtZWFzdC0xX3M2WW1WU2ZYaiIsImV4cCI6MTc0MjQzNzA4NywiaWF0IjoxNzQyNDMzNDg3LCJqdGkiOiJmNjQ2MTdhMy04MzY2LTQxZWUtOGU2MC04YTA3YzA2N2UzOTMiLCJjbGllbnRfaWQiOiJsZGZ2ZHZrdDZjbDIybjdwMzN2cXRzZjRqIiwidXNlcm5hbWUiOiI1OGVmZWQ4ZC1kMjc2LTQxYTgtODUwMi00YWI4YjVhNjQxNWUifQ.dRhCaEItKEBbzrl7b5Ndh2xI8YGCK8trfKRs6YsW0cdZ_lU59oLhfd1bXEUe-dPyUb3zzGM41bSVUKHZTTlaMx8QNq2U4HbtrgQuQ77yXkN_i8Ft0DpLJiOFtBJzdx-LDUU8CwfjgLNN9fSUyUfkPkCnssBug0fIVcUJpixadk19-7_LJ3_gCPxlpcWT3vCb3yQtY8DzpW4iFcbqBUt1i6XWMTQHfTNamqzaWQ7m6QarefWK1gfDxGmfRg5qQJCRYzsQXcCe3JXRy0BgErpKrVHeIx0Dz8DyOWy1s0hSmv6n9ZPrHOFj13LprS7XihEK9DFwq4usolBungPLRIs_Og'
event = { event = {
'headers': { 'headers': {
'authorization': f'Bearer {bearer_token}', 'authorization': 'Bearer 3c51cdfd-d23e-47f9-8d7c-e3e31a432921',
}, },
} }
@@ -21,6 +23,24 @@ def test_bearer_jwt(lambda_context: LambdaContext):
'user': { 'user': {
'sub': '58efed8d-d276-41a8-8502-4ab8b5a6415e', 'sub': '58efed8d-d276-41a8-8502-4ab8b5a6415e',
'name': 'pytest', 'name': 'pytest',
'custom:user_id': '5OxmMjL-ujoR5IMGegQz',
} }
}, },
} }
def test_parse_bearer_token_api_key():
bearer = _parse_bearer_token(
'Bearer pptx-35433970-6857-4062-bb43-f71683b2f68e',
apikey_prefix='pptx',
)
assert bearer.token == '35433970-6857-4062-bb43-f71683b2f68e' # type: ignore
assert bearer.auth_type == 'API_KEY' # type: ignore
def test_parse_bearer_token_user_token():
bearer = _parse_bearer_token('Bearer d977f5a2-0302-4dd2-87c7-57414264d27a')
assert bearer.token == 'd977f5a2-0302-4dd2-87c7-57414264d27a' # type: ignore
assert bearer.auth_type == 'USER_TOKEN' # type: ignore