From c807865ecec1ff5dffa57b482e7b5ae41d1718b8 Mon Sep 17 00:00:00 2001 From: Cody Fincher Date: Sat, 14 Sep 2024 14:58:33 -0500 Subject: [PATCH 1/2] fix: `httponly` correction in CSRFMiddleware --- litestar/middleware/csrf.py | 3 +++ tests/unit/test_middleware/test_csrf_middleware.py | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/litestar/middleware/csrf.py b/litestar/middleware/csrf.py index 0fef4fbe42..767d4e78b1 100644 --- a/litestar/middleware/csrf.py +++ b/litestar/middleware/csrf.py @@ -118,6 +118,9 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: form = await request.form() existing_csrf_token = form.get("_csrf_token", None) + if not existing_csrf_token and self.config.cookie_httponly: + existing_csrf_token = csrf_cookie + connection_state = ScopeState.from_scope(scope) if request.method in self.config.safe_methods: token = connection_state.csrf_token = csrf_cookie or generate_csrf_token(secret=self.config.secret) diff --git a/tests/unit/test_middleware/test_csrf_middleware.py b/tests/unit/test_middleware/test_csrf_middleware.py index e45f724747..2d3e8831e0 100644 --- a/tests/unit/test_middleware/test_csrf_middleware.py +++ b/tests/unit/test_middleware/test_csrf_middleware.py @@ -69,6 +69,19 @@ def test_csrf_successful_flow(get_handler: HTTPRouteHandler, post_handler: HTTPR response = client.post("/", headers={"x-csrftoken": csrf_token}) assert response.status_code == HTTP_201_CREATED +def test_csrf_httponly_flow(get_handler: HTTPRouteHandler, post_handler: HTTPRouteHandler) -> None: + with create_test_client( + route_handlers=[get_handler, post_handler], csrf_config=CSRFConfig(secret="secret", cookie_httponly=True) + ) as client: + response = client.get("/") + assert response.status_code == HTTP_200_OK + + csrf_token: Optional[str] = response.cookies.get("csrftoken") + assert csrf_token is not None + assert "set-cookie" in response.headers + if csrf_token: + response = client.post("/" ) + assert response.status_code == HTTP_201_CREATED @pytest.mark.parametrize( "method", From dd1ca97542e7513adcefbcbc4d91b84d63ba6d68 Mon Sep 17 00:00:00 2001 From: Cody Fincher Date: Sat, 14 Sep 2024 15:15:15 -0500 Subject: [PATCH 2/2] fix: ruff formatting --- tests/unit/test_middleware/test_csrf_middleware.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/unit/test_middleware/test_csrf_middleware.py b/tests/unit/test_middleware/test_csrf_middleware.py index 2d3e8831e0..3b80aad8df 100644 --- a/tests/unit/test_middleware/test_csrf_middleware.py +++ b/tests/unit/test_middleware/test_csrf_middleware.py @@ -69,6 +69,7 @@ def test_csrf_successful_flow(get_handler: HTTPRouteHandler, post_handler: HTTPR response = client.post("/", headers={"x-csrftoken": csrf_token}) assert response.status_code == HTTP_201_CREATED + def test_csrf_httponly_flow(get_handler: HTTPRouteHandler, post_handler: HTTPRouteHandler) -> None: with create_test_client( route_handlers=[get_handler, post_handler], csrf_config=CSRFConfig(secret="secret", cookie_httponly=True) @@ -80,8 +81,9 @@ def test_csrf_httponly_flow(get_handler: HTTPRouteHandler, post_handler: HTTPRou assert csrf_token is not None assert "set-cookie" in response.headers if csrf_token: - response = client.post("/" ) - assert response.status_code == HTTP_201_CREATED + response = client.post("/") + assert response.status_code == HTTP_201_CREATED + @pytest.mark.parametrize( "method",