diff --git a/jupyter_server/auth/identity.py b/jupyter_server/auth/identity.py index 133c3706fc..1ac4724d2b 100644 --- a/jupyter_server/auth/identity.py +++ b/jupyter_server/auth/identity.py @@ -264,6 +264,9 @@ async def _get_user(self, handler: JupyterHandler) -> User | None: # Completely insecure! No authentication at all. # No need to warn here, though; validate_security will have already done that. user = self.generate_anonymous_user(handler) + # persist user on first request + # so the user data is stable for a given browser session + self.set_login_cookie(handler, user) return user diff --git a/jupyter_server/pytest_plugin.py b/jupyter_server/pytest_plugin.py index b7725e40f2..2756fac150 100644 --- a/jupyter_server/pytest_plugin.py +++ b/jupyter_server/pytest_plugin.py @@ -405,8 +405,9 @@ def client_fetch(*parts, headers=None, params=None, **kwargs): base_path_url = url_path_join(jp_base_url, path_url) params_url = urllib.parse.urlencode(params) url = base_path_url + "?" + params_url - # Add auth keys to header - headers.update(jp_auth_header) + # Add auth keys to header, if not overridden + for key, value in jp_auth_header.items(): + headers.setdefault(key, value) # Make request. return http_server_client.fetch(url, headers=headers, request_timeout=20, **kwargs) diff --git a/tests/auth/test_identity.py b/tests/auth/test_identity.py index 4fab11c049..ff4ebfc6ae 100644 --- a/tests/auth/test_identity.py +++ b/tests/auth/test_identity.py @@ -1,5 +1,7 @@ +import json import logging from contextlib import nullcontext +from unittest import mock import pytest @@ -177,3 +179,33 @@ def test_password_required(identity_provider_class, password_set, password_requi with ctx: idp.validate_security(app, ssl_options=None) + + +async def test_auth_disabled(request, jp_serverapp, jp_fetch): + idp = PasswordIdentityProvider( + parent=jp_serverapp, + hashed_password="", + token="", + ) + assert not idp.auth_enabled + + with mock.patch.dict(jp_serverapp.web_app.settings, {"identity_provider": idp}): + + resp = await jp_fetch("/api/me", headers={"Authorization": "", "Cookie": ""}) + + user_info = json.loads(resp.body.decode("utf8")) + # anonymous login sets a cookie + assert "Set-Cookie" in resp.headers + cookie = resp.headers["Set-Cookie"] + + # second request, with cookie keeps the same anonymous user + resp = await jp_fetch("/api/me", headers={"Authorization": "", "Cookie": cookie}) + + user_info_repeat = json.loads(resp.body.decode("utf8")) + assert user_info_repeat["identity"] == user_info["identity"] + + # another request, no cookie, new anonymous user + resp = await jp_fetch("/api/me", headers={"Authorization": "", "Cookie": ""}) + + user_info_2 = json.loads(resp.body.decode("utf8")) + assert user_info_2["identity"]["username"] != user_info["identity"]["username"]