mariobuikhuizen / voila-embed

Embed jupyter widgets in existing websites
Other
52 stars 7 forks source link

accessing input web request session inside the notebook event handler #23

Open havok2063 opened 3 years ago

havok2063 commented 3 years ago

We're in the process of integration our web authentication for the jdaviz site with voila-embed. Basically we need to restrict access to certain data based on user's authorization. Do ipyvuetify events or voila_embed requests allow access to the web request header or session cookie? I'm thinking in the notebook event handler, we extract the user info from the session cookie and validate it against the requested input data using our auth code. If it checks out we load Jdaviz proper, otherwise we return an alert message. Or are there other ideas on folding in authentication with notebooks?

maartenbreddels commented 3 years ago

Hi Brian,

in https://github.com/voila-dashboards/voila/pull/414 we added some of the CGI and vars to the kernel, which are in https://datatracker.ietf.org/doc/html/rfc3875 . I don't see anything for cookies. I guess we should be able to pass the cookie information somehow to the kernel, but we'd have to dig into what standard we should use. The other option would be if the frontend can access the cookie (which might be less save), so we can pass the cookie information in the event handler outselves.

cheers,

Maarten

maartenbreddels commented 3 years ago

Related: https://github.com/voila-dashboards/voila/pull/835

mariobuikhuizen commented 3 years ago

You can try out the updated PR (https://github.com/voila-dashboards/voila/pull/922) with:

conda create -y -n http_voila -c conda-forge jupyterlab nodejs
conda activate http_voila
pip install pip install git+https://github.com/mariobuikhuizen/voila.git@httpforward

Create a notebook test.ipynb:

import os
import pprint
from http import cookies

cookie = cookies.SimpleCookie()
cookie.load(os.environ.get('HTTP_COOKIE', 'Cookie env var not found'))
cookie_dict = {key: morsel.value for key, morsel in cookie.items()}

pp = pprint.PrettyPrinter()
pp.pprint(cookie_dict)

Start Voila:

voila --VoilaConfiguration.http_header_envs=Cookie test.ipynb
havok2063 commented 3 years ago

@mariobuikhuizen We're finally getting around to testing the implementation of this on our end. I was able to test that this works in your example. I'm now trying to get this to work within our voila-embed infrastructure. I'm using the most recent voila-embed and voila installed from pip install git+https://github.com/voila-dashboards/voila.git@main.

My voila.json config.

MappingKernelManager
  .cull_idle_timeout = 120
  .cull_interval = 60
Voila
  .open_browser = False
  .port = 8000
  .tornado_settings = {'allow_origin': '*'}
VoilaConfiguration
  .enable_nbextensions = True
  .http_header_envs = ["['Cookie','User-Agent’]"]
  .template = 'embed'

In my notebook I have a test cell to capture the cookie output into a debug window

@out.capture()
def check_cookie():
    print('cookie', os.environ.get("HTTP_COOKIE"))
    print('user agent', os.environ.get('HTTP_USER_AGENT'))
    print('server', os.environ.get('SERVER_NAME'))

but when I load the page, I don't see any HTTP information

cookie None
user agent None
server madrox.stsci.edu

Do we need to change anything about what is sent to the notebook via the requestWidget? Or anything with the jupyter-widget-embed?

havok2063 commented 3 years ago

Ok, some progrees. I changed my voila command to voila --VoilaConfiguration.http_header_envs=Cookie --VoilaConfiguration.http_header_envs='User-Agent' , which gives me the configuration syntax

VoilaConfiguration
  .enable_nbextensions = True
  .http_header_envs = ['Cookie', 'User-Agent']
  .template = 'embed'

and now I at least get the User-Agent printed, but still no cookie.

cookie None
user agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36
server madrox.stsci.edu
mariobuikhuizen commented 3 years ago

I didn't test the cookie stuff with voila-embed :|. Looking a bit closer now, the voila server needs to be accessed from the same domain as the website, else the cookie from the website domain is not passed.

This works for me with the nginx web server:

server {
  listen 80 default_server;
  server_name website.com;

  location /voila/ {
    proxy_pass http://localhost:8000;
  }

  location /api/ {
    proxy_pass http://localhost:8000;
    proxy_http_version 1.1;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Scheme $scheme;

    proxy_buffering off;
  }

  location / {
    proxy_pass http://localhost:5000;
  }

}

And then use website.com in the embed tag: <jupyter-widget-embed ... voila-url="http://website.com" ...>

havok2063 commented 3 years ago

Hmm ok. I'm running both servers locally, accessible on the same localhost or madrox.stsci.edu domain. But I'm not running voila via nginx. I can try that.

mariobuikhuizen commented 3 years ago

It also has to be the same port.

havok2063 commented 3 years ago

hmm, then that might be the problem. The voila and web servers aren't running on the same port locally. I can try to hack something locally for testing but I'm not sure about our production environments. I'd have to talk to some other folks.

mariobuikhuizen commented 3 years ago

I finally got it working on different ports (no need for proxying with nginx anymore), you'll need the following:

havok2063 commented 3 years ago

oh cool! ok, let me try that.

havok2063 commented 3 years ago

Huzzah, that seemed to work! I think in our production environment, everything is proxied with nginx. Does this solution work under that framework as well?

mariobuikhuizen commented 3 years ago

Yeah, should work the same. Only the websocket connection to Voila needs some special settings:

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
havok2063 commented 3 years ago

Ok, I checked our production nginx config for serving Voila and we have those settings in there. So we might be ok.

havok2063 commented 3 years ago

Is the code change in voila-embed.js something that should go into a new commit, and/or PR?