Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XSRF cookie path is set to '/' when using notebookapp instead of jupyter-server #3767

Closed
ykazakov opened this issue Jan 14, 2022 · 5 comments
Labels
bug not jupyterhub Bug or feature that must be addressed in another repo

Comments

@ykazakov
Copy link

ykazakov commented Jan 14, 2022

Bug description

If jupyterhub is used with classic notebooks by setting the environmental variable JUPYTERHUB_SINGLEUSER_APP as documented, then the XSRF cookie is installed in the incorrect path /, which can result in the error XSRF cookie does not match POST argument if other notebooks are used on the same server, e.g., shared notebook services:

Screenshot 2022-01-14 at 20 33 17

Expected behaviour

If the variable is not set, then the cookie is installed for the path /{base_url}/user/{username}/ for single user services and /{base_url}/services/{service} for shared services. I I think these should be the correct locations also if the variable is set.

Actual behaviour

If we have a configuration in which:

  • JUPYTERHUB_SINGLEUSER_APP is set for the single user notebooks
  • A shared notebooks is configured using this example

then by opening first the user notebook, and then opening the shared notebook, results in the above error message.

How to reproduce

  1. Create the files with the following files:
  • Dockerfile:
FROM jupyterhub/jupyterhub:2.0.2

RUN pip install jupyter jupyterlab --no-cache-dir

RUN useradd -m mal \
    && useradd -m zoe \
    && useradd -m shared

COPY jupyterhub_config.py /etc/jupyterhub/

CMD jupyterhub -f /etc/jupyterhub/jupyterhub_config.py --debug
  • jupyterhub_config.py:
c.JupyterHub.base_url = '/test/'

c.Authenticator.allowed_users = {'mal', 'zoe'}
c.Authenticator.admin_users = {'mal'}

c.JupyterHub.authenticator_class = 'dummy'
c.JupyterHub.spawner_class = 'simple'
c.Spawner.args = ["--allow-root"]

c.Spawner.environment = {
    'JUPYTERHUB_SINGLEUSER_APP': 'notebook.notebookapp.NotebookApp',
}

# shared notebook

service_name = 'shared-notebook'
group_name = 'shared'

c.JupyterHub.load_groups = {group_name: ['mal', 'zoe']}

c.JupyterHub.services = [
    {
        'name': service_name,
        'url': f'http://127.0.0.1:9999',
        'command': ['jupyterhub-singleuser', '--debug'],
        'user': 'shared',
        'cwd': '/home/shared',
    }
]

c.JupyterHub.load_roles = [
    {
        "name": "shared-notebook",
        "groups": [group_name],
        "scopes": [f"access:services!service={service_name}"],
    },
]
  1. Create and run the docker container:
docker build -t jupyterhub-xsrf .
docker run -it -p 8000:8000 jupyterhub-xsrf
  1. Open the url: http://127.0.0.1:8000/test/
  2. Enter Username: mal and press "Sign in"
  3. Wait until the single user server (classic notebook) starts
  4. Click on "Control Panel"
  5. Select "Services > shared-notebook" and press "Authorize"
  6. Wait until the jupyter lab starts
  7. Click on the "Terminal" icon to open the terminal
  8. Observe the error: XSRF cookie does not match POST argument

Your personal set up

  • OS: MacOS 12.1
  • Docker:
% docker --version    
Docker version 20.10.11, build dea9396
  • Safari 15.2

Workaround

Instead of setting the variable JUPYTERHUB_SINGLEUSER_APP, set default_url=/tree for example as follows:

c.Spawner.args = ['--SingleUserNotebookApp.default_url=/tree']

(I also tried setting c.Spawner.default_url = '/tree' but this did not work)

The cookie is then set for the correct path, but then the notebook is not seem to be aware of jupyter hub: it displays "Junypter" logo instead of "JupyterHub" in the top left and the "Control Panel" button is not visible.

@ykazakov ykazakov added the bug label Jan 14, 2022
@ykazakov ykazakov changed the title Conflicting paths for _xrsf cookie Conflicting paths for the XSRF cookie Jan 14, 2022
@ykazakov ykazakov changed the title Conflicting paths for the XSRF cookie XSRF cookie path is set to / if JUPYTERHUB_SINGLEUSER_APP is set Jan 15, 2022
@ykazakov ykazakov changed the title XSRF cookie path is set to / if JUPYTERHUB_SINGLEUSER_APP is set XSRF cookie path is set to '/' if JUPYTERHUB_SINGLEUSER_APP is set Jan 15, 2022
@minrk
Copy link
Member

minrk commented Jan 20, 2022

I think this means it's a bug in Jupyter Notebook that's fixed in Jupyter Server (this is the effect of setting JUPYTERHUB_SINGLEUSER_APP to 'notebook.notebookapp.NotebookApp' - you are changing the single-user server implementation to the older package). This appears to be the case.

If it works for you, I think sticking with the newer server combined with the older UI is indeed the better way to go.

@minrk minrk changed the title XSRF cookie path is set to '/' if JUPYTERHUB_SINGLEUSER_APP is set XSRF cookie path is set to '/' when using notebookapp instead of jupyter-server Jan 21, 2022
@minrk minrk added the not jupyterhub Bug or feature that must be addressed in another repo label Jan 21, 2022
@ykazakov
Copy link
Author

@minrk, many thanks for the explanation particularly for the link!

I am still confused about this setting for JUPYTERHUB_SINGLEUSER_APP. If I set JUPYTERHUB_SINGLEUSER_APP=notebook.notebookapp.NotebookApp but manually change /tree to /lab in the path, does the hub then switch to Jupyter Server, or there is also an "old" jupyter lab server?

Anyway, I was able to apply the same fix you linked using a custom server extension:

def load_jupyter_server_extension(nb_server_app):
    web_app = nbapp.web_app
    base_url = web_app.settings['base_url']   
    web_app.settings["xsrf_cookie_kwargs"] = {"path": base_url}

This fixes the cookie path. However, I wish the problem were fixed in the upstream. I reported it here: jupyter/notebook#6278. So this issue could probably be closed.

There are many plugins that do not yet work with jupyter lab, and we cannot completely abandon nbclassic. For example, nbgrader does not support jupyter lab.

The workaround of changing the suffix /lab to /tree has problems. For example, the relative links in notebooks (e.g., to embedded images from local folders) do not work for some reason as the path /notebooks does not appear to be redirect to /tree as it is normally happening. The keyboard shortcuts in nbgrader do not work as well. This is not really a usable solution.

@minrk
Copy link
Member

minrk commented Feb 22, 2022

Sorry, forgot I hadn't posted an answer to the last question.

If I set JUPYTERHUB_SINGLEUSER_APP=notebook.notebookapp.NotebookApp but manually change /tree to /lab in the path, does the hub then switch to Jupyter Server, or there is also an "old" jupyter lab server?

There are two server implementations (jupyter-server and notebook) and (at least) two UIs/clients (notebook/nbclassic and jupyterlab). Both clients are compatible with both servers. In the example you gave, that means you've chosen to use the notebook implementation of the server, with jupyterlab as the default UI.

If the notebooks redirects don't work as they used to, that's a bug should be reported in jupyter-server. There are efforts to catch up nbgrader to be fully compatible with the new server (see jupyter/nbgrader#1006), but it's definitely AOK to opt-in to the older server in the meantime if you are still using extensions that require it.

@yuvipanda
Copy link
Contributor

Think this can be closed, @minrk?

@minrk
Copy link
Member

minrk commented Oct 2, 2023

Yes, thanks @yuvipanda!

@minrk minrk closed this as completed Oct 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug not jupyterhub Bug or feature that must be addressed in another repo
Projects
None yet
Development

No branches or pull requests

3 participants