Skip to content

Commit 979e0bd

Browse files
committed
even more careful with login redirect checks
handle empty netloc being interpreted as first path part being the netloc by unhelpful browsers
1 parent 16cf97c commit 979e0bd

File tree

2 files changed

+16
-7
lines changed

2 files changed

+16
-7
lines changed

notebook/auth/login.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
import os
88

99
try:
10-
from urllib.parse import urlparse # Py 3
10+
from urllib.parse import urlparse, urlunparse # Py 3
1111
except ImportError:
12-
from urlparse import urlparse # Py 2
12+
from urlparse import urlparse, urlunparse # Py 2
1313
import uuid
1414

1515
from tornado.escape import url_escape
@@ -44,15 +44,18 @@ def _redirect_safe(self, url, default=None):
4444
# instead of %5C, causing `\\` to behave as `//`
4545
url = url.replace("\\", "%5C")
4646
parsed = urlparse(url)
47-
if parsed.netloc or not (parsed.path + '/').startswith(self.base_url):
47+
path_only = urlunparse(parsed._replace(netloc='', scheme=''))
48+
if url != path_only or not (parsed.path + '/').startswith(self.base_url):
4849
# require that next_url be absolute path within our path
4950
allow = False
5051
# OR pass our cross-origin check
51-
if parsed.netloc:
52+
if url != path_only:
5253
# if full URL, run our cross-origin check:
5354
origin = '%s://%s' % (parsed.scheme, parsed.netloc)
5455
origin = origin.lower()
55-
if self.allow_origin:
56+
if origin == '%s://%s' % (self.request.protocol, self.request.host):
57+
allow = True
58+
elif self.allow_origin:
5659
allow = self.allow_origin == origin
5760
elif self.allow_origin_pat:
5861
allow = bool(self.allow_origin_pat.match(origin))

notebook/auth/tests/test_login.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ def test_next_bad(self):
3131
"//host" + self.url_prefix + "tree",
3232
"https://google.com",
3333
"/absolute/not/base_url",
34+
"///jupyter.org",
35+
"/\\some-host",
3436
):
3537
url = self.login(next=bad_next)
3638
self.assertEqual(url, self.url_prefix)
@@ -39,10 +41,14 @@ def test_next_bad(self):
3941
def test_next_ok(self):
4042
for next_path in (
4143
"tree/",
42-
"//" + self.url_prefix + "tree",
44+
self.base_url() + "has/host",
4345
"notebooks/notebook.ipynb",
4446
"tree//something",
4547
):
46-
expected = self.url_prefix + next_path
48+
if "://" in next_path:
49+
expected = next_path
50+
else:
51+
expected = self.url_prefix + next_path
52+
4753
actual = self.login(next=expected)
4854
self.assertEqual(actual, expected)

0 commit comments

Comments
 (0)