From 8e07c299c46b87ced01b8fe42c37afb3344afae8 Mon Sep 17 00:00:00 2001 From: Ian Costanzo Date: Mon, 31 Jan 2022 10:41:08 -0800 Subject: [PATCH 1/2] Refactor tenant api's into sub-app Signed-off-by: Ian Costanzo --- services/traction/api/core/config.py | 3 + services/traction/api/endpoints/routes/api.py | 6 +- .../api/endpoints/routes/tenant_api.py | 9 +++ services/traction/api/main.py | 43 ++------------ services/traction/api/tenant_main.py | 56 +++++++++++++++++++ services/traction/api/tenant_security.py | 2 +- 6 files changed, 75 insertions(+), 44 deletions(-) create mode 100644 services/traction/api/endpoints/routes/tenant_api.py create mode 100644 services/traction/api/tenant_main.py diff --git a/services/traction/api/core/config.py b/services/traction/api/core/config.py index e5a050300..48674a6ae 100644 --- a/services/traction/api/core/config.py +++ b/services/traction/api/core/config.py @@ -18,6 +18,9 @@ class GlobalConfig(BaseSettings): TITLE: str = "Traction" DESCRIPTION: str = "A digital wallet solution for organizations" + TENANT_TITLE: str = "Traction" + TENANT_DESCRIPTION: str = "A digital wallet solution for organizations" + ENVIRONMENT: EnvironmentEnum DEBUG: bool = False TESTING: bool = False diff --git a/services/traction/api/endpoints/routes/api.py b/services/traction/api/endpoints/routes/api.py index 3a258164e..88995c8bd 100644 --- a/services/traction/api/endpoints/routes/api.py +++ b/services/traction/api/endpoints/routes/api.py @@ -1,11 +1,7 @@ from fastapi import APIRouter -from api.endpoints.routes import innkeeper, tenants, connections, ledger +from api.endpoints.routes import innkeeper, tenants api_router = APIRouter() -api_router.include_router( - connections.router, prefix="/connections", tags=["connections"] -) -api_router.include_router(ledger.router, prefix="/ledger", tags=["ledger"]) api_router.include_router(innkeeper.router, prefix="/innkeeper", tags=["innkeeper"]) api_router.include_router(tenants.router, prefix="/tenants", tags=["tenants"]) diff --git a/services/traction/api/endpoints/routes/tenant_api.py b/services/traction/api/endpoints/routes/tenant_api.py new file mode 100644 index 000000000..a030e62bc --- /dev/null +++ b/services/traction/api/endpoints/routes/tenant_api.py @@ -0,0 +1,9 @@ +from fastapi import APIRouter + +from api.endpoints.routes import connections, ledger + +tenant_router = APIRouter() +tenant_router.include_router( + connections.router, prefix="/connections", tags=["connections"] +) +tenant_router.include_router(ledger.router, prefix="/ledger", tags=["ledger"]) diff --git a/services/traction/api/main.py b/services/traction/api/main.py index 0c19a3581..c8cafc02e 100644 --- a/services/traction/api/main.py +++ b/services/traction/api/main.py @@ -1,45 +1,27 @@ import os import time -from datetime import timedelta import uvicorn -from fastapi import Depends, FastAPI, HTTPException, Request, status -from fastapi.security import OAuth2PasswordRequestForm -from starlette.middleware import Middleware +from fastapi import FastAPI, Request, status from starlette.responses import JSONResponse -from starlette_context import plugins -from starlette_context.middleware import RawContextMiddleware from api.db.errors import DoesNotExist, AlreadyExists from api.endpoints.routes.api import api_router from api.endpoints.routes.webhooks import get_webhookapp -from api.tenant_security import ( - TenantToken, - authenticate_tenant, - create_access_token, - JWTTFetchingMiddleware, -) from api.core.config import settings +from api.tenant_main import get_tenantapp os.environ["TZ"] = settings.TIMEZONE time.tzset() -middleware = [ - Middleware( - RawContextMiddleware, - plugins=(plugins.RequestIdPlugin(), plugins.CorrelationIdPlugin()), - ), - Middleware(JWTTFetchingMiddleware), -] - def get_application() -> FastAPI: application = FastAPI( title=settings.TITLE, description=settings.DESCRIPTION, debug=settings.DEBUG, - middleware=middleware, + middleware=None, ) application.include_router(api_router, prefix=settings.API_V1_STR) return application @@ -48,6 +30,8 @@ def get_application() -> FastAPI: app = get_application() webhook_app = get_webhookapp() app.mount("/webhook", webhook_app) +tenant_app = get_tenantapp() +app.mount("/tenant", tenant_app) @app.exception_handler(DoesNotExist) @@ -71,23 +55,6 @@ def main(): return {"status": "ok", "health": "ok"} -@app.post("/token", response_model=TenantToken) -async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()): - tenant = await authenticate_tenant(form_data.username, form_data.password) - if not tenant: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Incorrect wallet_id or wallet_key", - headers={"WWW-Authenticate": "Bearer"}, - ) - access_token_expires = timedelta(minutes=settings.JWT_ACCESS_TOKEN_EXPIRE_MINUTES) - access_token = create_access_token( - data={"sub": tenant["wallet_id"], "key": tenant["wallet_token"]}, - expires_delta=access_token_expires, - ) - return {"access_token": access_token, "token_type": "bearer"} - - if __name__ == "__main__": print("main.") uvicorn.run(app, host="0.0.0.0", port=8080) diff --git a/services/traction/api/tenant_main.py b/services/traction/api/tenant_main.py new file mode 100644 index 000000000..f9bf68cf0 --- /dev/null +++ b/services/traction/api/tenant_main.py @@ -0,0 +1,56 @@ +from datetime import timedelta + +from fastapi import APIRouter, Depends, FastAPI, HTTPException, status +from fastapi.security import OAuth2PasswordRequestForm +from starlette.middleware import Middleware +from starlette_context import plugins +from starlette_context.middleware import RawContextMiddleware + +from api.endpoints.routes.tenant_api import tenant_router +from api.tenant_security import ( + TenantToken, + authenticate_tenant, + create_access_token, + JWTTFetchingMiddleware, +) +from api.core.config import settings + + +middleware = [ + Middleware( + RawContextMiddleware, + plugins=(plugins.RequestIdPlugin(), plugins.CorrelationIdPlugin()), + ), + Middleware(JWTTFetchingMiddleware), +] + +router = APIRouter() + + +def get_tenantapp() -> FastAPI: + application = FastAPI( + title=settings.TENANT_TITLE, + description=settings.TENANT_DESCRIPTION, + debug=settings.DEBUG, + middleware=middleware, + ) + application.include_router(tenant_router, prefix=settings.API_V1_STR) + application.include_router(router, prefix="") + return application + + +@router.post("/token", response_model=TenantToken) +async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()): + tenant = await authenticate_tenant(form_data.username, form_data.password) + if not tenant: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Incorrect wallet_id or wallet_key", + headers={"WWW-Authenticate": "Bearer"}, + ) + access_token_expires = timedelta(minutes=settings.JWT_ACCESS_TOKEN_EXPIRE_MINUTES) + access_token = create_access_token( + data={"sub": tenant["wallet_id"], "key": tenant["wallet_token"]}, + expires_delta=access_token_expires, + ) + return {"access_token": access_token, "token_type": "bearer"} diff --git a/services/traction/api/tenant_security.py b/services/traction/api/tenant_security.py index 0423cbfd5..d34c1a7dc 100644 --- a/services/traction/api/tenant_security.py +++ b/services/traction/api/tenant_security.py @@ -26,7 +26,7 @@ class TenantTokenData(BaseModel): bearer_token: Optional[str] = None -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") +oauth2_scheme = OAuth2PasswordBearer(tokenUrl="tenant/token") class JWTTFetchingMiddleware(BaseHTTPMiddleware): From 4bc35e50a046644cde6f1398467eefdd34af978b Mon Sep 17 00:00:00 2001 From: Ian Costanzo Date: Mon, 31 Jan 2022 10:53:51 -0800 Subject: [PATCH 2/2] Fix endpoint Signed-off-by: Ian Costanzo --- services/traction/api/tenant_security.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/traction/api/tenant_security.py b/services/traction/api/tenant_security.py index d34c1a7dc..0423cbfd5 100644 --- a/services/traction/api/tenant_security.py +++ b/services/traction/api/tenant_security.py @@ -26,7 +26,7 @@ class TenantTokenData(BaseModel): bearer_token: Optional[str] = None -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="tenant/token") +oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") class JWTTFetchingMiddleware(BaseHTTPMiddleware):