async def test_user_code_execute():
    """
    User logs in, starts a server & executes code
    """
    # This *must* be localhost, not an IP
    # aiohttp throws away cookies if we are connecting to an IP!
    hub_url = "http://localhost"
    username = secrets.token_hex(8)

    assert (
        0
        == await (
            await asyncio.create_subprocess_exec(
                *TLJH_CONFIG_PATH, "set", "auth.type", "dummy"
            )
        ).wait()
    )
    assert (
        0
        == await (
            await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, "reload")
        ).wait()
    )

    async with User(username, hub_url, partial(login_dummy, password="")) as u:
        await u.login()
        await u.ensure_server_simulate()
        await u.start_kernel()
        await u.assert_code_output("5 * 4", "20", 5, 5)

        # Assert that the user exists
        assert pwd.getpwnam(f"jupyter-{username}") is not None
async def test_user_admin_remove():
    """
    User is made an admin, logs in and we check if they are in admin group.

    Then we remove them from admin group, and check they *aren't* in admin group :D
    """
    # This *must* be localhost, not an IP
    # aiohttp throws away cookies if we are connecting to an IP!
    hub_url = 'http://localhost'
    username = secrets.token_hex(8)

    assert 0 == await (await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'set', 'auth.type', 'dummyauthenticator.DummyAuthenticator')).wait()
    assert 0 == await (await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'add-item', 'users.admin', username)).wait()
    assert 0 == await (await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'reload')).wait()

    async with User(username, hub_url, partial(login_dummy, password='')) as u:
            await u.login()
            await u.ensure_server()

            # Assert that the user exists
            assert pwd.getpwnam(f'jupyter-{username}') is not None

            # Assert that the user has admin rights
            assert f'jupyter-{username}' in grp.getgrnam('jupyterhub-admins').gr_mem

            assert 0 == await (await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'remove-item', 'users.admin', username)).wait()
            assert 0 == await (await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'reload')).wait()

            await u.stop_server()
            await u.ensure_server()

            # Assert that the user does *not* have admin rights
            assert f'jupyter-{username}' not in grp.getgrnam('jupyterhub-admins').gr_mem
Example #3
0
async def test_user_admin_add():
    """
    User is made an admin, logs in and we check if they are in admin group
    """
    # This *must* be localhost, not an IP
    # aiohttp throws away cookies if we are connecting to an IP!
    hub_url = 'http://localhost'
    username = secrets.token_hex(8)


    assert 0 == await (await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'add-item', 'users.admin', username)).wait()
    assert 0 == await (await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'reload')).wait()

    # FIXME: wait for reload to finish & hub to come up
    # Should be part of tljh-config reload
    await asyncio.sleep(1)
    async with User(username, hub_url, partial(login_dummy, password='')) as u:
            await u.login()
            await u.ensure_server()

            # Assert that the user exists
            assert pwd.getpwnam(f'jupyter-{username}') is not None

            # Assert that the user has admin rights
            assert f'jupyter-{username}' in grp.getgrnam('jupyterhub-admins').gr_mem
Example #4
0
async def test_user_code_execute():
    """
    User logs in, starts a server & executes code
    """
    # This *must* be localhost, not an IP
    # aiohttp throws away cookies if we are connecting to an IP!
    hub_url = 'http://localhost'
    username = secrets.token_hex(8)

    assert 0 == await (await asyncio.create_subprocess_exec(
        *TLJH_CONFIG_PATH, 'set', 'auth.type',
        'dummyauthenticator.DummyAuthenticator')).wait()
    assert 0 == await (await
                       asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH,
                                                      'reload')).wait()

    # FIXME: wait for reload to finish & hub to come up
    # Should be part of tljh-config reload
    await asyncio.sleep(1)

    async with User(username, hub_url, partial(login_dummy, password='')) as u:
        await u.login()
        await u.ensure_server()
        await u.start_kernel()
        await u.assert_code_output("5 * 4", "20", 5, 5)

        # Assert that the user exists
        assert pwd.getpwnam(f'jupyter-{username}') is not None
async def test_long_username():
    """
    User with a long name logs in, and we check if their name is properly truncated.
    """
    # This *must* be localhost, not an IP
    # aiohttp throws away cookies if we are connecting to an IP!
    hub_url = 'http://localhost'
    username = secrets.token_hex(32)

    assert 0 == await (await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'set', 'auth.type', 'dummyauthenticator.DummyAuthenticator')).wait()
    assert 0 == await (await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'reload')).wait()

    try:
        async with User(username, hub_url, partial(login_dummy, password='')) as u:
                await u.login()
                await u.ensure_server()

                # Assert that the user exists
                system_username = generate_system_username(f'jupyter-{username}')
                assert pwd.getpwnam(system_username) is not None

                await u.stop_server()
    except:
        # If we have any errors, print jupyterhub logs before exiting
        subprocess.check_call([
            'journalctl',
            '-u', 'jupyterhub',
            '--no-pager'
        ])
        raise
Example #6
0
async def simulate_user(hub_url, username, password, delay_seconds,
                        code_execute_seconds):
    await asyncio.sleep(delay_seconds)
    async with User(username, hub_url, partial(login_dummy,
                                               password=password)) as u:
        try:
            await u.login()
            await u.ensure_server()
            await u.start_kernel()
            await u.assert_code_output("5 * 4", "20", 5, code_execute_seconds)
        except OperationError:
            pass
        finally:
            try:
                if u.state == User.States.KERNEL_STARTED:
                    await u.stop_kernel()
            except OperationError:
                # We'll try to sto the server anyway
                pass
            try:
                if u.state == User.States.SERVER_STARTED:
                    await u.stop_server()
            except OperationError:
                # Nothing to do
                pass
Example #7
0
async def test_user_server_started_with_custom_base_url():
    """
    User logs in, starts a server with a custom base_url & executes code
    """
    # This *must* be localhost, not an IP
    # aiohttp throws away cookies if we are connecting to an IP!
    base_url = "/custom-base"
    hub_url = f"http://localhost{base_url}"
    username = secrets.token_hex(8)

    assert 0 == await (await asyncio.create_subprocess_exec(
        *TLJH_CONFIG_PATH, 'set', 'auth.type',
        'dummyauthenticator.DummyAuthenticator')).wait()
    assert 0 == await (await
                       asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'set',
                                                      'base_url',
                                                      base_url)).wait()
    assert 0 == await (await
                       asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH,
                                                      'reload')).wait()

    async with User(username, hub_url, partial(login_dummy, password='')) as u:
        await u.login()
        await u.ensure_server_simulate()

        # unset base_url to avoid problems with other tests
        assert 0 == await (await asyncio.create_subprocess_exec(
            *TLJH_CONFIG_PATH, 'unset', 'base_url')).wait()
        assert 0 == await (await asyncio.create_subprocess_exec(
            *TLJH_CONFIG_PATH, 'reload')).wait()
Example #8
0
async def test_idle_server_culled():
    """
    User logs in, starts a server & stays idle for 1 min.
    (the user's server should be culled during this period)
    """
    # This *must* be localhost, not an IP
    # aiohttp throws away cookies if we are connecting to an IP!
    hub_url = 'http://localhost'
    username = secrets.token_hex(8)

    assert 0 == await (await asyncio.create_subprocess_exec(
        *TLJH_CONFIG_PATH, 'set', 'auth.type',
        'dummyauthenticator.DummyAuthenticator')).wait()
    # Check every 10s for idle servers to cull
    assert 0 == await (await
                       asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'set',
                                                      'services.cull.every',
                                                      "10")).wait()
    # Apart from servers, also cull users
    assert 0 == await (await
                       asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'set',
                                                      'services.cull.users',
                                                      "True")).wait()
    # Cull servers and users after 60s of activity
    assert 0 == await (await
                       asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'set',
                                                      'services.cull.max_age',
                                                      "60")).wait()
    assert 0 == await (await
                       asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH,
                                                      'reload')).wait()

    async with User(username, hub_url, partial(login_dummy, password='')) as u:
        await u.login()
        # Start user's server
        await u.ensure_server()
        # Assert that the user exists
        assert pwd.getpwnam(f'jupyter-{username}') is not None

        # Check that we can get to the user's server
        r = await u.session.get(u.hub_url / 'hub/api/users' / username,
                                headers={'Referer': str(u.hub_url / 'hub/')})
        assert r.status == 200

        async def _check_culling_done():
            # Check that after 60s, the user and server have been culled and are not reacheable anymore
            r = await u.session.get(
                u.hub_url / 'hub/api/users' / username,
                headers={'Referer': str(u.hub_url / 'hub/')})
            print(r.status)
            return r.status == 403

        await exponential_backoff(
            _check_culling_done,
            "Server culling failed!",
            timeout=100,
        )
async def test_user_group_adding():
    """
    User logs in, and we check if they are added to the specified group.
    """
    # This *must* be localhost, not an IP
    # aiohttp throws away cookies if we are connecting to an IP!
    hub_url = "http://localhost"
    username = secrets.token_hex(8)
    groups = {"somegroup": [username]}
    # Create the group we want to add the user to
    system("groupadd somegroup")

    assert (
        0
        == await (
            await asyncio.create_subprocess_exec(
                *TLJH_CONFIG_PATH, "set", "auth.type", "dummy"
            )
        ).wait()
    )
    assert (
        0
        == await (
            await asyncio.create_subprocess_exec(
                *TLJH_CONFIG_PATH,
                "add-item",
                "users.extra_user_groups.somegroup",
                username,
            )
        ).wait()
    )
    assert (
        0
        == await (
            await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, "reload")
        ).wait()
    )

    try:
        async with User(username, hub_url, partial(login_dummy, password="")) as u:
            await u.login()
            await u.ensure_server_simulate()

            # Assert that the user exists
            system_username = generate_system_username(f"jupyter-{username}")
            assert pwd.getpwnam(system_username) is not None

            # Assert that the user was added to the specified group
            assert f"jupyter-{username}" in grp.getgrnam("somegroup").gr_mem

            await u.stop_server()
            # Delete the group
            system("groupdel somegroup")
    except:
        # If we have any errors, print jupyterhub logs before exiting
        subprocess.check_call(["journalctl", "-u", "jupyterhub", "--no-pager"])
        raise
async def test_unsuccessful_login(username, password):
    """
    Ensure nobody but the admin that was added during install can login
    """
    hub_url = "http://localhost"

    async with User(username, hub_url, partial(login_dummy, password="")) as u:
        user_logged_in = await u.login()

    assert user_logged_in == False
async def test_admin_login():
    """
    Test if the admin that was added during install can login with
    the password provided.
    """
    hub_url = 'http://localhost'
    username = "******"
    password = "******"

    async with User(username, hub_url, partial(login_dummy,
                                               password=password)) as u:
        await u.login()
        await u.ensure_server()
async def test_admin_login():
    """
    Test if the admin that was added during install can login with
    the password provided.
    """
    hub_url = "http://localhost"
    username = "******"
    password = "******"

    async with User(username, hub_url, partial(login_dummy, password=password)) as u:
        await u.login()
        # If user is not logged in, this will raise an exception
        await u.ensure_server_simulate()
async def test_unsuccessful_login(username, password):
    """
    Ensure nobody but the admin that was added during install can login
    """
    hub_url = 'http://localhost'

    try:
        async with User(username, hub_url, partial(login_dummy,
                                                   password="")) as u:
            await u.login()
    except Exception:
        # This is what we except to happen
        pass
    else:
        raise
Example #14
0
async def test_user_code_execute():
    """
    User logs in, starts a server & executes code
    """
    # This *must* be localhost, not an IP
    # aiohttp throws away cookies if we are connecting to an IP!
    hub_url = 'http://localhost'
    username = secrets.token_hex(8)

    async with User(username, hub_url, partial(login_dummy, password='')) as u:
            await u.login()
            await u.ensure_server()
            await u.start_kernel()
            await u.assert_code_output("5 * 4", "20", 5, 5)

            # Assert that the user exists
            assert pwd.getpwnam(f'jupyter-{username}') is not None
Example #15
0
async def check_user(hub_url, username):
    async with User(username, hub_url, no_auth) as u:
        try:
            if not await u.ensure_server_api():
                return 'start-server'
            if not await u.start_kernel():
                return 'start-kernel'
            nonce = secrets.token_hex(64)
            if not await u.assert_code_output(
                    f"!echo -n {nonce} > nonce \n!cat nonce", nonce, 2):
                return 'run-code'
        finally:
            if u.state == User.States.KERNEL_STARTED:
                if not await u.stop_kernel():
                    return 'stop-kernel'
            if u.state == User.States.SERVER_STARTED:
                if not await u.stop_server():
                    return 'stop-kernel'
            return 'completed'
Example #16
0
async def test_user_group_adding():
    """
    User logs in, and we check if they are added to the specified group.
    """
    # This *must* be localhost, not an IP
    # aiohttp throws away cookies if we are connecting to an IP!
    hub_url = 'http://localhost'
    username = secrets.token_hex(8)
    groups = {"somegroup": [username]}
    # Create the group we want to add the user to
    system('groupadd somegroup')

    assert 0 == await (await asyncio.create_subprocess_exec(
        *TLJH_CONFIG_PATH, 'set', 'auth.type',
        'dummyauthenticator.DummyAuthenticator')).wait()
    assert 0 == await (await asyncio.create_subprocess_exec(
        *TLJH_CONFIG_PATH, 'add-item', 'users.extra_user_groups.somegroup',
        username)).wait()
    assert 0 == await (await
                       asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH,
                                                      'reload')).wait()

    try:
        async with User(username, hub_url, partial(login_dummy,
                                                   password='')) as u:
            await u.login()
            await u.ensure_server()

            # Assert that the user exists
            system_username = generate_system_username(f'jupyter-{username}')
            assert pwd.getpwnam(system_username) is not None

            # Assert that the user was added to the specified group
            assert f'jupyter-{username}' in grp.getgrnam('somegroup').gr_mem

            await u.stop_server()
            # Delete the group
            system('groupdel somegroup')
    except:
        # If we have any errors, print jupyterhub logs before exiting
        subprocess.check_call(['journalctl', '-u', 'jupyterhub', '--no-pager'])
        raise
Example #17
0
async def simulate_user(hub_url, username, password, delay_seconds,
                        code_execute_seconds):
    await asyncio.sleep(delay_seconds)
    async with User(username, hub_url, partial(login_dummy,
                                               password=password)) as u:
        try:
            if not await u.login():
                return 'login'
            if not await u.ensure_server_simulate():
                return 'start-server'
            if not await u.start_kernel():
                return 'start-kernel'
            if not await u.assert_code_output("5 * 4", "20", 5,
                                              code_execute_seconds):
                return 'run-code'
            return 'completed'
        finally:
            if u.state == User.States.KERNEL_STARTED:
                await u.stop_kernel()
                await u.stop_server()
async def test_user_admin_add():
    """
    User is made an admin, logs in and we check if they are in admin group
    """
    # This *must* be localhost, not an IP
    # aiohttp throws away cookies if we are connecting to an IP!
    hub_url = "http://localhost"
    username = secrets.token_hex(8)

    assert (
        0
        == await (
            await asyncio.create_subprocess_exec(
                *TLJH_CONFIG_PATH, "set", "auth.type", "dummy"
            )
        ).wait()
    )
    assert (
        0
        == await (
            await asyncio.create_subprocess_exec(
                *TLJH_CONFIG_PATH, "add-item", "users.admin", username
            )
        ).wait()
    )
    assert (
        0
        == await (
            await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, "reload")
        ).wait()
    )

    async with User(username, hub_url, partial(login_dummy, password="")) as u:
        await u.login()
        await u.ensure_server_simulate()

        # Assert that the user exists
        assert pwd.getpwnam(f"jupyter-{username}") is not None

        # Assert that the user has admin rights
        assert f"jupyter-{username}" in grp.getgrnam("jupyterhub-admins").gr_mem
async def test_long_username():
    """
    User with a long name logs in, and we check if their name is properly truncated.
    """
    # This *must* be localhost, not an IP
    # aiohttp throws away cookies if we are connecting to an IP!
    hub_url = "http://localhost"
    username = secrets.token_hex(32)

    assert (
        0
        == await (
            await asyncio.create_subprocess_exec(
                *TLJH_CONFIG_PATH, "set", "auth.type", "dummy"
            )
        ).wait()
    )
    assert (
        0
        == await (
            await asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, "reload")
        ).wait()
    )

    try:
        async with User(username, hub_url, partial(login_dummy, password="")) as u:
            await u.login()
            await u.ensure_server_simulate()

            # Assert that the user exists
            system_username = generate_system_username(f"jupyter-{username}")
            assert pwd.getpwnam(system_username) is not None

            await u.stop_server()
    except:
        # If we have any errors, print jupyterhub logs before exiting
        subprocess.check_call(["journalctl", "-u", "jupyterhub", "--no-pager"])
        raise
Example #20
0
async def simulate_user(hub_url,
                        username,
                        password,
                        delay_seconds,
                        code_execute_seconds,
                        debug=False,
                        config=None):
    await asyncio.sleep(delay_seconds)
    async with User(username,
                    hub_url,
                    partial(login_dummy, password=password),
                    debug=debug,
                    config=config) as u:
        code_and_output = load_code_and_output(config)
        try:
            await u.login()
            await u.ensure_server()
            await u.start_kernel()
            for code_pair in code_and_output:
                await u.assert_code_output(code_pair['code'],
                                           code_pair['output'], 5,
                                           code_execute_seconds)
        except OperationError:
            pass
        finally:
            try:
                if u.state == User.States.KERNEL_STARTED:
                    await u.stop_kernel()
            except OperationError:
                # We'll try to sto the server anyway
                pass
            try:
                if u.state == User.States.SERVER_STARTED:
                    await u.stop_server()
            except OperationError:
                # Nothing to do
                pass
Example #21
0
async def test_active_server_not_culled():
    """
    User logs in, starts a server & stays idle for 30s
    (the user's server should not be culled during this period).
    """
    # This *must* be localhost, not an IP
    # aiohttp throws away cookies if we are connecting to an IP!
    hub_url = 'http://localhost'
    username = secrets.token_hex(8)

    assert 0 == await (await asyncio.create_subprocess_exec(
        *TLJH_CONFIG_PATH, 'set', 'auth.type',
        'dummyauthenticator.DummyAuthenticator')).wait()
    # Check every 10s for idle servers to cull
    assert 0 == await (await
                       asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'set',
                                                      'services.cull.every',
                                                      "10")).wait()
    # Apart from servers, also cull users
    assert 0 == await (await
                       asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'set',
                                                      'services.cull.users',
                                                      "True")).wait()
    # Cull servers and users after 60s of activity
    assert 0 == await (await
                       asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH, 'set',
                                                      'services.cull.max_age',
                                                      "60")).wait()
    assert 0 == await (await
                       asyncio.create_subprocess_exec(*TLJH_CONFIG_PATH,
                                                      'reload')).wait()

    async with User(username, hub_url, partial(login_dummy, password='')) as u:
        await u.login()
        # Start user's server
        await u.ensure_server_simulate()
        # Assert that the user exists
        assert pwd.getpwnam(f'jupyter-{username}') is not None

        # Check that we can get to the user's server
        r = await u.session.get(u.hub_url / 'hub/api/users' / username,
                                headers={'Referer': str(u.hub_url / 'hub/')})
        assert r.status == 200

        async def _check_culling_done():
            # Check that after 30s, we can still reach the user's server
            r = await u.session.get(
                u.hub_url / 'hub/api/users' / username,
                headers={'Referer': str(u.hub_url / 'hub/')})
            print(r.status)
            return r.status != 200

        try:
            await exponential_backoff(
                _check_culling_done,
                "User's server is still reacheable!",
                timeout=30,
            )
        except TimeoutError:
            # During the 30s timeout the user's server wasn't culled, which is what we intended.
            pass