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

Commit e694a59

Browse files
authored
Sanity check identity server passed to bind/unbind. (#9802)
Signed-off-by: Denis Kasak <dkasak@termina.org.uk>
1 parent 2b7dd21 commit e694a59

File tree

3 files changed

+59
-3
lines changed

3 files changed

+59
-3
lines changed

changelog.d/9802.bugfix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add some sanity checks to identity server passed to 3PID bind/unbind endpoints.

synapse/handlers/identity.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
# limitations under the License.
1616

1717
"""Utilities for interacting with Identity Servers"""
18-
1918
import logging
2019
import urllib.parse
2120
from typing import Awaitable, Callable, Dict, List, Optional, Tuple
@@ -34,7 +33,11 @@
3433
from synapse.types import JsonDict, Requester
3534
from synapse.util import json_decoder
3635
from synapse.util.hash import sha256_and_url_safe_base64
37-
from synapse.util.stringutils import assert_valid_client_secret, random_string
36+
from synapse.util.stringutils import (
37+
assert_valid_client_secret,
38+
random_string,
39+
valid_id_server_location,
40+
)
3841

3942
from ._base import BaseHandler
4043

@@ -172,6 +175,11 @@ async def bind_threepid(
172175
server with, if necessary. Required if use_v2 is true
173176
use_v2: Whether to use v2 Identity Service API endpoints. Defaults to True
174177
178+
Raises:
179+
SynapseError: On any of the following conditions
180+
- the supplied id_server is not a valid identity server name
181+
- we failed to contact the supplied identity server
182+
175183
Returns:
176184
The response from the identity server
177185
"""
@@ -181,6 +189,12 @@ async def bind_threepid(
181189
if id_access_token is None:
182190
use_v2 = False
183191

192+
if not valid_id_server_location(id_server):
193+
raise SynapseError(
194+
400,
195+
"id_server must be a valid hostname with optional port and path components",
196+
)
197+
184198
# Decide which API endpoint URLs to use
185199
headers = {}
186200
bind_data = {"sid": sid, "client_secret": client_secret, "mxid": mxid}
@@ -269,12 +283,21 @@ async def try_unbind_threepid_with_id_server(
269283
id_server: Identity server to unbind from
270284
271285
Raises:
272-
SynapseError: If we failed to contact the identity server
286+
SynapseError: On any of the following conditions
287+
- the supplied id_server is not a valid identity server name
288+
- we failed to contact the supplied identity server
273289
274290
Returns:
275291
True on success, otherwise False if the identity
276292
server doesn't support unbinding
277293
"""
294+
295+
if not valid_id_server_location(id_server):
296+
raise SynapseError(
297+
400,
298+
"id_server must be a valid hostname with optional port and path components",
299+
)
300+
278301
url = "https://%s/_matrix/identity/api/v1/3pid/unbind" % (id_server,)
279302
url_bytes = "/_matrix/identity/api/v1/3pid/unbind".encode("ascii")
280303

synapse/util/stringutils.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,38 @@ def parse_and_validate_server_name(server_name: str) -> Tuple[str, Optional[int]
132132
return host, port
133133

134134

135+
def valid_id_server_location(id_server: str) -> bool:
136+
"""Check whether an identity server location, such as the one passed as the
137+
`id_server` parameter to `/_matrix/client/r0/account/3pid/bind`, is valid.
138+
139+
A valid identity server location consists of a valid hostname and optional
140+
port number, optionally followed by any number of `/` delimited path
141+
components, without any fragment or query string parts.
142+
143+
Args:
144+
id_server: identity server location string to validate
145+
146+
Returns:
147+
True if valid, False otherwise.
148+
"""
149+
150+
components = id_server.split("/", 1)
151+
152+
host = components[0]
153+
154+
try:
155+
parse_and_validate_server_name(host)
156+
except ValueError:
157+
return False
158+
159+
if len(components) < 2:
160+
# no path
161+
return True
162+
163+
path = components[1]
164+
return "#" not in path and "?" not in path
165+
166+
135167
def parse_and_validate_mxc_uri(mxc: str) -> Tuple[str, Optional[int], str]:
136168
"""Parse the given string as an MXC URI
137169

0 commit comments

Comments
 (0)