Validate jwts in the scanner

This commit is contained in:
Zoe Roux 2025-05-10 17:00:00 +02:00
parent 4a796d2058
commit d4e5afd514
No known key found for this signature in database
5 changed files with 63 additions and 3 deletions

View File

@ -13,3 +13,13 @@ THEMOVIEDB_API_ACCESS_TOKEN=""
KYOO_URL="http://api:3567/api"
KYOO_APIKEY=""
JWKS_URL="http://auth:4568/.well-known/jwks.json"
JWT_ISSUER=$PUBLIC_URL
# The behavior of the below variables match what is documented here:
# https://www.postgresql.org/docs/current/libpq-envars.html
PGUSER=kyoo
PGPASSWORD=password
PGDATABASE=kyooDB
PGHOST=postgres
PGPORT=5432

View File

@ -5,3 +5,4 @@ aiohttp
watchfiles
langcodes
asyncpg
pyjwt[crypto]

View File

@ -1,12 +1,14 @@
import asyncio
import logging
from contextlib import asynccontextmanager
from typing import Annotated
import asyncpg
from fastapi import BackgroundTasks, FastAPI
from fastapi import BackgroundTasks, FastAPI, Security
from .client import KyooClient
from .fsscan import Scanner
from .jwt import validate_bearer
from .providers.composite import CompositeProvider
from .providers.themoviedatabase import TheMovieDatabase
from .requests import RequestCreator, RequestProcessor
@ -71,8 +73,13 @@ app = FastAPI(
@app.put(
"/scan",
status_code=204,
description="Trigger a full scan of the filesystem, trying to find new videos & deleting old ones.",
response_description="Scan started.",
)
async def trigger_scan(tasks: BackgroundTasks):
async def trigger_scan(
tasks: BackgroundTasks,
_: Annotated[None, Security(validate_bearer, scopes=["scanner."])],
):
"""
Trigger a full scan of the filesystem, trying to find new videos & deleting old ones.
"""
tasks.add_task(scanner.scan)

41
scanner/scanner/jwt.py Normal file
View File

@ -0,0 +1,41 @@
import os
from typing import Annotated
import jwt
from fastapi import Depends, HTTPException
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer, SecurityScopes
from jwt import PyJWKClient
jwks_client = PyJWKClient(
os.environ.get("JWKS_URL", "http://auth:4568/.well-known/jwks.json")
)
security = HTTPBearer(scheme_name="Bearer")
def validate_bearer(
token: Annotated[HTTPAuthorizationCredentials, Depends(security)],
perms: SecurityScopes,
):
try:
payload = jwt.decode(
token.credentials,
jwks_client.get_signing_key_from_jwt(token.credentials).key,
issuer=os.environ.get("JWT_ISSUER"),
)
for scope in perms.scopes:
if scope not in payload["permissions"]:
raise HTTPException(
status_code=403,
detail=f"Missing permissions {', '.join(perms.scopes)}",
headers={
"WWW-Authenticate": f'Bearer permissions="{",".join(perms.scopes)}"'
},
)
return payload
except Exception as e:
raise HTTPException(
status_code=403,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
) from e

View File

@ -8,6 +8,7 @@
watchfiles
langcodes
asyncpg
pyjwt
]);
in
pkgs.mkShell {