jupyter-collaboration icon indicating copy to clipboard operation
jupyter-collaboration copied to clipboard

Kiss off users

Open c0ntradicti0n opened this issue 10 months ago • 2 comments

Problem

I tried to add a kind of revocation of user acces via calling the hub-endpoint:

PATCH http://{{hub-host}}/hub/api/shares/{{username}}/
Content-Type: application/json

{
  "user": "{{other_user}}"
}

(authenticates with the hub-login-cookie)

The basic problem is, that the ydoc connection is never cancelled to that user. Until the jupyterhub-{{lab-server-name}} cookie expires (or the hub-login?), that connection also can even still be reestablished, even on page reload. On page reload, it anyhow needs some time, until the the hub-login has to be refreshed, then one cannot acces the shared server anymore. That is nice.

I wonder, why the lab itself should not handle revoke connections too, maybe by slow polling existing shares in some interval, if the user still has access. And because there is no such mechanism, the ydoc connection will allow loading and editing any document, as long as it stays open. So once a server is shared and one gets access, the sharing person cannot really revoke access anymore.

Proposed Solution

  • Every 5 seconds, the Lab should query the Hub to verify if the users in the YDoc room are still authorized.

  • If the doc-server maintains a more robust awareness of active users and their permissions, the collaborators menu and access controls can become more reliable and responsive.

Additional context

Environment Setup:

  • JupyterHub Version: 5.2.1 (OAuth-connected)
  • JupyterLab Version: jupyterlab-4.4.0a2
  • Jupyter Collaboration Extension: 3.1.0 (also with latest main branch)

Image

c0ntradicti0n avatar Jan 28 '25 11:01 c0ntradicti0n

I think this is one example of the more general issue of connections remaining active after logout. For example, even without RTC if you have an active JupyterLab notebook or terminal they'll remain active if you keep your JupyterLab browser tab open but logout of JupyterHub using a different tab.

manics avatar Jan 28 '25 13:01 manics

The problem with the not happening logout I "solved" via:

document.addEventListener('visibilitychange', () => {
    const response = await fetch("${hubHost}${hubPrefix}api/user", {
        headers: {
            Authorization: 'token ' + PageConfig.getOption('token')
        }
    });
    if (!response.ok && (response.status === 401 || response.status === 403)) {
        PageConfig.setOption('token', '');
        window.location.href = '...';
    }
});

Not safe, but helps when logging out.

A sledgehammer cure against the problem of the issue seems to be restarting the container automatically. I patched https://github.com/jupyterhub/jupyterhub/blob/9fc16bb3f7e8631570ed1cd5df3cde35f5f852b9/jupyterhub/apihandlers/shares.py#L395 to this:

class ServerShareAPIHandler(_ShareAPIHandler):
    """Endpoint for shares of a single server

    This is where permissions are granted and revoked
    """

    ...
    @needs_scope('shares')
    async def patch(self, user_name, server_name=None):
            """PATCH revokes permissions from single shares for a given server"""

            print("PATCH revokes permissions from single shares for a given server")
       
            ...

            spawner = self._lookup_runtime_spawner(user_name, server_name)
            self.log.info(f"Revocation complete; stopping server {server_name} for {user_name}.")
            await spawner.stop(now=True)
            logging.error(f"Restarting server {server_name} for {user_name}.")
            await spawner.start()

Sharing user is prompted to restart the notebook-server and the notebook tells the kicked user:

Image

Maybe there is also the point to start: Make the hub tell the lab that permissions have changed?

c0ntradicti0n avatar Jan 29 '25 07:01 c0ntradicti0n