Skip to content
Merged
10 changes: 5 additions & 5 deletions auth/validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from auth.config import Settings, get_settings
from schemas.tokens import AccessTokenPayload
from schemas.user import User
from schemas.user import SessionUser

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

Expand Down Expand Up @@ -58,13 +58,13 @@ def get_rsa_key(token: str, settings: Settings) -> jwk.RSAKey | None: # type: i


def get_current_user(token: str = Depends(oauth2_scheme),
settings: Settings = Depends(get_settings)) -> User:
settings: Settings = Depends(get_settings)) -> SessionUser:
access_token = verify_jwt(token, settings=settings)
return User(access_token=access_token)
return SessionUser(access_token=access_token)


def user_is_admin(current_user: Annotated[User, Depends(get_current_user)],
settings: Annotated[Settings, Depends(get_settings)]) -> User:
def user_is_admin(current_user: Annotated[SessionUser, Depends(get_current_user)],
settings: Annotated[Settings, Depends(get_settings)]) -> SessionUser:
if not current_user.is_admin(settings=settings):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
Expand Down
18 changes: 9 additions & 9 deletions auth0/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import httpx

from auth0.schemas import Auth0UserResponse
from schemas.biocommons import BiocommonsAuth0User


class Auth0Client:
Expand All @@ -17,9 +17,9 @@ def __init__(self, domain: str, management_token: str):
@staticmethod
def _convert_users(resp: httpx.Response):
"""Convert a list of Auth0UserResponse objects from a response."""
return [Auth0UserResponse(**user) for user in resp.json()]
return [BiocommonsAuth0User(**user) for user in resp.json()]

def get_users(self, page: Optional[int] = None, per_page: Optional[int] = None) -> list[Auth0UserResponse]:
def get_users(self, page: Optional[int] = None, per_page: Optional[int] = None) -> list[BiocommonsAuth0User]:
params = {}
if page is not None:
# Convert from 1-based pagination to 0-based.
Expand All @@ -31,12 +31,12 @@ def get_users(self, page: Optional[int] = None, per_page: Optional[int] = None)
resp = self._client.get(url, params=params)
return self._convert_users(resp)

def get_user(self, user_id: str) -> Auth0UserResponse:
def get_user(self, user_id: str) -> BiocommonsAuth0User:
url = f"https://{self.domain}/api/v2/users/{user_id}"
resp = self._client.get(url)
return Auth0UserResponse(**resp.json())
return BiocommonsAuth0User(**resp.json())

def _search_users(self, query: str, page: Optional[int] = None, per_page: Optional[int] = None) -> list[Auth0UserResponse]:
def _search_users(self, query: str, page: Optional[int] = None, per_page: Optional[int] = None) -> list[BiocommonsAuth0User]:
params = {"q": query, "search_engine": "v3"}
if page is not None:
# Convert from 1-based pagination to 0-based.
Expand All @@ -58,15 +58,15 @@ def _search_users(self, query: str, page: Optional[int] = None, per_page: Option
)
return self._convert_users(resp)

def get_approved_users(self, page: Optional[int] = None, per_page: Optional[int] = None) -> list[Auth0UserResponse]:
def get_approved_users(self, page: Optional[int] = None, per_page: Optional[int] = None) -> list[BiocommonsAuth0User]:
# TODO: also search for approved resources? (with OR)
approved_query = 'app_metadata.services.status:"approved"'
return self._search_users(approved_query, page, per_page)

def get_pending_users(self, page: Optional[int] = None, per_page: Optional[int] = None) -> list[Auth0UserResponse]:
def get_pending_users(self, page: Optional[int] = None, per_page: Optional[int] = None) -> list[BiocommonsAuth0User]:
pending_query = 'app_metadata.services.status:"pending"'
return self._search_users(pending_query, page, per_page)

def get_revoked_users(self, page: Optional[int] = None, per_page: Optional[int] = None) -> list[Auth0UserResponse]:
def get_revoked_users(self, page: Optional[int] = None, per_page: Optional[int] = None) -> list[BiocommonsAuth0User]:
revoked_query = 'app_metadata.services.status:"revoked"'
return self._search_users(revoked_query, page, per_page)
36 changes: 0 additions & 36 deletions auth0/schemas.py

This file was deleted.

14 changes: 6 additions & 8 deletions routers/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
from auth.management import get_management_token
from auth.validator import get_current_user, user_is_admin
from auth0.client import Auth0Client
from auth0.schemas import Auth0UserResponse
from routers.user import update_user_metadata
from schemas.user import User
from schemas.biocommons import BiocommonsAuth0User
from schemas.user import SessionUser

logger = logging.getLogger('uvicorn.error')

Expand Down Expand Up @@ -53,10 +53,8 @@ def get_auth0_client(settings: Settings = Depends(get_settings),
return Auth0Client(settings.auth0_domain, management_token=management_token)


# TODO: May need to paginate this response to make sure we get all
# of them
@router.get("/users",
response_model=list[Auth0UserResponse])
response_model=list[BiocommonsAuth0User],)
def get_users(client: Annotated[Auth0Client, Depends(get_auth0_client)],
pagination: Annotated[PaginationParams, Depends(get_pagination_params)]):
resp = client.get_users(page=pagination.page, per_page=pagination.per_page)
Expand Down Expand Up @@ -86,7 +84,7 @@ def get_revoked_users(client: Annotated[Auth0Client, Depends(get_auth0_client)],


@router.get("/users/{user_id}",
response_model=Auth0UserResponse)
response_model=BiocommonsAuth0User)
def get_user(user_id: Annotated[str, UserIdParam],
client: Annotated[Auth0Client, Depends(get_auth0_client)]):
return client.get_user(user_id)
Expand All @@ -96,7 +94,7 @@ def get_user(user_id: Annotated[str, UserIdParam],
def approve_service(user_id: Annotated[str, UserIdParam],
service_id: Annotated[str, ServiceIdParam],
client: Annotated[Auth0Client, Depends(get_auth0_client)],
approving_user: Annotated[User, Depends(get_current_user)]):
approving_user: Annotated[SessionUser, Depends(get_current_user)]):
user = client.get_user(user_id=user_id)
# Need to fetch full user info currently to get email address, not in access token
approving_user_data = client.get_user(user_id=approving_user.access_token.sub)
Expand All @@ -118,7 +116,7 @@ def approve_service(user_id: Annotated[str, UserIdParam],
def revoke_service(user_id: Annotated[str, UserIdParam],
service_id: Annotated[str, ServiceIdParam],
client: Annotated[Auth0Client, Depends(get_auth0_client)],
revoking_user: Annotated[User, Depends(get_current_user)]):
revoking_user: Annotated[SessionUser, Depends(get_current_user)]):
"""
Revoke a service and all associated resources for a user.
"""
Expand Down
15 changes: 3 additions & 12 deletions routers/bpa_register.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,16 @@

from fastapi import APIRouter, Depends, HTTPException
from httpx import AsyncClient
from pydantic import BaseModel, EmailStr

from auth.config import Settings, get_settings
from auth.management import get_management_token
from schemas.bpa import BPARegisterData
from schemas.biocommons import BiocommonsRegisterData
from schemas.bpa import BPARegistrationRequest
from schemas.service import Resource, Service

router = APIRouter(prefix="/bpa", tags=["bpa", "registration"])


class BPARegistrationRequest(BaseModel):
username: str
fullname: str
email: EmailStr
reason: str
password: str
organizations: Dict[str, bool]


@router.post(
"/register",
response_model=Dict[str, Any],
Expand Down Expand Up @@ -64,7 +55,7 @@ async def register_bpa_user(
)

# Create Auth0 user data
user_data = BPARegisterData.from_registration(
user_data = BiocommonsRegisterData.from_bpa_registration(
registration=registration, bpa_service=bpa_service
)

Expand Down
3 changes: 2 additions & 1 deletion routers/galaxy_register.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from auth.config import Settings, get_settings
from auth.management import get_management_token
from register.tokens import create_registration_token, verify_registration_token
from schemas.biocommons import BiocommonsRegisterData
from schemas.galaxy import GalaxyRegistrationData

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -38,7 +39,7 @@ def register(
logger.debug("Getting management token.")
management_token = get_management_token(settings=settings)
headers = {"Authorization": f"Bearer {management_token}"}
user_data = registration_data.to_auth0_create_user_data()
user_data = BiocommonsRegisterData.from_galaxy_registration(registration_data)
logger.debug("Registering with Auth0 management API")
resp = httpx.post(url, json=user_data.model_dump(), headers=headers)
if resp.status_code != 201:
Expand Down
31 changes: 16 additions & 15 deletions routers/user.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
from datetime import datetime, timezone
from typing import Any, Dict, List
from typing import Annotated, Any, Dict, List

from fastapi import APIRouter, Depends, HTTPException
from httpx import AsyncClient

from auth.config import Settings, get_settings
from auth.management import get_management_token
from auth.validator import get_current_user
from schemas.biocommons import BiocommonsAuth0User
from schemas.requests import ResourceRequest, ServiceRequest
from schemas.service import Auth0User, Resource, Service
from schemas.user import User
from schemas.service import Resource, Service
from schemas.user import SessionUser

router = APIRouter(
prefix="/me", tags=["user"], responses={401: {"description": "Unauthorized"}}
)


async def get_user_data(user: User, settings: Settings) -> Auth0User:
async def get_user_data(user: SessionUser, settings: Annotated[Settings, Depends(get_settings)]) -> BiocommonsAuth0User:
"""Fetch and return user data from Auth0."""
url = f"https://{settings.auth0_domain}/api/v2/users/{user.access_token.sub}"
token = get_management_token(settings=settings)
Expand All @@ -30,7 +31,7 @@ async def get_user_data(user: User, settings: Settings) -> Auth0User:
status_code=403,
detail="Failed to fetch user data",
)
return Auth0User(**response.json())
return BiocommonsAuth0User(**response.json())
except HTTPException:
raise
except Exception as e:
Expand Down Expand Up @@ -69,49 +70,49 @@ async def update_user_metadata(


@router.get("/services", response_model=Dict[str, List[Service]])
async def get_services(user: User = Depends(get_current_user)):
async def get_services(user: Annotated[SessionUser, Depends(get_current_user)]):
"""Get all services for the authenticated user."""
user_data = await get_user_data(user)
return {"services": user_data.app_metadata.services}


@router.get("/services/approved", response_model=Dict[str, List[Service]])
async def get_approved_services(user: User = Depends(get_current_user)):
async def get_approved_services(user: Annotated[SessionUser, Depends(get_current_user)]):
"""Get approved services for the authenticated user."""
user_data = await get_user_data(user)
return {"approved_services": user_data.approved_services}


@router.get("/services/pending", response_model=Dict[str, List[Service]])
async def get_pending_services(user: User = Depends(get_current_user)):
async def get_pending_services(user: Annotated[SessionUser, Depends(get_current_user)]):
"""Get pending services for the authenticated user."""
user_data = await get_user_data(user)
return {"pending_services": user_data.pending_services}


@router.get("/resources", response_model=Dict[str, List[Resource]])
async def get_resources(user: User = Depends(get_current_user)):
async def get_resources(user: Annotated[SessionUser, Depends(get_current_user)]):
"""Get all resources for the authenticated user."""
user_data = await get_user_data(user)
return {"resources": user_data.app_metadata.get_all_resources()}


@router.get("/resources/approved", response_model=Dict[str, List[Resource]])
async def get_approved_resources(user: User = Depends(get_current_user)):
async def get_approved_resources(user: Annotated[SessionUser, Depends(get_current_user)]):
"""Get approved resources for the authenticated user."""
user_data = await get_user_data(user)
return {"approved_resources": user_data.approved_resources}


@router.get("/resources/pending", response_model=Dict[str, List[Resource]])
async def get_pending_resources(user: User = Depends(get_current_user)):
async def get_pending_resources(user: Annotated[SessionUser, Depends(get_current_user)]):
"""Get pending resources for the authenticated user."""
user_data = await get_user_data(user)
return {"pending_resources": user_data.pending_resources}


@router.get("/all/pending", response_model=Dict[str, List[Any]])
async def get_all_pending(user: User = Depends(get_current_user)):
async def get_all_pending(user: Annotated[SessionUser, Depends(get_current_user)]):
"""Get all pending services and resources."""
user_data = await get_user_data(user)
return {
Expand All @@ -130,8 +131,8 @@ async def get_all_pending(user: User = Depends(get_current_user)):
},
)
async def request_service(
service_request: ServiceRequest, user: User = Depends(get_current_user),
settings: Settings = Depends(get_settings),
service_request: ServiceRequest, user: Annotated[SessionUser, Depends(get_current_user)],
settings: Annotated[Settings, Depends(get_settings)]
) -> Dict[str, Any]:
"""Submit a request for a service."""
if user.access_token.sub != service_request.user_id:
Expand Down Expand Up @@ -184,7 +185,7 @@ async def request_resource(
service_id: str,
resource_id: str,
resource_request: ResourceRequest,
user: User = Depends(get_current_user),
user: Annotated[SessionUser, Depends(get_current_user)],
settings: Settings = Depends(get_settings),
) -> Dict[str, Any]:
"""Submit a request for a resource within a service."""
Expand Down
4 changes: 2 additions & 2 deletions schemas/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .group import Group
from .service import Resource, Service
from schemas.group import Group
from schemas.service import Resource, Service

__all__ = ["Service", "Resource", "Group"]
Loading