diff --git a/http-api/middlewares/tenant_middelware.py b/http-api/middlewares/tenant_middelware.py index fa8341d..6c37ba8 100644 --- a/http-api/middlewares/tenant_middelware.py +++ b/http-api/middlewares/tenant_middelware.py @@ -23,8 +23,28 @@ class Tenant(BaseModel): class TenantMiddleware(BaseMiddlewareHandler): - def __init__(self, collect: DynamoDBCollection) -> None: + """ + Middleware that associates a Tenant instance with the request context based on the authentication flow. + + For API authentication (`AuthFlowType.API_AUTH`), it assigns tenant information directly from the authorizer context. + For User authentication (`AuthFlowType.USER_AUTH`), it gets the Tenant ID from the specified request header. + + Parameters + ---------- + collect : DynamoDBCollection + The DynamoDB collection used to validate user access and retrieve tenant information. + header : str, optional + The request header name containing the tenant ID. Defaults to `'X-Tenant'`. + """ + + def __init__( + self, + collect: DynamoDBCollection, + /, + header: str = 'X-Tenant', + ) -> None: self.collect = collect + self.header = header def handler( self, @@ -40,7 +60,7 @@ class TenantMiddleware(BaseMiddlewareHandler): if auth_flow_type == AuthFlowType.USER_AUTH: app.append_context( tenant=_tenant( - app.current_event.headers.get('x-tenant'), + app.current_event.headers.get(self.header), app.context.get('user'), # type: ignore collect=self.collect, ) @@ -50,8 +70,8 @@ class TenantMiddleware(BaseMiddlewareHandler): class ForbiddenError(ServiceError): - def __init__(self, msg: str): - super().__init__(HTTPStatus.FORBIDDEN, msg) + def __init__(self, *args, **kwargs): + super().__init__(HTTPStatus.FORBIDDEN, 'Deny') def _tenant( @@ -60,14 +80,39 @@ def _tenant( /, collect: DynamoDBCollection, ) -> Tenant: + """Get a Tenant instance based on the provided tenant_id and user's access permissions. + + Parameters + ---------- + tenant_id : str | None + The identifier of the tenant. Must not be None or empty. + user : User + The user attempting to access the tenant. + collect : DynamoDBCollection + The DynamoDB collection used to retrieve tenant information. + + Returns + ------- + Tenant + The Tenant instance corresponding to the provided tenant_id. + + Raises + ------ + BadRequestError + If tenant_id is not provided. + ForbiddenError + If the user lacks the necessary ACL permissions for the specified tenant_id. + """ if not tenant_id: raise BadRequestError('Missing tenant') + # Ensure user has ACL collect.get_item( KeyPair(user.id, ComposeKey(tenant_id, prefix='acls')), exception_cls=ForbiddenError, ) + # For root tenant, provide the default Tenant if tenant_id == '*': return Tenant(id=tenant_id, name='default')