my_voice_assistant_v3/tests/test_cookie_auth.py

72 lines
2.8 KiB
Python
Raw Normal View History

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"