From 186ab662fb0913a3bf1be33b953da3954431896a Mon Sep 17 00:00:00 2001 From: lilly Date: Thu, 28 May 2026 17:31:06 +0200 Subject: [PATCH 1/2] 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, From 99668e2a33f9188dd2284424ad1c8ee7b261e98f Mon Sep 17 00:00:00 2001 From: lilly Date: Thu, 28 May 2026 17:53:15 +0200 Subject: [PATCH 2/2] document current api parameters in README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index f83e55d..7cf569f 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,10 @@ THe following table lists all available configuration parameters: | `--base-url` | `DOORIS_BASE_URL` | Yes | *None* | | `--serve-static` | `DOORIS_SERVE_STATIC` | No | *None* | | `--ccujack-url` | `DOORIS_CCUJACK_URL` | No | `https://hmdooris-ccu.ccchh.net:2122` | +| `--ccujack-mqtt` | `DOORIS_CCUJACK_MQTT` | No | `hmdooris-ccu.ccchh.net:1883` | | `--ccujack-user` | `DOORIS_CCUJACK_USER` | Yes | *None* | | `--ccujack-password` | `DOORIS_CCUJACK_PASSWORD` | Yes | *None* | +| `--static-api-tokens` | `DOORIS_STATIC_API_TOKENS` | No | *None* | ## API Development