Browse Source

Fix: Add realm to Basic Auth WWW-Authenticate header (RFC 7617 compliance)

pull/14107/head
jsibitoye 10 months ago
parent
commit
04c09e5220
  1. 8
      fastapi/security/http.py
  2. 29
      tests/test_httpbasic_realm.py
  3. 4
      tests/test_security_http_basic_optional.py
  4. 6
      tests/test_tutorial/test_security/test_tutorial006.py

8
fastapi/security/http.py

@ -189,10 +189,10 @@ class HTTPBasic(HTTPBase):
) -> Optional[HTTPBasicCredentials]:
authorization = request.headers.get("Authorization")
scheme, param = get_authorization_scheme_param(authorization)
if self.realm:
unauthorized_headers = {"WWW-Authenticate": f'Basic realm="{self.realm}"'}
else:
unauthorized_headers = {"WWW-Authenticate": "Basic"}
# Always include a realm as required by RFC 7617.
realm_value = self.realm or "fastapi"
unauthorized_headers = {"WWW-Authenticate": f'Basic realm="{realm_value}"'}
if not authorization or scheme.lower() != "basic":
if self.auto_error:
raise HTTPException(

29
tests/test_httpbasic_realm.py

@ -0,0 +1,29 @@
from fastapi import Depends, FastAPI
from fastapi.security import HTTPBasic
from fastapi.testclient import TestClient
def test_default_realm_is_included():
app = FastAPI()
security = HTTPBasic()
@app.get("/protected")
def protected(_: str = Depends(security)):
return {"ok": True}
client = TestClient(app)
response = client.get("/protected")
assert response.status_code == 401
assert response.headers["www-authenticate"] == 'Basic realm="fastapi"'
def test_custom_realm_is_respected():
app = FastAPI()
security = HTTPBasic(realm="custom")
@app.get("/protected")
def protected(_: str = Depends(security)):
return {"ok": True}
client = TestClient(app)
response = client.get("/protected")
assert response.status_code == 401
assert response.headers["www-authenticate"] == 'Basic realm="custom"'

4
tests/test_security_http_basic_optional.py

@ -37,7 +37,7 @@ def test_security_http_basic_invalid_credentials():
"/users/me", headers={"Authorization": "Basic notabase64token"}
)
assert response.status_code == 401, response.text
assert response.headers["WWW-Authenticate"] == "Basic"
assert response.headers["WWW-Authenticate"] == 'Basic realm="fastapi"'
assert response.json() == {"detail": "Invalid authentication credentials"}
@ -46,7 +46,7 @@ def test_security_http_basic_non_basic_credentials():
auth_header = f"Basic {payload}"
response = client.get("/users/me", headers={"Authorization": auth_header})
assert response.status_code == 401, response.text
assert response.headers["WWW-Authenticate"] == "Basic"
assert response.headers["WWW-Authenticate"] == 'Basic realm="fastapi"'
assert response.json() == {"detail": "Invalid authentication credentials"}

6
tests/test_tutorial/test_security/test_tutorial006.py

@ -32,7 +32,7 @@ def test_security_http_basic_no_credentials(client: TestClient):
response = client.get("/users/me")
assert response.json() == {"detail": "Not authenticated"}
assert response.status_code == 401, response.text
assert response.headers["WWW-Authenticate"] == "Basic"
assert response.headers["WWW-Authenticate"] == 'Basic realm="fastapi"'
def test_security_http_basic_invalid_credentials(client: TestClient):
@ -40,7 +40,7 @@ def test_security_http_basic_invalid_credentials(client: TestClient):
"/users/me", headers={"Authorization": "Basic notabase64token"}
)
assert response.status_code == 401, response.text
assert response.headers["WWW-Authenticate"] == "Basic"
assert response.headers["WWW-Authenticate"] == 'Basic realm="fastapi"'
assert response.json() == {"detail": "Invalid authentication credentials"}
@ -49,7 +49,7 @@ def test_security_http_basic_non_basic_credentials(client: TestClient):
auth_header = f"Basic {payload}"
response = client.get("/users/me", headers={"Authorization": auth_header})
assert response.status_code == 401, response.text
assert response.headers["WWW-Authenticate"] == "Basic"
assert response.headers["WWW-Authenticate"] == 'Basic realm="fastapi"'
assert response.json() == {"detail": "Invalid authentication credentials"}

Loading…
Cancel
Save