Skip to content

Commit 87d4955

Browse files
Start on whitelist and add docs
1 parent 4812d41 commit 87d4955

File tree

3 files changed

+31
-6
lines changed

3 files changed

+31
-6
lines changed

docs/arbitrary-ports.rst renamed to docs/arbitrary-ports-hosts.rst

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
.. _arbitrary-ports:
22

3-
=========================
4-
Accessing Arbitrary Ports
5-
=========================
3+
==================================
4+
Accessing Arbitrary Ports or Hosts
5+
==================================
66

77
If you already have a server running on localhost listening on
88
a port, you can access it through the notebook at
@@ -15,6 +15,11 @@ URL in the request.
1515

1616
This works for all ports listening on the local machine.
1717

18+
You can also specify arbitrary hosts in order to proxy traffic from
19+
another machine on the network ``<notebook-base>/proxy/<host>:<port>``.
20+
21+
For security reasons the host must match an entry in the whitelist in your configuration.
22+
1823
With JupyterHub
1924
===============
2025

@@ -38,7 +43,7 @@ Without JupyterHub
3843
==================
3944

4045
A very similar set up works when you don't use JupyterHub. You
41-
can construct the URL with ``<notebook-url>/proxy/<port>``.
46+
can construct the URL with ``<notebook-url>/proxy/<port>``.
4247

4348
If your notebook url is ``http://localhost:8888`` and you have
4449
a process running listening on port 8080, you can access it with

docs/index.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ The primary use cases are:
2020
#. Allow access from frontend javascript (in classic notebook or
2121
JupyterLab extensions) to access web APIs of other processes
2222
running locally in a safe manner. This is used by the `JupyterLab
23-
extension <https://github.com/dask/dask-labextension>`_ for
23+
extension <https://github.com/dask/dask-labextension>`_ for
2424
`dask <https://dask.org/>`_.
2525

2626

@@ -33,7 +33,7 @@ Contents
3333
install
3434
server-process
3535
launchers
36-
arbitrary-ports
36+
arbitrary-ports-hosts
3737

3838

3939
Convenience packages for popular applications

jupyter_server_proxy/handlers.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from urllib.parse import urlunparse, urlparse
1111
import aiohttp
1212
from asyncio import Lock
13+
import re
1314

1415
from tornado import gen, web, httpclient, httputil, process, websocket, ioloop, version_info
1516

@@ -166,6 +167,11 @@ def _build_proxy_request(self, host, port, proxied_path, body):
166167
headers=headers, **self.proxy_request_options())
167168
return req
168169

170+
def _check_host_whitelist(self, host):
171+
# TODO Get whitelist from config
172+
whitelist = [r'localhost']
173+
return any([bool(re.match(pattern, host)) for pattern in whitelist])
174+
169175
@web.authenticated
170176
async def proxy(self, host, port, proxied_path):
171177
'''
@@ -175,6 +181,12 @@ async def proxy(self, host, port, proxied_path):
175181
{base_url}/{proxy_base}/{proxied_path}
176182
'''
177183

184+
if not self._check_host_whitelist(host):
185+
self.set_status(403)
186+
self.write("Host '{host}' is not whitelisted. "
187+
"See https://jupyter-server-proxy.readthedocs.io/en/latest/arbitrary-ports-hosts.html for info.".format(host=host))
188+
return
189+
178190
if 'Proxy-Connection' in self.request.headers:
179191
del self.request.headers['Proxy-Connection']
180192

@@ -226,6 +238,14 @@ async def proxy_open(self, host, port, proxied_path=''):
226238
We establish a websocket connection to the proxied backend &
227239
set up a callback to relay messages through.
228240
"""
241+
242+
if not self._check_host_whitelist(host):
243+
self.set_status(403)
244+
self.log.info("Host '{host}' is not whitelisted. "
245+
"See https://jupyter-server-proxy.readthedocs.io/en/latest/arbitrary-ports-hosts.html for info.".format(host=host))
246+
self.close()
247+
return
248+
229249
if not proxied_path.startswith('/'):
230250
proxied_path = '/' + proxied_path
231251

0 commit comments

Comments
 (0)