From 186ab662fb0913a3bf1be33b953da3954431896a Mon Sep 17 00:00:00 2001 From: lilly Date: Thu, 28 May 2026 17:31:06 +0200 Subject: [PATCH] api: implement static dooris tokens --- api/src/dooris_api/__init__.py | 3 ++- api/src/dooris_api/deps.py | 40 +++++++++++++++++++++++++++++----- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/api/src/dooris_api/__init__.py b/api/src/dooris_api/__init__.py index 618ce97..cdf4d67 100644 --- a/api/src/dooris_api/__init__.py +++ b/api/src/dooris_api/__init__.py @@ -78,9 +78,10 @@ def main(): required=False, nargs=1, action="append", - default=[], + default=[i for i in os.environ.get("DOORIS_STATIC_API_TOKENS", "").split(",") if bool(i)], ) args = argp.parse_args() + print(args.static_api_tokens) # setup logging logging.basicConfig( diff --git a/api/src/dooris_api/deps.py b/api/src/dooris_api/deps.py index c611b5d..b82ae05 100644 --- a/api/src/dooris_api/deps.py +++ b/api/src/dooris_api/deps.py @@ -1,11 +1,12 @@ -from typing import Annotated, Optional, Tuple +from typing import Annotated, Optional import logging from datetime import datetime, UTC, timedelta -from fastapi import Request, Depends, Response +from fastapi import Request, Depends, Response, Header +from fastapi.security import APIKeyHeader from simple_openid_connect.data import TokenSuccessResponse from simple_openid_connect.client import OpenidClient -from simple_openid_connect.exceptions import ValidationError +from dooris_api import app_config from dooris_api import models, exceptions from dooris_api.ccujack import CCUJackClient @@ -13,6 +14,9 @@ from dooris_api.ccujack import CCUJackClient logger = logging.getLogger(__name__) +api_key_security_scheme = APIKeyHeader(name="Authorization", scheme_name="Static-Token", auto_error=False) + + async def get_oidc_client(req: Request) -> OpenidClient: return req.app.extra["oidc_client"] @@ -129,13 +133,39 @@ def clear_oidc_auth_state(resp: Response): resp.set_cookie("auth_start_time", "", max_age=0) +def get_logged_in_token_user(req: Request, token: Optional[str]): + if not token or not token.startswith("Static-Token "): + logger.debug("No valid API-Token was provided") + return None + + token = token.removeprefix("Static-Token ") + valid_tokens = app_config.get().static_api_tokens + + if any((i == token for i in valid_tokens)): + logger.debug("Successfully authenticated a static API-Token") + return models.ApiUser( + is_anonymous=False, + is_ccchh_user=False, + is_token_user=True, + may_operate_locks=True, + username="static-token", + guaranteed_session_until=None, + raw_id_token=None, + ) + + return None + + async def get_api_user( - req: Request, resp: Response, oidc_client: OpenidClient + req: Request, resp: Response, oidc_client: OpenidClient, token: Annotated[Optional[str], Depends(api_key_security_scheme)] = None ) -> models.ApiUser: oidc_user = await get_logged_in_oidc_user(req, resp, oidc_client) - # TODO: Implement API user based on static tokens + token_user = get_logged_in_token_user(req, token) + if oidc_user is not None: return oidc_user + elif token_user is not None: + return token_user else: return models.ApiUser( is_anonymous=True,