List call_requests check auth with dependency

pull/931/head
kompotkot 2023-10-04 10:50:09 +00:00
rodzic a46afe65d7
commit a92aeed916
3 zmienionych plików z 119 dodań i 54 usunięć

Wyświetl plik

@ -430,7 +430,7 @@ def create_request_calls(
return len(call_specs)
def get_call_requests(
def get_call_request(
db_session: Session,
request_id: uuid.UUID,
) -> Tuple[CallRequest, RegisteredContract]:

Wyświetl plik

@ -6,8 +6,9 @@ from uuid import UUID
from bugout.data import BugoutResource, BugoutResources, BugoutUser
from bugout.exceptions import BugoutResponseException
from fastapi import HTTPException, Request, Response
from fastapi import Header, HTTPException, Request, Response
from pydantic import AnyHttpUrl, parse_obj_as
from starlette.datastructures import Headers
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.middleware.cors import CORSMiddleware
from starlette.responses import Response
@ -34,6 +35,89 @@ from .settings import bugout_client as bc
logger = logging.getLogger(__name__)
class InvalidAuthHeaderFormat(Exception):
"""
Raised when authorization header not pass validation.
"""
class BugoutUnverifiedAuth(Exception):
"""
Raised when attempted access by unverified Brood account.
"""
class BugoutAuthWrongApp(Exception):
"""
Raised when user does not belong to this application.
"""
def parse_auth_header(auth_header: str) -> Tuple[str, str]:
"""
Returns: auth_format and user_token passed in authorization header.
"""
auth_list = auth_header.split()
if len(auth_list) != 2:
raise InvalidAuthHeaderFormat("Wrong authorization header")
return auth_list[0], auth_list[1]
def bugout_auth(token: str) -> BugoutUser:
"""
Extended bugout.get_user with additional checks.
"""
user: BugoutUser = bc.get_user(token)
if not user.verified:
raise BugoutUnverifiedAuth("Only verified accounts can have access")
if str(user.application_id) != str(MOONSTREAM_APPLICATION_ID):
raise BugoutAuthWrongApp("User does not belong to this application")
return user
def user_for_auth_header(
authorization: str = Header(None),
) -> Optional[BugoutUser]:
"""
Fetch Bugout user if authorization token provided.
"""
user: Optional[BugoutUser] = None
if authorization is not None:
user_token: str = ""
try:
_, user_token = parse_auth_header(auth_header=authorization)
except InvalidAuthHeaderFormat:
raise EngineHTTPException(
status_code=403, detail="Wrong authorization header"
)
except Exception as e:
logger.error(f"Error processing Brood response: {str(e)}")
raise EngineHTTPException(status_code=500, detail="Internal server error")
if user_token != "":
try:
user: BugoutUser = bugout_auth(token=user_token)
except BugoutUnverifiedAuth:
logger.info(f"Attempted access by unverified Brood account: {user.id}")
raise EngineHTTPException(
status_code=403,
detail="Only verified accounts can have access",
)
except BugoutAuthWrongApp:
raise EngineHTTPException(
status_code=403, detail="User does not belong to this application"
)
except BugoutResponseException as e:
raise HTTPException(status_code=e.status_code, detail=e.detail)
except Exception as e:
logger.error(f"Error processing Brood response: {str(e)}")
raise HTTPException(status_code=500, detail="Internal server error")
return user
class BroodAuthMiddleware(BaseHTTPMiddleware):
"""
Checks the authorization header on the request. If it represents a verified Brood user,
@ -59,28 +143,33 @@ class BroodAuthMiddleware(BaseHTTPMiddleware):
if path in self.whitelist.keys() and self.whitelist[path] == method:
return await call_next(request)
authorization_header = request.headers.get("authorization")
if authorization_header is None:
authorization = request.headers.get("authorization")
if authorization is None:
return Response(
status_code=403, content="No authorization header passed with request"
status_code=403,
content="No authorization header passed with request",
)
user_token_list = authorization_header.split()
if len(user_token_list) != 2:
return Response(status_code=403, content="Wrong authorization header")
user_token: str = user_token_list[-1]
try:
user: BugoutUser = bc.get_user(user_token)
if not user.verified:
logger.info(f"Attempted access by unverified Brood account: {user.id}")
return Response(
status_code=403,
content="Only verified accounts can have access",
)
if str(user.application_id) != str(MOONSTREAM_APPLICATION_ID):
return Response(
status_code=403, content="User does not belong to this application"
)
_, user_token = parse_auth_header(auth_header=authorization)
except InvalidAuthHeaderFormat:
return Response(status_code=403, content="Wrong authorization header")
except Exception as e:
logger.error(f"Error processing Brood response: {str(e)}")
return Response(status_code=500, content="Internal server error")
try:
user: BugoutUser = bugout_auth(token=user_token)
except BugoutUnverifiedAuth:
logger.info(f"Attempted access by unverified Brood account: {user.id}")
return Response(
status_code=403,
content="Only verified accounts can have access",
)
except BugoutAuthWrongApp:
return Response(
status_code=403, content="User does not belong to this application"
)
except BugoutResponseException as e:
return Response(status_code=e.status_code, content=e.detail)
except Exception as e:

Wyświetl plik

@ -9,8 +9,7 @@ import logging
from typing import Dict, List, Optional
from uuid import UUID
from bugout.data import BugoutResource, BugoutResources, BugoutUser
from bugout.exceptions import BugoutResponseException
from bugout.data import BugoutUser
from fastapi import Body, Depends, FastAPI, Path, Query, Request
from sqlalchemy.exc import NoResultFound
from sqlalchemy.orm import Session
@ -20,9 +19,9 @@ from ..middleware import (
BroodAuthMiddleware,
BugoutCORSMiddleware,
EngineHTTPException,
user_for_auth_header,
)
from ..settings import DOCS_TARGET_PATH, MOONSTREAM_APPLICATION_ID
from ..settings import bugout_client as bc
from ..settings import DOCS_TARGET_PATH
from ..version import VERSION
logger = logging.getLogger(__name__)
@ -285,9 +284,12 @@ async def call_request_types_route(
return call_request_types
@app.get("/requests", tags=["requests"], response_model=List[data.CallRequestResponse])
@app.get(
"/requests",
tags=["requests"],
response_model=List[data.CallRequestResponse],
)
async def list_requests_route(
request: Request,
contract_id: Optional[UUID] = Query(None),
contract_address: Optional[str] = Query(None),
caller: str = Query(...),
@ -295,6 +297,7 @@ async def list_requests_route(
offset: Optional[int] = Query(None),
show_expired: bool = Query(False),
show_before_live_at: bool = Query(False),
user: Optional[BugoutUser] = Depends(user_for_auth_header),
db_session: Session = Depends(db.yield_db_read_only_session),
) -> List[data.CallRequestResponse]:
"""
@ -302,33 +305,6 @@ async def list_requests_route(
At least one of `contract_id` or `contract_address` must be provided as query parameters.
"""
authorization_header = request.headers.get("authorization")
user: Optional[BugoutUser] = None
if authorization_header is not None:
try:
auth_list = authorization_header.split()
if len(auth_list) != 2:
return EngineHTTPException(
status_code=403, content="Wrong authorization header"
)
user = bc.get_user(auth_list[-1])
if not user.verified:
logger.info(f"Attempted access by unverified Brood account: {user.id}")
return EngineHTTPException(
status_code=403,
content="Only verified accounts can have access",
)
if str(user.application_id) != str(MOONSTREAM_APPLICATION_ID):
return EngineHTTPException(
status_code=403, content="User does not belong to this application"
)
except BugoutResponseException as e:
return EngineHTTPException(status_code=e.status_code, content=e.detail)
except Exception as e:
logger.error(f"Error processing Brood response: {str(e)}")
return EngineHTTPException(status_code=500, content="Internal server error")
try:
requests = contracts_actions.list_call_requests(
db_session=db_session,
@ -364,7 +340,7 @@ async def get_request(
At least one of `contract_id` or `contract_address` must be provided as query parameters.
"""
try:
request = contracts_actions.get_call_requests(
request = contracts_actions.get_call_request(
db_session=db_session,
request_id=request_id,
)