Fix cookie not accepted in safari
This commit is contained in:
@@ -478,6 +478,39 @@ class AuthDependencyTests(unittest.TestCase):
|
||||
self.assertEqual(raised.exception.status_code, 403)
|
||||
self.assertEqual(raised.exception.detail, "Invalid CSRF token")
|
||||
|
||||
def test_cookie_auth_accepts_matching_session_among_duplicate_cookie_values(self) -> None:
|
||||
"""Cookie auth accepts the first valid session token among duplicate cookie values."""
|
||||
|
||||
request = SimpleNamespace(
|
||||
method="GET",
|
||||
headers={"cookie": "dcm_session=stale-token; dcm_session=fresh-token"},
|
||||
)
|
||||
resolved_session = SimpleNamespace(
|
||||
id=uuid.uuid4(),
|
||||
expires_at=datetime.now(UTC),
|
||||
user=SimpleNamespace(
|
||||
id=uuid.uuid4(),
|
||||
username="admin",
|
||||
role=UserRole.ADMIN,
|
||||
),
|
||||
)
|
||||
with patch.object(
|
||||
auth_dependency_module,
|
||||
"resolve_auth_session",
|
||||
side_effect=[None, resolved_session],
|
||||
) as resolve_mock:
|
||||
context = auth_dependency_module.get_request_auth_context(
|
||||
request=request,
|
||||
credentials=None,
|
||||
csrf_header=None,
|
||||
csrf_cookie=None,
|
||||
session_cookie="stale-token",
|
||||
session=SimpleNamespace(),
|
||||
)
|
||||
self.assertEqual(context.username, "admin")
|
||||
self.assertEqual(context.role, UserRole.ADMIN)
|
||||
self.assertEqual(resolve_mock.call_count, 2)
|
||||
|
||||
|
||||
class DocumentCatalogVisibilityTests(unittest.TestCase):
|
||||
"""Verifies predefined tag and path discovery visibility by caller role."""
|
||||
@@ -842,22 +875,44 @@ class AuthLoginRouteThrottleTests(unittest.TestCase):
|
||||
|
||||
self.commit_count += 1
|
||||
|
||||
@staticmethod
|
||||
def _response_stub() -> SimpleNamespace:
|
||||
class _ResponseStub:
|
||||
"""Captures response cookie calls for direct route invocation tests."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.set_cookie_calls: list[tuple[tuple[object, ...], dict[str, object]]] = []
|
||||
self.delete_cookie_calls: list[tuple[tuple[object, ...], dict[str, object]]] = []
|
||||
|
||||
def set_cookie(self, *args: object, **kwargs: object) -> None:
|
||||
"""Records one set-cookie call."""
|
||||
|
||||
self.set_cookie_calls.append((args, kwargs))
|
||||
|
||||
def delete_cookie(self, *args: object, **kwargs: object) -> None:
|
||||
"""Records one delete-cookie call."""
|
||||
|
||||
self.delete_cookie_calls.append((args, kwargs))
|
||||
|
||||
@classmethod
|
||||
def _response_stub(cls) -> "AuthLoginRouteThrottleTests._ResponseStub":
|
||||
"""Builds a minimal response object for direct route invocation."""
|
||||
|
||||
return SimpleNamespace(
|
||||
set_cookie=lambda *_args, **_kwargs: None,
|
||||
delete_cookie=lambda *_args, **_kwargs: None,
|
||||
)
|
||||
return cls._ResponseStub()
|
||||
|
||||
@staticmethod
|
||||
def _request_stub(ip_address: str = "203.0.113.2", user_agent: str = "unit-test") -> SimpleNamespace:
|
||||
def _request_stub(
|
||||
ip_address: str = "203.0.113.2",
|
||||
user_agent: str = "unit-test",
|
||||
origin: str | None = None,
|
||||
) -> SimpleNamespace:
|
||||
"""Builds request-like object containing client host and user-agent header fields."""
|
||||
|
||||
headers = {"user-agent": user_agent}
|
||||
if origin:
|
||||
headers["origin"] = origin
|
||||
return SimpleNamespace(
|
||||
client=SimpleNamespace(host=ip_address),
|
||||
headers={"user-agent": user_agent},
|
||||
headers=headers,
|
||||
url=SimpleNamespace(hostname="api.docs.lan"),
|
||||
)
|
||||
|
||||
def test_login_rejects_when_precheck_reports_active_throttle(self) -> None:
|
||||
@@ -970,6 +1025,57 @@ class AuthLoginRouteThrottleTests(unittest.TestCase):
|
||||
self.assertEqual(raised.exception.detail, auth_routes_module.LOGIN_RATE_LIMITER_UNAVAILABLE_DETAIL)
|
||||
self.assertEqual(session.commit_count, 0)
|
||||
|
||||
def test_login_sets_host_only_and_parent_domain_cookie_variants(self) -> None:
|
||||
"""Successful login sets a host-only cookie and an optional parent-domain mirror."""
|
||||
|
||||
payload = auth_routes_module.AuthLoginRequest(username="admin", password="correct-password")
|
||||
session = self._SessionStub()
|
||||
response_stub = self._response_stub()
|
||||
fake_user = SimpleNamespace(
|
||||
id=uuid.uuid4(),
|
||||
username="admin",
|
||||
role=UserRole.ADMIN,
|
||||
)
|
||||
fake_session = SimpleNamespace(
|
||||
token="session-token",
|
||||
expires_at=datetime.now(UTC),
|
||||
)
|
||||
fake_settings = SimpleNamespace(
|
||||
auth_cookie_domain="docs.lan",
|
||||
auth_cookie_samesite="none",
|
||||
public_base_url="https://api.docs.lan",
|
||||
)
|
||||
with (
|
||||
patch.object(
|
||||
auth_routes_module,
|
||||
"check_login_throttle",
|
||||
return_value=auth_login_throttle_module.LoginThrottleStatus(
|
||||
is_throttled=False,
|
||||
retry_after_seconds=0,
|
||||
),
|
||||
),
|
||||
patch.object(auth_routes_module, "authenticate_user", return_value=fake_user),
|
||||
patch.object(auth_routes_module, "clear_login_throttle"),
|
||||
patch.object(auth_routes_module, "issue_user_session", return_value=fake_session),
|
||||
patch.object(auth_routes_module, "get_settings", return_value=fake_settings),
|
||||
patch.object(auth_routes_module.secrets, "token_urlsafe", return_value="csrf-token"),
|
||||
):
|
||||
auth_routes_module.login(
|
||||
payload=payload,
|
||||
request=self._request_stub(origin="https://docs.lan"),
|
||||
response=response_stub,
|
||||
session=session,
|
||||
)
|
||||
|
||||
session_cookie_calls = [call for call in response_stub.set_cookie_calls if call[0][0] == auth_routes_module.SESSION_COOKIE_NAME]
|
||||
csrf_cookie_calls = [call for call in response_stub.set_cookie_calls if call[0][0] == auth_routes_module.CSRF_COOKIE_NAME]
|
||||
self.assertEqual(len(session_cookie_calls), 2)
|
||||
self.assertEqual(len(csrf_cookie_calls), 2)
|
||||
self.assertFalse(any("domain" in kwargs and kwargs["domain"] is None for _args, kwargs in session_cookie_calls))
|
||||
self.assertIn("domain", session_cookie_calls[1][1])
|
||||
self.assertEqual(session_cookie_calls[1][1]["domain"], "docs.lan")
|
||||
self.assertEqual(session_cookie_calls[0][1]["samesite"], "lax")
|
||||
|
||||
|
||||
class ProviderBaseUrlValidationTests(unittest.TestCase):
|
||||
"""Verifies allowlist, scheme, and private-network SSRF protections."""
|
||||
|
||||
Reference in New Issue
Block a user