Skip to content

Commit 13fc1ba

Browse files
authored
Fix #857: Support Basic Auth for the JBI Api Key (#860)
1 parent 1dc17a2 commit 13fc1ba

File tree

3 files changed

+37
-11
lines changed

3 files changed

+37
-11
lines changed

jbi/router.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from fastapi import APIRouter, Body, Depends, HTTPException, Request, Response, status
99
from fastapi.encoders import jsonable_encoder
1010
from fastapi.responses import HTMLResponse
11-
from fastapi.security import APIKeyHeader
11+
from fastapi.security import APIKeyHeader, HTTPBasic, HTTPBasicCredentials
1212
from fastapi.templating import Jinja2Templates
1313

1414
from jbi import bugzilla, jira
@@ -75,15 +75,22 @@ def version(version_json: VersionDep):
7575
return version_json
7676

7777

78-
header_scheme = APIKeyHeader(name="X-Api-Key")
78+
header_scheme = APIKeyHeader(name="X-Api-Key", auto_error=False)
79+
basicauth_scheme = HTTPBasic(auto_error=False)
7980

8081

8182
def api_key_auth(
82-
settings: SettingsDep, api_key: Annotated[str, Depends(header_scheme)]
83+
settings: SettingsDep,
84+
api_key: Annotated[str, Depends(header_scheme)],
85+
basic_auth: Annotated[HTTPBasicCredentials, Depends(basicauth_scheme)],
8386
):
84-
if not secrets.compare_digest(api_key, settings.jbi_api_key):
87+
if not api_key and basic_auth:
88+
api_key = basic_auth.password
89+
if not api_key or not secrets.compare_digest(api_key, settings.jbi_api_key):
8590
raise HTTPException(
86-
status_code=status.HTTP_401_UNAUTHORIZED, detail="Forbidden"
91+
status_code=status.HTTP_401_UNAUTHORIZED,
92+
detail="Incorrect API Key",
93+
headers={"WWW-Authenticate": "Basic"},
8794
)
8895

8996

tests/conftest.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,15 @@ def anon_client():
7979

8080

8181
@pytest.fixture
82-
def authenticated_client():
83-
"""An test client with a valid API key."""
82+
def test_api_key():
8483
# api key for tests defined in .env.example
85-
return TestClient(app, headers={"X-Api-Key": "fake_api_key"})
84+
return "fake_api_key"
85+
86+
87+
@pytest.fixture
88+
def authenticated_client(test_api_key):
89+
"""An test client with a valid API key."""
90+
return TestClient(app, headers={"X-Api-Key": test_api_key})
8691

8792

8893
@pytest.fixture

tests/unit/test_router.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import base64
12
import json
23
import os
34
from datetime import datetime
@@ -26,10 +27,23 @@ def test_read_root(anon_client):
2627
],
2728
)
2829
def test_get_protected_endpoints(
29-
endpoint, webhook_request_factory, mocked_bugzilla, anon_client
30+
endpoint, webhook_request_factory, mocked_bugzilla, anon_client, test_api_key
3031
):
3132
resp = anon_client.get(endpoint)
32-
assert resp.status_code == 403
33+
assert resp.status_code == 401
34+
35+
# Supports authentication via `X-Api-Key` header
36+
resp = anon_client.get(endpoint, headers={"X-Api-Key": test_api_key})
37+
assert resp.status_code == 200
38+
39+
# Supports authentication via Basic Auth header
40+
username_password = ":" + test_api_key
41+
credentials_b64 = base64.b64encode(username_password.encode("utf8")).decode("utf8")
42+
resp = anon_client.get(
43+
endpoint,
44+
headers={"Authorization": f"Basic {credentials_b64}"},
45+
)
46+
assert resp.status_code == 200
3347

3448

3549
def test_whiteboard_tags(authenticated_client):
@@ -148,7 +162,7 @@ def test_webhook_is_401_if_unathenticated(
148162
"/bugzilla_webhook",
149163
data={},
150164
)
151-
assert response.status_code == 403
165+
assert response.status_code == 401
152166

153167

154168
def test_webhook_is_401_if_wrong_key(

0 commit comments

Comments
 (0)