Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 8afb7b5

Browse files
authored
Make handling of federation Authorization header (more) compliant with RFC7230 (#12774)
The main differences are: - values with delimiters (such as colons) should be quoted, so always quote the origin, since it could contain a colon followed by a port number - should allow more than one space after "X-Matrix" - quoted values with backslash-escaped characters should be unescaped - names should be case insensitive
1 parent 37935b5 commit 8afb7b5

File tree

4 files changed

+35
-5
lines changed

4 files changed

+35
-5
lines changed

changelog.d/12774.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Make handling of federation Authorization header (more) compliant with RFC7230.

synapse/federation/transport/server/_base.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,14 +169,16 @@ def _parse_auth_header(header_bytes: bytes) -> Tuple[str, str, str, Optional[str
169169
"""
170170
try:
171171
header_str = header_bytes.decode("utf-8")
172-
params = header_str.split(" ")[1].split(",")
172+
params = re.split(" +", header_str)[1].split(",")
173173
param_dict: Dict[str, str] = {
174-
k: v for k, v in [param.split("=", maxsplit=1) for param in params]
174+
k.lower(): v for k, v in [param.split("=", maxsplit=1) for param in params]
175175
}
176176

177177
def strip_quotes(value: str) -> str:
178178
if value.startswith('"'):
179-
return value[1:-1]
179+
return re.sub(
180+
"\\\\(.)", lambda matchobj: matchobj.group(1), value[1:-1]
181+
)
180182
else:
181183
return value
182184

synapse/http/matrixfederationclient.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -747,7 +747,7 @@ def build_auth_headers(
747747
for key, sig in request["signatures"][self.server_name].items():
748748
auth_headers.append(
749749
(
750-
'X-Matrix origin=%s,key="%s",sig="%s",destination="%s"'
750+
'X-Matrix origin="%s",key="%s",sig="%s",destination="%s"'
751751
% (
752752
self.server_name,
753753
key,

tests/federation/transport/server/test__base.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
from synapse.api.errors import Codes
1919
from synapse.federation.transport.server import BaseFederationServlet
20-
from synapse.federation.transport.server._base import Authenticator
20+
from synapse.federation.transport.server._base import Authenticator, _parse_auth_header
2121
from synapse.http.server import JsonResource, cancellable
2222
from synapse.server import HomeServer
2323
from synapse.types import JsonDict
@@ -112,3 +112,30 @@ def test_uncancellable_disconnect(self) -> None:
112112
expect_cancellation=False,
113113
expected_body={"result": True},
114114
)
115+
116+
117+
class BaseFederationAuthorizationTests(unittest.TestCase):
118+
def test_authorization_header(self) -> None:
119+
"""Tests that the Authorization header is parsed correctly."""
120+
121+
# test a "normal" Authorization header
122+
self.assertEqual(
123+
_parse_auth_header(
124+
b'X-Matrix origin=foo,key="ed25519:1",sig="sig",destination="bar"'
125+
),
126+
("foo", "ed25519:1", "sig", "bar"),
127+
)
128+
# test an Authorization with extra spaces, upper-case names, and escaped
129+
# characters
130+
self.assertEqual(
131+
_parse_auth_header(
132+
b'X-Matrix ORIGIN=foo,KEY="ed25\\519:1",SIG="sig",destination="bar"'
133+
),
134+
("foo", "ed25519:1", "sig", "bar"),
135+
)
136+
self.assertEqual(
137+
_parse_auth_header(
138+
b'X-Matrix origin=foo,key="ed25519:1",sig="sig",destination="bar",extra_field=ignored'
139+
),
140+
("foo", "ed25519:1", "sig", "bar"),
141+
)

0 commit comments

Comments
 (0)