From d6807e3f017ae83c025846691cfd09be3161b2df Mon Sep 17 00:00:00 2001 From: rasmus Date: Fri, 8 Aug 2025 01:05:29 +0300 Subject: [PATCH] move /cards from inventory-app --- app/doorboy-proxy.py | 49 ++++++++++++++++++++++---------------------- app/users.py | 22 ++++++++++++++++++++ docker-compose.yml | 2 -- requirements.txt | 1 + 4 files changed, 47 insertions(+), 27 deletions(-) create mode 100644 app/users.py diff --git a/app/doorboy-proxy.py b/app/doorboy-proxy.py index 1b01a02..5a77a64 100755 --- a/app/doorboy-proxy.py +++ b/app/doorboy-proxy.py @@ -1,8 +1,7 @@ #!/usr/bin/env python3 from datetime import date, datetime -from sanic import Sanic -from sanic.response import text, json -from sanic_prometheus import monitor +from typing import List + from dateutil.parser import parse import httpx from functools import wraps @@ -10,6 +9,7 @@ from motor.motor_asyncio import AsyncIOMotorClient from pymongo.errors import PyMongoError import os from .slack import add_slack_routes +from .users import users_with_group app = Sanic(__name__) add_slack_routes(app) @@ -21,7 +21,6 @@ FLOOR_ACCESS_GROUP = os.environ["FLOOR_ACCESS_GROUP"] WORKSHOP_ACCESS_GROUP = os.environ["WORKSHOP_ACCESS_GROUP"] MONGO_URI = os.environ["MONGO_URI"] INVENTORY_API_KEY = os.environ["INVENTORY_API_KEY"] # asshole forwards to inventory-app, instead of using mongo directly -CARD_URI = os.environ["CARD_URI"] assert len(DOORBOY_SECRET_FLOOR) >= 10 assert len(DOORBOY_SECRET_WORKSHOP) >= 10 @@ -48,29 +47,29 @@ def authenticate_door(wrapped): @app.route("/allowed") @authenticate_door async def view_doorboy_uids(request): + users = List[str] + # authorize key = request.headers.get("KEY") - groups = [] if key == DOORBOY_SECRET_FLOOR: - groups.append(FLOOR_ACCESS_GROUP) - if key == DOORBOY_SECRET_WORKSHOP: - groups.append(WORKSHOP_ACCESS_GROUP) - if not groups: - return "fail", 500 - async with httpx.AsyncClient() as client: - r = await client.post(CARD_URI, json={ - "groups": groups - }, headers={ - "Content-Type": "application/json", - "Authorization": f"Basic {INVENTORY_API_KEY}" - }) - j = r.json() - allowed_uids = [] - for obj in j: - allowed_uids.append({ - "token": obj["token"] - }) - return json({"allowed_uids": allowed_uids}) + users = users_with_group(FLOOR_ACCESS_GROUP) + elif key == DOORBOY_SECRET_WORKSHOP: + users = users_with_group(WORKSHOP_ACCESS_GROUP) + else: + print("WARN: unknown door token in /allowed") + return "unknown doorboy secret token", 403 + + flt = { + "token.uid_hash": {"$exists": True}, + "inventory.owner.username": {"$in": users} + } + prj = { + "token.uid_hash": True + } + tokens = await app.ctx.db.inventory.find(flt, prj) + + print(f"delegating {len(tokens)} doorkey tokens") + return json({"allowed_uids": tokens}) def datetime_to_json_formatting(o): if isinstance(o, (date, datetime)): @@ -153,7 +152,7 @@ async def swipe(request): if key == DOORBOY_SECRET_WORKSHOP: doors.add("workshopdoor") if data.get("door") not in doors: - print("Door", repr(data.get("door")), "not in", doors) + print("WARN: Door", repr(data.get("door")), "not in", doors) return text("Not allowed", 403) timestamp = parse(data["timestamp"]) if data.get("timestamp") else datetime.now(datetime.timezone.utc) diff --git a/app/users.py b/app/users.py new file mode 100644 index 0000000..ef93c3e --- /dev/null +++ b/app/users.py @@ -0,0 +1,22 @@ + +from typing import List +from kubernetes import client, config +import os + +OIDC_USERS_NAMESPACE = os.getenv("OIDC_USERS_NAMESPACE") + +def users_with_group(group: str) -> List[str]: + config.load_incluster_config() + api_instance = client.CustomObjectsApi() + + users = List[str] + + ret = api_instance.list_namespaced_custom_object("codemowers.cloud", "v1beta1", OIDC_USERS_NAMESPACE, "oidcusers") + for item in ret["items"]: + if group not in item.get("status", {}).get("groups", []): + continue + + users.append(item['metadata']['name']) + + print(f"INFO: {len(users)} users in group {group}") + return users diff --git a/docker-compose.yml b/docker-compose.yml index 9efa962..753affc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -24,12 +24,10 @@ services: doorboy_proxy: network_mode: host environment: - INVENTORY_API_KEY: "sptWL6XFxl4b8" DOORBOY_SECRET_FLOOR: "0123456789" DOORBOY_SECRET_WORKSHOP: "9999999999" FLOOR_ACCESS_GROUP: "k-space:floor" WORKSHOP_ACCESS_GROUP: "k-space:workshop" - CARD_URI: "https://inventory-app-72zn4.codemowers.ee/cards" SLACK_DOORLOG_CALLBACK: DEV env_file: .env build: diff --git a/requirements.txt b/requirements.txt index 88b4c3b..1b86442 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,4 @@ python_dateutil==2.9.0 Requests==2.32.4 sanic==25.3.0 sanic_prometheus==0.2.1 +kubernetes