From 4c339970570d07916bee6ade51f4e9781d51627a Mon Sep 17 00:00:00 2001 From: Paul Bailey Date: Mon, 8 Oct 2018 13:49:29 -0500 Subject: [PATCH] bpo-34911: Added support for secure websocket cookies (GH-9734) --- Doc/library/http.cookiejar.rst | 10 ++-- Lib/http/cookiejar.py | 4 +- Lib/test/test_http_cookiejar.py | 55 +++++++++++++++++++ .../2018-10-08-15-22-02.bpo-34911.hCy0Fv.rst | 3 + 4 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2018-10-08-15-22-02.bpo-34911.hCy0Fv.rst diff --git a/Doc/library/http.cookiejar.rst b/Doc/library/http.cookiejar.rst index d8da6683a3a..4c8be2917b2 100644 --- a/Doc/library/http.cookiejar.rst +++ b/Doc/library/http.cookiejar.rst @@ -78,14 +78,16 @@ The following classes are provided: from / returned to the server. -.. class:: DefaultCookiePolicy( blocked_domains=None, allowed_domains=None, netscape=True, rfc2965=False, rfc2109_as_netscape=None, hide_cookie2=False, strict_domain=False, strict_rfc2965_unverifiable=True, strict_ns_unverifiable=False, strict_ns_domain=DefaultCookiePolicy.DomainLiberal, strict_ns_set_initial_dollar=False, strict_ns_set_path=False ) +.. class:: DefaultCookiePolicy( blocked_domains=None, allowed_domains=None, netscape=True, rfc2965=False, rfc2109_as_netscape=None, hide_cookie2=False, strict_domain=False, strict_rfc2965_unverifiable=True, strict_ns_unverifiable=False, strict_ns_domain=DefaultCookiePolicy.DomainLiberal, strict_ns_set_initial_dollar=False, strict_ns_set_path=False, secure_protocols=("https", "wss") ) Constructor arguments should be passed as keyword arguments only. *blocked_domains* is a sequence of domain names that we never accept cookies from, nor return cookies to. *allowed_domains* if not :const:`None`, this is a - sequence of the only domains for which we accept and return cookies. For all - other arguments, see the documentation for :class:`CookiePolicy` and - :class:`DefaultCookiePolicy` objects. + sequence of the only domains for which we accept and return cookies. + *secure_protocols* is a sequence of protocols for which secure cookies can be + added to. By default *https* and *wss* (secure websocket) are considered + secure protocols. For all other arguments, see the documentation for + :class:`CookiePolicy` and :class:`DefaultCookiePolicy` objects. :class:`DefaultCookiePolicy` implements the standard accept / reject rules for Netscape and :rfc:`2965` cookies. By default, :rfc:`2109` cookies (ie. cookies diff --git a/Lib/http/cookiejar.py b/Lib/http/cookiejar.py index e0f1032b281..0ba8200f325 100644 --- a/Lib/http/cookiejar.py +++ b/Lib/http/cookiejar.py @@ -878,6 +878,7 @@ class DefaultCookiePolicy(CookiePolicy): strict_ns_domain=DomainLiberal, strict_ns_set_initial_dollar=False, strict_ns_set_path=False, + secure_protocols=("https", "wss") ): """Constructor arguments should be passed as keyword arguments only.""" self.netscape = netscape @@ -890,6 +891,7 @@ class DefaultCookiePolicy(CookiePolicy): self.strict_ns_domain = strict_ns_domain self.strict_ns_set_initial_dollar = strict_ns_set_initial_dollar self.strict_ns_set_path = strict_ns_set_path + self.secure_protocols = secure_protocols if blocked_domains is not None: self._blocked_domains = tuple(blocked_domains) @@ -1116,7 +1118,7 @@ class DefaultCookiePolicy(CookiePolicy): return True def return_ok_secure(self, cookie, request): - if cookie.secure and request.type != "https": + if cookie.secure and request.type not in self.secure_protocols: _debug(" secure cookie with non-secure request") return False return True diff --git a/Lib/test/test_http_cookiejar.py b/Lib/test/test_http_cookiejar.py index 6fee4df10a4..968725901f2 100644 --- a/Lib/test/test_http_cookiejar.py +++ b/Lib/test/test_http_cookiejar.py @@ -984,6 +984,61 @@ class CookieTests(unittest.TestCase): c._cookies["www.acme.com"]["/"]["foo2"].secure, "secure cookie registered non-secure") + def test_secure_block(self): + pol = DefaultCookiePolicy() + c = CookieJar(policy=pol) + + headers = ["Set-Cookie: session=narf; secure; path=/"] + req = urllib.request.Request("https://www.acme.com/") + res = FakeResponse(headers, "https://www.acme.com/") + c.extract_cookies(res, req) + self.assertEqual(len(c), 1) + + req = urllib.request.Request("https://www.acme.com/") + c.add_cookie_header(req) + self.assertTrue(req.has_header("Cookie")) + + req = urllib.request.Request("http://www.acme.com/") + c.add_cookie_header(req) + self.assertFalse(req.has_header("Cookie")) + + # secure websocket protocol + req = urllib.request.Request("wss://www.acme.com/") + c.add_cookie_header(req) + self.assertTrue(req.has_header("Cookie")) + + # non-secure websocket protocol + req = urllib.request.Request("ws://www.acme.com/") + c.add_cookie_header(req) + self.assertFalse(req.has_header("Cookie")) + + def test_custom_secure_protocols(self): + pol = DefaultCookiePolicy(secure_protocols=["foos"]) + c = CookieJar(policy=pol) + + headers = ["Set-Cookie: session=narf; secure; path=/"] + req = urllib.request.Request("https://www.acme.com/") + res = FakeResponse(headers, "https://www.acme.com/") + c.extract_cookies(res, req) + self.assertEqual(len(c), 1) + + # test https removed from secure protocol list + req = urllib.request.Request("https://www.acme.com/") + c.add_cookie_header(req) + self.assertFalse(req.has_header("Cookie")) + + req = urllib.request.Request("http://www.acme.com/") + c.add_cookie_header(req) + self.assertFalse(req.has_header("Cookie")) + + req = urllib.request.Request("foos://www.acme.com/") + c.add_cookie_header(req) + self.assertTrue(req.has_header("Cookie")) + + req = urllib.request.Request("foo://www.acme.com/") + c.add_cookie_header(req) + self.assertFalse(req.has_header("Cookie")) + def test_quote_cookie_value(self): c = CookieJar(policy=DefaultCookiePolicy(rfc2965=True)) interact_2965(c, "http://www.acme.com/", r'foo=\b"a"r; Version=1') diff --git a/Misc/NEWS.d/next/Library/2018-10-08-15-22-02.bpo-34911.hCy0Fv.rst b/Misc/NEWS.d/next/Library/2018-10-08-15-22-02.bpo-34911.hCy0Fv.rst new file mode 100644 index 00000000000..d3509475306 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-10-08-15-22-02.bpo-34911.hCy0Fv.rst @@ -0,0 +1,3 @@ +Added *secure_protocols* argument to *http.cookiejar.DefaultCookiePolicy* to +allow for tweaking of protocols and also to add support by default for +*wss*, the secure websocket protocol.