diff options
author | David Lord <davidism@gmail.com> | 2023-05-01 12:35:58 -0700 |
---|---|---|
committer | David Lord <davidism@gmail.com> | 2023-05-01 12:35:58 -0700 |
commit | 825633eb783f49b0450b0e6866bc55985b154531 (patch) | |
tree | 8a7536df257adf8bcf55e39eb0399dc34bbfecbc | |
parent | d8ab313dbf23c0fe88a40e5be8c1a6a32a5367cc (diff) | |
parent | 2051469a2be722121369b416a5c14435c9e82f90 (diff) | |
download | werkzeug-825633eb783f49b0450b0e6866bc55985b154531.tar.gz |
Merge branch '2.3.x'
-rw-r--r-- | CHANGES.rst | 9 | ||||
-rw-r--r-- | src/werkzeug/__init__.py | 2 | ||||
-rw-r--r-- | src/werkzeug/datastructures/auth.py | 20 | ||||
-rw-r--r-- | tests/test_http.py | 26 |
4 files changed, 46 insertions, 11 deletions
diff --git a/CHANGES.rst b/CHANGES.rst index 3e46b1ec..2d83ee59 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,5 +1,14 @@ .. currentmodule:: werkzeug +Version 2.3.4 +------------- + +Unreleased + +- ``Authorization.from_header`` and ``WWWAuthenticate.from_header`` detects tokens + that end with base64 padding (``=``). :issue:`2685` + + Version 2.3.3 ------------- diff --git a/src/werkzeug/__init__.py b/src/werkzeug/__init__.py index a448e0f3..b3208b2f 100644 --- a/src/werkzeug/__init__.py +++ b/src/werkzeug/__init__.py @@ -3,4 +3,4 @@ from .test import Client as Client from .wrappers import Request as Request from .wrappers import Response as Response -__version__ = "2.3.3" +__version__ = "2.3.4.dev" diff --git a/src/werkzeug/datastructures/auth.py b/src/werkzeug/datastructures/auth.py index afc719c7..0d216516 100644 --- a/src/werkzeug/datastructures/auth.py +++ b/src/werkzeug/datastructures/auth.py @@ -112,13 +112,12 @@ class Authorization: return cls(scheme, {"username": username, "password": password}) - parameters = parse_dict_header(rest) + if "=" in rest.rstrip("="): + # = that is not trailing, this is parameters. + return cls(scheme, parse_dict_header(rest), None) - if len(parameters) == 1 and parameters[next(iter(parameters))] is None: - # There is one parameter with no value, was actually a token. - return cls(scheme, None, rest) - - return cls(scheme, parameters, None) + # No = or only trailing =, this is a token. + return cls(scheme, None, rest) def to_header(self) -> str: """Produce an ``Authorization`` header value representing this data. @@ -377,12 +376,13 @@ class WWWAuthenticate: scheme, _, rest = value.partition(" ") scheme = scheme.lower() rest = rest.strip() - parameters = parse_dict_header(rest) - if len(parameters) == 1 and parameters[next(iter(parameters))] is None: - return cls(scheme, None, rest) + if "=" in rest.rstrip("="): + # = that is not trailing, this is parameters. + return cls(scheme, parse_dict_header(rest), None) - return cls(scheme, parameters, None) + # No = or only trailing =, this is a token. + return cls(scheme, None, rest) def to_header(self) -> str: """Produce a ``WWW-Authenticate`` header value representing this data.""" diff --git a/tests/test_http.py b/tests/test_http.py index 5ceb7ef5..7d76775b 100644 --- a/tests/test_http.py +++ b/tests/test_http.py @@ -203,6 +203,19 @@ class TestHTTPUtility: assert Authorization.from_header(None) is None assert Authorization.from_header("foo").type == "foo" + def test_authorization_token_padding(self): + # padded with = + token = base64.b64encode(b"This has base64 padding").decode() + a = Authorization.from_header(f"Token {token}") + assert a.type == "token" + assert a.token == token + + # padded with == + token = base64.b64encode(b"This has base64 padding..").decode() + a = Authorization.from_header(f"Token {token}") + assert a.type == "token" + assert a.token == token + def test_bad_authorization_header_encoding(self): """If the base64 encoded bytes can't be decoded as UTF-8""" content = base64.b64encode(b"\xffser:pass").decode() @@ -242,6 +255,19 @@ class TestHTTPUtility: assert WWWAuthenticate.from_header("broken").type == "broken" assert WWWAuthenticate.from_header("") is None + def test_www_authenticate_token_padding(self): + # padded with = + token = base64.b64encode(b"This has base64 padding").decode() + a = WWWAuthenticate.from_header(f"Token {token}") + assert a.type == "token" + assert a.token == token + + # padded with == + token = base64.b64encode(b"This has base64 padding..").decode() + a = WWWAuthenticate.from_header(f"Token {token}") + assert a.type == "token" + assert a.token == token + def test_www_authenticate_eq(self): basic1 = WWWAuthenticate.from_header("Basic realm=abc") basic2 = WWWAuthenticate("basic", {"realm": "abc"}) |