diff --git a/stock/app/auth.py b/stock/app/auth.py new file mode 100644 index 0000000..42174d6 --- /dev/null +++ b/stock/app/auth.py @@ -0,0 +1,28 @@ +import os +import logging + +from fastapi import Header, HTTPException +from starlette.requests import Request + +logger = logging.getLogger("stock") + + +def verify_webai_key( + request: Request, + x_webai_key: str | None = Header(default=None, alias="X-WebAI-Key"), +) -> None: + """ + /api/webai/* 보호용 FastAPI dependency. + + - WEBAI_API_KEY env 미설정 → 503 (다른 endpoint 무영향) + - 헤더 누락 또는 키 불일치 → 401 + logger.warning(ip) + """ + configured = os.getenv("WEBAI_API_KEY", "").strip() + if not configured: + logger.error("WEBAI_API_KEY not configured — refusing /api/webai/* request") + raise HTTPException(status_code=503, detail="webai auth not configured") + + if not x_webai_key or x_webai_key != configured: + remote = request.client.host if request.client else "?" + logger.warning("auth_fail path=%s remote=%s", request.url.path, remote) + raise HTTPException(status_code=401, detail="invalid or missing X-WebAI-Key") diff --git a/stock/app/test_webai_auth.py b/stock/app/test_webai_auth.py new file mode 100644 index 0000000..35fa0e0 --- /dev/null +++ b/stock/app/test_webai_auth.py @@ -0,0 +1,45 @@ +import pytest +from fastapi import HTTPException +from starlette.requests import Request + + +def _make_request() -> Request: + """Minimal Request stub for verify_webai_key (only request.url.path + request.client used).""" + scope = { + "type": "http", + "path": "/api/webai/test", + "headers": [], + "client": ("1.2.3.4", 12345), + } + return Request(scope=scope) + + +def test_verify_with_valid_key_passes(monkeypatch): + monkeypatch.setenv("WEBAI_API_KEY", "secret-key-abc") + from app.auth import verify_webai_key + verify_webai_key(_make_request(), x_webai_key="secret-key-abc") + + +def test_verify_without_key_raises_401(monkeypatch): + monkeypatch.setenv("WEBAI_API_KEY", "secret-key-abc") + from app.auth import verify_webai_key + with pytest.raises(HTTPException) as exc: + verify_webai_key(_make_request(), x_webai_key=None) + assert exc.value.status_code == 401 + assert "X-WebAI-Key" in exc.value.detail + + +def test_verify_with_wrong_key_raises_401(monkeypatch): + monkeypatch.setenv("WEBAI_API_KEY", "secret-key-abc") + from app.auth import verify_webai_key + with pytest.raises(HTTPException) as exc: + verify_webai_key(_make_request(), x_webai_key="wrong-key") + assert exc.value.status_code == 401 + + +def test_verify_returns_503_when_env_missing(monkeypatch): + monkeypatch.delenv("WEBAI_API_KEY", raising=False) + from app.auth import verify_webai_key + with pytest.raises(HTTPException) as exc: + verify_webai_key(_make_request(), x_webai_key="anything") + assert exc.value.status_code == 503