summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Lord <davidism@gmail.com>2023-05-01 12:35:58 -0700
committerDavid Lord <davidism@gmail.com>2023-05-01 12:35:58 -0700
commit825633eb783f49b0450b0e6866bc55985b154531 (patch)
tree8a7536df257adf8bcf55e39eb0399dc34bbfecbc
parentd8ab313dbf23c0fe88a40e5be8c1a6a32a5367cc (diff)
parent2051469a2be722121369b416a5c14435c9e82f90 (diff)
downloadwerkzeug-825633eb783f49b0450b0e6866bc55985b154531.tar.gz
Merge branch '2.3.x'
-rw-r--r--CHANGES.rst9
-rw-r--r--src/werkzeug/__init__.py2
-rw-r--r--src/werkzeug/datastructures/auth.py20
-rw-r--r--tests/test_http.py26
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"})