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

Revert #1915 for security reason #1947

Merged
merged 7 commits into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions demos/demo_multiple_classes/jupyter_server_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
c = get_config()

c.ServerApp.tornado_settings = {}
c.ServerApp.tornado_settings["headers"] = {
"Content-Security-Policy": "frame-ancestors 'self'"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
c = get_config()

c.ServerApp.tornado_settings = {}
c.ServerApp.tornado_settings["headers"] = {
"Content-Security-Policy": "frame-ancestors 'self'"
}
6 changes: 6 additions & 0 deletions demos/demo_one_class_one_grader/jupyter_server_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
c = get_config()

c.ServerApp.tornado_settings = {}
c.ServerApp.tornado_settings["headers"] = {
"Content-Security-Policy": "frame-ancestors 'self'"
}
1 change: 1 addition & 0 deletions demos/utils.sh
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ setup_jupyterhub () {

# Copy config file.
cp jupyterhub_config.py "${jupyterhub_root}/jupyterhub_config.py"
cp jupyter_server_config.py /usr/local/etc/jupyter/jupyter_server_config.py
}

enable_create_assignment () {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
66 changes: 66 additions & 0 deletions nbgrader/docs/source/configuration/jupyterhub_config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,20 @@ Using nbgrader with JupyterHub
much required reading if you want to integrate the formgrader with
JupyterHub.

.. warning::

For security reasons, ``iframe`` are not allowed with JupyterHub from version 4.1. The
documentation about this security change is at
`mitigating-same-origin-deployments <https://jupyterhub.readthedocs.io/en/stable/explanation/websecurity.html#mitigating-same-origin-deployments>`_.

In the current version of nbgrader, the ``formgrader`` UI is embedded in an ``iframe``, to
be available in a new tab of Jupyterlab or Notebook. Therefore, the ``formgrader`` UI can't
be loaded when using ``jupyterhub>=4.1``, and shows a blank panel instead.

There are several ways to use the ``formgrader`` with ``jupyterhub>=4.1``, see details
at :ref:`jupyterhub-4.1`.


For instructors running a class with JupyterHub, nbgrader offers several tools
that optimize and enrich the instructors' and students' experience of sharing
the same system. By integrating with JupyterHub, nbgrader streamlines the
Expand Down Expand Up @@ -331,3 +345,55 @@ API
.. automethod:: add_student_to_course

.. automethod:: remove_student_from_course


.. _jupyterhub-4.1:

Formgrader with ``jupyterhub>=4.1``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

As explained above in the warning, ``jupyterhub>=4.1`` does not allow iframe for security
reasons, which lead to blank panel instead of the ``formgrader`` UI.

Below are different ways to use the ``formgrader`` UI with ``jupyterhub>=4.1``.

Opening the ``formgrader`` UI in a new browser tab
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Web browsers are able to open iframes in a new browser tab, which allows using the
``formgrader`` without any additional setting on the jupyterhub server.
For example with Firefox, right clicking on the iframe shows a context menu to open the
contents in a new browser tab.

.. image:: images/jupyterhub_4.1_iframe.png

Although this solution isn't the most practical, it does allow to use ```formgrader``
without having to update the configuration and without adding vulnerabilities to the application.

Enabling JupyterHub subdomains
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Enabling per-user and per-service subdomains with ``JupyterHub.enable_subdomains = True``
allows to securely use iframes with JupyterHub.
With subdomains enabled, `frame-ancestors 'self'` allows embedding the iframe only on pages
served by the user's own server.

In this case, the ``"frame-ancestor 'self'"`` can be restored in the application:

.. code:: python

c.ServerApp.tornado_settings = {}
c.ServerApp.tornado_settings["headers"] = {
"Content-Security-Policy": "frame-ancestors 'self'"
}

in e.g. ``/usr/local/etc/jupyter/jupyter_server_config.py``.

Trusting users (less secure)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If you trust users and are aware of the security vulnerability, it is also possible to
enable the iframe with the same configuration as above, without subdomains.

This is the solution used in the JupyterHub docker
`demo <https://github.com/jupyter/nbgrader/tree/main/demos>`_.
4 changes: 0 additions & 4 deletions nbgrader/server_extensions/formgrader/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,6 @@ def api(self):
api.log_level = level
return api

def initialize(self):
super().initialize()
self.set_header("Content-Security-Policy", "frame-ancestors 'self'")

def render(self, name, **ns):
template = self.settings['nbgrader_jinja2_env'].get_template(name)
return template.render(**ns)
Expand Down
Loading