Skip to content

Commit

Permalink
fix: csrf middleware excluding router (#3698)
Browse files Browse the repository at this point in the history
---------

Co-authored-by: Janek Nouvertné <[email protected]>
  • Loading branch information
trim21 and provinzkraut authored Aug 25, 2024
1 parent 58b20bc commit eb31341
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 7 deletions.
17 changes: 10 additions & 7 deletions litestar/middleware/csrf.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@

__all__ = ("CSRFMiddleware",)


CSRF_SECRET_BYTES = 32
CSRF_SECRET_LENGTH = CSRF_SECRET_BYTES * 2

Expand Down Expand Up @@ -98,6 +97,15 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
await self.app(scope, receive, send)
return

if should_bypass_middleware(
scope=scope,
scopes=self.scopes,
exclude_opt_key=self.config.exclude_from_csrf_key,
exclude_path_pattern=self.exclude,
):
await self.app(scope, receive, send)
return

request: Request[Any, Any, Any] = scope["app"].request_class(scope=scope, receive=receive)
content_type, _ = request.content_type
csrf_cookie = request.cookies.get(self.config.cookie_name)
Expand All @@ -111,12 +119,7 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
existing_csrf_token = form.get("_csrf_token", None)

connection_state = ScopeState.from_scope(scope)
if request.method in self.config.safe_methods or should_bypass_middleware(
scope=scope,
scopes=self.scopes,
exclude_opt_key=self.config.exclude_from_csrf_key,
exclude_path_pattern=self.exclude,
):
if request.method in self.config.safe_methods:
token = connection_state.csrf_token = csrf_cookie or generate_csrf_token(secret=self.config.secret)
await self.app(scope, receive, self.create_send_wrapper(send=send, csrf_cookie=csrf_cookie, token=token))
elif (
Expand Down
25 changes: 25 additions & 0 deletions tests/unit/test_middleware/test_csrf_middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,31 @@ def post_handler2(data: dict = Body(media_type=RequestEncodingType.URL_ENCODED))
assert response.json() == data


def test_csrf_middleware_exclude_from_set_cookies() -> None:
# https://github.com/litestar-org/litestar/issues/3688
# middleware should be bypassed completely when excluded, so no cookies should be set

@get("/protected-handler")
def get_handler() -> dict:
return {}

@get("/unprotected-handler")
def get_handler2() -> dict:
return {}

with create_test_client(
route_handlers=[get_handler, get_handler2],
csrf_config=CSRFConfig(secret=str(urandom(10)), exclude=["unprotected-handler"]),
) as client:
response = client.get("/unprotected-handler")
assert response.status_code == HTTP_200_OK
assert "set-cookie" not in response.headers

response = client.get("/protected-handler")
assert response.status_code == HTTP_200_OK
assert "set-cookie" in response.headers


def test_csrf_middleware_configure_name_for_exclude_from_check_via_opts() -> None:
@post("/handler", exclude_from_csrf=True)
def post_handler(data: dict = Body(media_type=RequestEncodingType.URL_ENCODED)) -> dict:
Expand Down

0 comments on commit eb31341

Please sign in to comment.