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

course_list server extension does not work on JupyterHub when formgrader service is accessed by non-admin user #1831

Open
lahwaacz opened this issue Sep 14, 2023 · 6 comments

Comments

@lahwaacz
Copy link
Contributor

Operating system

Arch Linux

nbgrader --version

nbgrader version 0.9.0

jupyterhub --version (if used with JupyterHub)

4.0.2

jupyter notebook --version

7.0.3

Expected behavior

The formgrader service should be accessible by admin and non-admin users alike.

Actual behavior

Traceback:

  File "/usr/lib/python3.11/site-packages/nbgrader/server_extensions/course_list/handlers.py", line 173, in get
    jhub_courses = yield self.check_for_jupyterhub_formgraders(config)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/tornado/gen.py", line 769, in run
    value = future.result()
            ^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/tornado/gen.py", line 782, in run
    yielded = self.gen.send(value)
              ^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/nbgrader/server_extensions/course_list/handlers.py", line 159, in check_for_jupyterhub_formgraders
    'url': self.get_base_url() + service['prefix'].rstrip('/') + "/lab",
                                 ~~~~~~~^^^^^^^^^^
KeyError: 'prefix'

service object for a non-admin user:

{'kind': 'service', 'name': 'testcourse', 'admin': False}

service object for an admin user:

{'display': True, 'info': {}, 'pid': 0, 'name': 'testcourse', 'command': [], 'roles': [], 'url': 'http://127.0.0.1:10000', 'kind': 'service', 'admin': False, 'prefix': '/jupyter/services/testcourse/'}

Steps to reproduce the behavior

I have the following jupyterhub config based on the one class, multiple graders use case:

c.JupyterHub.load_groups.update({
    "instructors": {
        "users": [
            "instructor1",
            "instructor2",
        ],
        "properties": {},
    },
    "formgrade-testcourse": {
        "users": [
            "instructor1",
            "instructor2",
            "grader-testcourse",
        ],
        "properties": {},
    },
    "nbgrader-testcourse": {
        "users": [
            "student1",
        ],
        "properties": {},
    },
})

c.JupyterHub.load_roles += [
    {
        'name': 'instructor',
        'groups': ['instructors'],
        'scopes': [
            # these are the scopes required for the admin UI
            'admin:users',
            'admin:servers',
        ],
    },
    # The class_list extension needs permission to access services
    {
        'name': 'server',
        'scopes': [
            'inherit',
        ],
    },
]

c.JupyterHub.load_roles += [
    # access to formgrader for instructors
    {
        "name": "formgrade-testcourse",
        "groups": ["formgrade-testcourse"],
        "scopes": [
            "list:services",
            "access:services!service=testcourse",
        ],
    },
    # access to course materials for students
    {
        "name": "nbgrader-testcourse",
        "groups": ["nbgrader-testcourse"],
        "scopes": [
            # access to the services API to discover the service(s)
            "list:services",
            "read:services!service=testcourse",
        ],
    },
]


# Start the notebook server as a service. The port can be whatever you want
# and the group has to match the name of the group defined above. The name
# of the service MUST match the name of your course.
c.JupyterHub.services.append({
    "name": "testcourse",
    "url": "http://127.0.0.1:10000",
    "api_token": "redacted",
})

The "instructor1" is an admin in JupyterHub, but "instructor2" is not. Formgrader is running as an externally-managed JupyterHub service.

@jeflem
Copy link

jeflem commented Sep 15, 2023

Hi @lahwaacz,

had the same problem some time ago. I think your formgrade-testcourse role in addition needs the read:services!service=testcourse scope to see all service properties. But not sure. I it does not work, I'll have a look at my setup where this (non-admin instructors) works.

Best regards,

Jens

@lahwaacz
Copy link
Contributor Author

Hi @jeflem, thanks for the hint! It fixed the problem, but I will leave this issue open for the developers to decide if this is worth adding to the documentation.

@brichet
Copy link
Contributor

brichet commented Sep 26, 2023

Thanks @jeflem for the answer.
Is this fix also necessary for the docker example ?

@jeflem
Copy link

jeflem commented Sep 26, 2023

I would say: yes, fix is necessary in demo_multiple_classes. But did not test this.

The formgrade-course101 role in demo_one_class_multiple_graders has the read:services... scope, but the formgrade-... roles in demo_multiple_classes do not.

@lahwaacz
Copy link
Contributor Author

@brichet Please also update the documentation on Using nbgrader with JupyterHub – it uses an obsolete format for load_groups and does not mention scopes at all.

@szazs89
Copy link

szazs89 commented Mar 9, 2024

@jeflem I confirm the need of scope read:services!service=testcourse
I had similar problem: non-admin users could not list courses. The log misses scope list:services, however, adding it was not enough.

I have updated the wiki pages on my multi-grader / multiple-class show-case with the new configuration (jupyterhub 4.0.2, nbgrader 0.9.1).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants