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

Kiss off users #434

Open
c0ntradicti0n opened this issue Jan 28, 2025 · 2 comments
Open

Kiss off users #434

c0ntradicti0n opened this issue Jan 28, 2025 · 2 comments
Labels
enhancement New feature or request

Comments

@c0ntradicti0n
Copy link

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 c0ntradicti0n added the enhancement New feature or request label Jan 28, 2025
@manics
Copy link

manics commented Jan 28, 2025

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.

@c0ntradicti0n
Copy link
Author

c0ntradicti0n commented Jan 29, 2025

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants