bpo-34911: Added support for secure websocket cookies (GH-9734)

This commit is contained in:
Paul Bailey 2018-10-08 13:49:29 -05:00 committed by Andrew Svetlov
parent af5658ae93
commit 4c33997057
4 changed files with 67 additions and 5 deletions

View File

@ -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

View File

@ -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

View File

@ -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')

View File

@ -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.