import base64 import hashlib import hmac import json import pytest from app.auth import _username_from_cookie, authenticate from app.config import settings def _b64url(raw: bytes) -> str: return base64.urlsafe_b64encode(raw).decode().rstrip("=") def _make_jwt(payload: dict, secret: str | None = None) -> str: header = _b64url(json.dumps({"alg": "HS256", "typ": "JWT"}).encode()) body = _b64url(json.dumps(payload).encode()) signing = f"{header}.{body}".encode() sig = hmac.new((secret or "x").encode(), signing, hashlib.sha256).digest() return f"{header}.{body}.{_b64url(sig)}" class _Headers(dict): """Case-insensitives .get wie Starlette-Headers (nur was wir brauchen).""" def get(self, key, default=None): return super().get(key.lower(), default) def _cfg(monkeypatch, **over): monkeypatch.setattr(settings, "trusted_auth_cookie", "yunohost.portal") monkeypatch.setattr(settings, "trusted_auth_cookie_claim", "user") monkeypatch.setattr(settings, "trusted_auth_jwt_secret", over.get("secret", "")) return settings def test_username_from_unsigned_cookie(monkeypatch): _cfg(monkeypatch) jwt = _make_jwt({"user": "dieterschlueter", "host": "linix.de"}) headers = _Headers({"cookie": f"foo=bar; yunohost.portal={jwt}; baz=qux"}) assert _username_from_cookie(headers, settings) == "dieterschlueter" def test_no_cookie_returns_none(monkeypatch): _cfg(monkeypatch) assert _username_from_cookie(_Headers({"cookie": "foo=bar"}), settings) is None assert _username_from_cookie(_Headers({}), settings) is None def test_signature_checked_when_secret_set(monkeypatch): _cfg(monkeypatch, secret="geheim") good = _make_jwt({"user": "atoor"}, secret="geheim") bad = _make_jwt({"user": "atoor"}, secret="falsch") assert _username_from_cookie(_Headers({"cookie": f"yunohost.portal={good}"}), settings) == "atoor" assert _username_from_cookie(_Headers({"cookie": f"yunohost.portal={bad}"}), settings) is None def test_authenticate_via_cookie_from_trusted_proxy(monkeypatch): import app.dependencies as deps _cfg(monkeypatch) monkeypatch.setattr(settings, "trusted_auth_header", "") monkeypatch.setattr(settings, "trusted_proxy_ips", "192.168.179.10") monkeypatch.setattr(settings, "admin_users", "atoor,dieterschlueter,dschlueter") jwt = _make_jwt({"user": "dieterschlueter"}) headers = _Headers({"cookie": f"yunohost.portal={jwt}"}) user = authenticate(headers, "192.168.179.10", None) assert user is not None assert user.external_id == "dieterschlueter" and user.is_admin is True # Von fremder IP wird das Cookie ignoriert. assert authenticate(headers, "10.0.0.1", None) is None or \ authenticate(headers, "10.0.0.1", None).external_id != "dieterschlueter"