feat: service key dependency generic

Dependency to verify service API key accepts the service_name from a RN generic, allowing for endpoints without a full RN to use it.
This commit is contained in:
Chris Milne 2026-06-16 16:09:17 +01:00
parent f96cb2112c
commit 154870acb1
3 changed files with 43 additions and 15 deletions

View file

@ -7,21 +7,19 @@ Exports:
from typing import Annotated from typing import Annotated
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from fastapi import Request, Depends
from src.service.models import Service
from src.database import db_dependency from src.database import db_dependency
from src.exceptions import UnauthorizedException from src.exceptions import UnauthorizedException
from src.utils import send_email, generate_jwt from src.utils import send_email, generate_jwt
from src.iam.schemas import IAMCAoRRequest
from src.iam.models import Group from src.iam.models import Group
from src.service.models import Service
from fastapi import Request, Depends from src.service.schemas import HasServiceName
def valid_service_key( def valid_service_key(
db: db_dependency, request: Request, request_model: IAMCAoRRequest db: db_dependency, request: Request, request_model: HasServiceName
) -> bool: ) -> bool:
rn = request_model.rn rn = request_model.rn
api_key = request.headers.get("X-API-Key", None) api_key = request.headers.get("X-API-Key", None)

View file

@ -14,13 +14,6 @@ class CustomBaseModel(BaseModel):
pass pass
class ResourceName(CustomBaseModel):
service: str
organisation: str
resource: str
instance: Optional[str] = None
### Mixins ### ### Mixins ###
class OrgIDMixin(CustomBaseModel): class OrgIDMixin(CustomBaseModel):
organisation_id: int = Field(gt=0) organisation_id: int = Field(gt=0)
@ -42,6 +35,10 @@ class UserIDMixin(CustomBaseModel):
user_id: int = Field(gt=0) user_id: int = Field(gt=0)
class ServiceNameMixin(CustomBaseModel):
service: str
class OrgSummary(CustomBaseModel): class OrgSummary(CustomBaseModel):
id: int id: int
name: str name: str
@ -60,3 +57,9 @@ class UserSummary(CustomBaseModel):
class ServiceSummary(CustomBaseModel): class ServiceSummary(CustomBaseModel):
id: int id: int
name: str name: str
class ResourceName(ServiceNameMixin):
organisation: str
resource: str
instance: Optional[str] = None

View file

@ -6,9 +6,36 @@ Models follow the nomenclature of:
- Models: "<Module><Method><Resource><Opt:Resource><Direction>" ie "ServiceGetServiceResponse" - Models: "<Module><Method><Resource><Opt:Resource><Direction>" ie "ServiceGetServiceResponse"
""" """
from pydantic import Field from typing import Generic, TypeVar
from pydantic import Field, ConfigDict
from src.schemas import CustomBaseModel, ServiceIDMixin, ServiceSummary from src.schemas import (
CustomBaseModel,
ServiceIDMixin,
ServiceSummary,
ServiceNameMixin,
)
T = TypeVar("T", bound=ServiceNameMixin)
class HasServiceName(CustomBaseModel, Generic[T]):
rn: T
class PermissionResponseSchema(CustomBaseModel):
model_config = ConfigDict(from_attributes=True, extra="ignore")
id: int
service_name: str
resource: str
action: str
class PermissionRequestSchema(CustomBaseModel):
resource: str
action: str
class ServiceWithKeySchema(ServiceSummary): class ServiceWithKeySchema(ServiceSummary):