diff --git a/gateway/auth.py b/gateway/auth.py index cc3a098..18d15a8 100644 --- a/gateway/auth.py +++ b/gateway/auth.py @@ -2,18 +2,18 @@ from urllib.parse import urljoin import requests -from fastapi import Security, HTTPException, Depends -from fastapi.security import OAuth2AuthorizationCodeBearer +from fastapi import Security, HTTPException +from fastapi.security import OAuth2AuthorizationCodeBearer, OAuth2PasswordBearer from jose import jwt, JOSEError from starlette import status from gateway.conf import gateway_settings -from gateway.models import AuthConfiguration, User +from gateway.models import AuthConfiguration IDP_ISSUER_URL = urljoin(gateway_settings.IDP_URL, "/".join(["realms", gateway_settings.IDP_REALM])) # IDP i.e. Keycloak -idp_settings = AuthConfiguration( +realm_idp_settings = AuthConfiguration( server_url=gateway_settings.IDP_URL, # Take last part of issuer URL for realm realm=gateway_settings.IDP_REALM, @@ -24,9 +24,14 @@ issuer_url=IDP_ISSUER_URL, ) -oauth2_scheme = OAuth2AuthorizationCodeBearer( - authorizationUrl=idp_settings.authorization_url, - tokenUrl=idp_settings.token_url, +realm_oauth2_scheme = OAuth2AuthorizationCodeBearer( + authorizationUrl=realm_idp_settings.authorization_url, + tokenUrl=realm_idp_settings.token_url, +) + +hub_oauth2_scheme = OAuth2PasswordBearer( + # authorizationUrl=gateway_settings.HUB_AUTH_SERVICE_URL + "/authorize", + tokenUrl=gateway_settings.HUB_AUTH_SERVICE_URL + "/token", ) @@ -35,12 +40,12 @@ async def get_idp_public_key() -> str: """Get the public key.""" return ( "-----BEGIN PUBLIC KEY-----\n" - f"{requests.get(idp_settings.issuer_url).json().get('public_key')}" + f"{requests.get(realm_idp_settings.issuer_url).json().get('public_key')}" "\n-----END PUBLIC KEY-----" ) -async def get_token(token: str = Security(oauth2_scheme)) -> dict: +async def verify_realm_idp_token(token: str = Security(realm_oauth2_scheme)) -> dict: """Decode the auth token using keycloak's public key.""" try: return jwt.decode( @@ -56,23 +61,27 @@ async def get_token(token: str = Security(oauth2_scheme)) -> dict: headers={"WWW-Authenticate": "Bearer"}, ) + except jwt.ExpiredSignatureError: + raise HTTPException( + status_code=401, + detail='Authorization token expired') -async def get_user_info(payload: dict = Depends(get_token)) -> User: - """Return User info from the IDP. Mostly for debugging.""" - try: - return User( - id=payload.get("sub"), - username=payload.get("preferred_username"), - email=payload.get("email"), - first_name=payload.get("given_name"), - last_name=payload.get("family_name"), - realm_roles=payload.get("realm_access", {}).get("roles", []), - client_roles=payload.get("realm_access", {}).get("roles", []), - ) + except jwt.JWTClaimsError: + raise HTTPException( + status_code=401, + detail='Incorrect claims, check the audience and issuer.') - except JOSEError as e: + except Exception: raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail=str(e), # Invalid authentication credentials - headers={"WWW-Authenticate": "Bearer"}, - ) + status_code=401, + detail='Unable to parse authentication token') + + +async def get_hub_token(): + """Get a JWT from the Hub.""" + resp = requests.post( + gateway_settings.HUB_AUTH_SERVICE_URL + "/token", + data={"username": "admin", "password": "start123"} + ) + token_data = resp.json() + return token_data diff --git a/gateway/routers/hub.py b/gateway/routers/hub.py index 5aa3f81..1323af1 100644 --- a/gateway/routers/hub.py +++ b/gateway/routers/hub.py @@ -1,7 +1,13 @@ """EPs for Hub provided information.""" -from fastapi import APIRouter +from fastapi import APIRouter, Security +from starlette import status +from starlette.requests import Request +from starlette.responses import Response +from gateway.auth import hub_oauth2_scheme +from gateway.conf import gateway_settings +from gateway.core import route from gateway.models import ImageDataResponse, ContainerResponse hub_router = APIRouter( @@ -76,3 +82,20 @@ async def get_vault_status(): } } return dummy_data + + +@route( + request_method=hub_router.get, + path="/projects", + status_code=status.HTTP_200_OK, + service_url=gateway_settings.HUB_SERVICE_URL, + response_model=None, + dependencies=[ + Security(hub_oauth2_scheme) # TODO: move to router definition + ] +) +async def hub_projects( + request: Request, + response: Response, +): + pass diff --git a/gateway/server.py b/gateway/server.py index 5b1caf1..080253c 100644 --- a/gateway/server.py +++ b/gateway/server.py @@ -1,10 +1,10 @@ """Methods for verifying auth.""" + import uvicorn from fastapi import FastAPI from starlette import status from starlette.middleware.cors import CORSMiddleware -from gateway.auth import idp_settings from gateway.models import HealthCheck from gateway.routers.hub import hub_router from gateway.routers.k8s import k8s_router @@ -23,12 +23,12 @@ openapi_tags=tags_metadata, title="FLAME API", description="Test API for FLAME project", - swagger_ui_init_oauth={ - "usePkceWithAuthorizationCodeGrant": True, - # Auth fill client ID for the docs with the below value - "clientId": idp_settings.client_id, # default client-id is Keycloak - "clientSecret": idp_settings.client_secret, - }, + # swagger_ui_init_oauth={ + # "usePkceWithAuthorizationCodeGrant": True, + # # Auth fill client ID for the docs with the below value + # "clientId": realm_idp_settings.client_id, # default client-id is Keycloak + # "clientSecret": realm_idp_settings.client_secret, + # }, ) app.add_middleware(