allow subclasses to override xsrf check

need to inject our override into the base class,
rather than at the instance level,
to avoid clobbering any overrides in extensions like jupyter-server-proxy
This commit is contained in:
Min RK
2024-03-22 23:46:49 +01:00
parent 68f359360e
commit 5831079bf6

View File

@@ -936,13 +936,39 @@ class HubOAuth(HubAuth):
def _patch_xsrf(self, handler):
"""Patch handler to inject JuptyerHub xsrf token behavior"""
handler._xsrf_token_id = self._get_xsrf_token_id(handler)
# override xsrf_token property on class,
# so it's still a getter, not invoked immediately
handler.__class__.xsrf_token = property(
partial(get_xsrf_token, cookie_path=self.base_url)
)
handler.check_xsrf_cookie = partial(self.check_xsrf_cookie, handler)
if isinstance(handler, HubAuthenticated):
# doesn't need patch
return
# patch in our xsrf token handling
# overrides tornado and jupyter_server defaults,
# but not others.
# subclasses will still inherit our overridden behavior,
# but their overrides (if any) will take precedence over ours
# such as jupyter-server-proxy
for cls in handler.__class__.__mro__:
# search for the nearest parent class defined
# in one of the 'base' Handler-defining packages.
# In current implementations, this will
# generally be jupyter_server.base.handlers.JupyterHandler
# or tornado.web.RequestHandler,
# but doing it this way ensures consistent results
if (cls.__module__ or '').partition('.')[0] not in {
"jupyter_server",
"notebook",
"tornado",
}:
continue
# override check_xsrf_cookie where it's defined
if "check_xsrf_cookie" in cls.__dict__:
if "_get_xsrf_token_id" in cls.__dict__:
# already patched
return
cls._xsrf_token_id = property(self._get_xsrf_token_id)
cls.xsrf_token = property(
partial(get_xsrf_token, cookie_path=self.base_url)
)
cls.check_xsrf_cookie = lambda handler: self.check_xsrf_cookie(handler)
def check_xsrf_cookie(self, handler):
"""check_xsrf_cookie patch
@@ -987,8 +1013,10 @@ class HubOAuth(HubAuth):
token = self._get_token_cookie(handler)
session_id = self.get_session_id(handler)
if token and self._needs_check_xsrf(handler):
# call handler.check_xsrf_cookie instead of self.check_xsrf_cookie
# to allow subclass overrides
try:
self.check_xsrf_cookie(handler)
handler.check_xsrf_cookie()
except HTTPError as e:
self.log.error(
f"Not accepting cookie auth on {handler.request.method} {handler.request.path}: {e}"