Skip to content
This repository has been archived by the owner on Aug 30, 2022. It is now read-only.

Examples of connecting to secured servers #251

Closed
nikitakit opened this issue Oct 14, 2016 · 6 comments · Fixed by #281
Closed

Examples of connecting to secured servers #251

nikitakit opened this issue Oct 14, 2016 · 6 comments · Fixed by #281

Comments

@nikitakit
Copy link

Hi, I'm working on remote kernel functionality in nteract/hydrogen, using this services package.

Lately we've had several reports of being unable to configure secure connections (see nteract/hydrogen#467 and nteract/hydrogen#473). I'm trying to address these issues, but there doesn't appear to be any documentation on how to connect jupyter-js-services to a secured server (be it a notebook server or a kernel gateway).

Could someone involved with jupyter-js-services or the Jupyter project help me out here?

Based on crawling a scattering of github issues, websites, and mailing list posts, my current understanding of the situation is:

  • Notebooks don't appear to support any auth mechanism other than cookies, meaning that programs have no chance of connecting to secure notebook servers unless they embed a web browser
  • Kernel gateways support token-based auth, but the setup required is not documented anywhere. My best attempt was setting up KG_AUTH_TOKEN and passing requestHeaders.Authorization, which allows accessing the HTTP-based API. However attempting to actually connect to a kernel over websockets does not pass the required credentials, and I haven't come across any documentation on how to get the websocket connection to proceed.
  • [WIP] Secure browser example #206 only appears to address the use case of frontends running in the browser. If you don't have a browser-based cookie system available, the method there doesn't work.

It is my belief that supporting community-made frontends is beneficial for the Jupyter community, and the kernel gateway + jupyter-js-services combination provides a good foundation for this. However, I think that being able to establish secure connections is an important part of this story. I'd appreciate if someone could help me get this feature working.

Thanks!

@blink1073
Copy link
Contributor

@parente, any thoughts on the above?

@parente
Copy link
Member

parente commented Oct 14, 2016

The demo project here: https://github.com/jupyter/kernel_gateway_demos/tree/master/node_client_example shows one pattern of securing access to kernel gateways via nginx using basic auth headers.

Kernel gateways support token-based auth, but the setup required is not documented anywhere. My best attempt was setting up KG_AUTH_TOKEN and passing requestHeaders.Authorization, which allows accessing the HTTP-based API. However attempting to actually connect to a kernel over websockets does not pass the required credentials, and I haven't come across any documentation on how to get the websocket connection to proceed.

The shared token auth supported in the kernel gateway can also be used to authenticate connections, but:

  • You need to have a websocket client library that supports sending the Authorization: token <value> header. Not all of them do because some are modeled after the websocket API in browsers (which disallows it).
  • The current implementation supports on token per server. There's no concept of managing separate tokens for multiple clients.

@nikitakit
Copy link
Author

Would there be interest in updating this package to make connecting to secure servers from nodejs a first-class usecase?

So far the suggestions above have recommended alternative ways of setting up the notebook server itself, which may not be viable if the server is administered by a 3rd party.

To get secure connections more working for hydrogen, I have released a hydrogen-auth plugin. Unfortunately, the amount of monkey-patching involved precludes this from being merged into the hydrogen package itself.

In short, the changes required have been the following:

  • Make the XMLHttpRequest and Websocket objects effectively respect cookies, and share them with each other. (As it happens, the xmlhttprequest package recommended by the node.js examples here doesn't support cookies)
  • Provide a function that allows submitting the login form programmatically, to capture the resulting cookie
  • Work around same-origin policy by spoofing the origin header. (More on this later)

I think it would be useful to bring some of this functionality into the services package itself. Specifically, what I'm imagining is:

  1. Provide a way to have the services use custom XMLHttpRequest and Websocket objects, instead of having to monkey-patch the globals. (As a bonus, you could even detect that the services package is running inside node and automatically source known-good implementations of this functionality.)
  2. Make an API function for logging in to notebook servers with a password (or maybe username/password, because I'm not sure what JupyterHub actually uses)

As for the same-origin policy bypass, the story there is that same-origin protections are designed to prevent rouge webpages from messing with your notebook server. But if you're running a nodejs package, it has (in principle) the same permissions as a browser -- same-origin policy would not be effective in preventing malicious code. Rather than having to reconfigure notebook servers and disable CORS, it makes more sense for a program like hydrogen to spoof the Host headers to achieve full functionality. If the services is able to use custom classes to make web requests (as opposed to overriding globals), it could therefore be used in this manner without compromising other web requests in the same process.

Any thoughts?

@blink1073
Copy link
Contributor

I am comfortable if you want to submit PRs for the dependency injection and the login parts, but should defer to @minrk on the CORS issue.

@minrk
Copy link
Member

minrk commented Nov 17, 2016

With jupyter/notebook#1831, notebook 4.3 will allow authenticating with the same Authorization: token <secret> header as KG, JupyterHub, etc., and require authentication (via existing cookie or new token) by default. So making it as easy as possible to set the Authorization header would be great. If you can wait for 4.3 (we are working on releasing it now), then you shouldn't have to do the cookie workarounds, and things should be simpler.

I'll have to double-check the CORS stuff. You are right that requests from nodejs shouldn't trigger CORS. One way is to spoof the headers, but if I recall, one or both of Origin/Host are not set on requests from a script. The CORS checks shouldn't apply in that case, but maybe node does something different to what I've worked with in python-requests/cURL. On the case!

@minrk minrk mentioned this issue Nov 17, 2016
@minrk
Copy link
Member

minrk commented Nov 17, 2016

#281 adds a top-level option for token most places. This gets added to the headers via ajaxSettings and websockets via url parameter.

jupyter/notebook#1903 should address the cross-origin websockets issue.

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

Successfully merging a pull request may close this issue.

4 participants