Skip to content

Commit e66306d

Browse files
authored
persist userid cookie when auth is disabled (#1076)
* allow override of headers in jp_fetch allows unsetting auth * persist userid cookie for disabled auth ensures stable userid for a given browser when auth is completely disabled
1 parent 908e843 commit e66306d

File tree

3 files changed

+38
-2
lines changed

3 files changed

+38
-2
lines changed

jupyter_server/auth/identity.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,9 @@ async def _get_user(self, handler: JupyterHandler) -> User | None:
264264
# Completely insecure! No authentication at all.
265265
# No need to warn here, though; validate_security will have already done that.
266266
user = self.generate_anonymous_user(handler)
267+
# persist user on first request
268+
# so the user data is stable for a given browser session
269+
self.set_login_cookie(handler, user)
267270

268271
return user
269272

jupyter_server/pytest_plugin.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -405,8 +405,9 @@ def client_fetch(*parts, headers=None, params=None, **kwargs):
405405
base_path_url = url_path_join(jp_base_url, path_url)
406406
params_url = urllib.parse.urlencode(params)
407407
url = base_path_url + "?" + params_url
408-
# Add auth keys to header
409-
headers.update(jp_auth_header)
408+
# Add auth keys to header, if not overridden
409+
for key, value in jp_auth_header.items():
410+
headers.setdefault(key, value)
410411
# Make request.
411412
return http_server_client.fetch(url, headers=headers, request_timeout=20, **kwargs)
412413

tests/auth/test_identity.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import json
12
import logging
23
from contextlib import nullcontext
4+
from unittest import mock
35

46
import pytest
57

@@ -177,3 +179,33 @@ def test_password_required(identity_provider_class, password_set, password_requi
177179

178180
with ctx:
179181
idp.validate_security(app, ssl_options=None)
182+
183+
184+
async def test_auth_disabled(request, jp_serverapp, jp_fetch):
185+
idp = PasswordIdentityProvider(
186+
parent=jp_serverapp,
187+
hashed_password="",
188+
token="",
189+
)
190+
assert not idp.auth_enabled
191+
192+
with mock.patch.dict(jp_serverapp.web_app.settings, {"identity_provider": idp}):
193+
194+
resp = await jp_fetch("/api/me", headers={"Authorization": "", "Cookie": ""})
195+
196+
user_info = json.loads(resp.body.decode("utf8"))
197+
# anonymous login sets a cookie
198+
assert "Set-Cookie" in resp.headers
199+
cookie = resp.headers["Set-Cookie"]
200+
201+
# second request, with cookie keeps the same anonymous user
202+
resp = await jp_fetch("/api/me", headers={"Authorization": "", "Cookie": cookie})
203+
204+
user_info_repeat = json.loads(resp.body.decode("utf8"))
205+
assert user_info_repeat["identity"] == user_info["identity"]
206+
207+
# another request, no cookie, new anonymous user
208+
resp = await jp_fetch("/api/me", headers={"Authorization": "", "Cookie": ""})
209+
210+
user_info_2 = json.loads(resp.body.decode("utf8"))
211+
assert user_info_2["identity"]["username"] != user_info["identity"]["username"]

0 commit comments

Comments
 (0)