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

Commit 3f49f74

Browse files
Don't fail /submit_token requests on incorrect session ID if request_token_inhibit_3pid_errors is turned on (#7991)
* Don't raise session_id errors on submit_token if request_token_inhibit_3pid_errors is set * Changelog * Also wait some time before responding to /requestToken * Incorporate review * Update synapse/storage/databases/main/registration.py Co-authored-by: Andrew Morgan <[email protected]> * Incorporate review Co-authored-by: Andrew Morgan <[email protected]>
1 parent cbbf912 commit 3f49f74

File tree

5 files changed

+68
-6
lines changed

5 files changed

+68
-6
lines changed

changelog.d/7991.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Don't fail `/submit_token` requests on incorrect session ID if `request_token_inhibit_3pid_errors` is turned on.

synapse/rest/client/v2_alpha/account.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
# See the License for the specific language governing permissions and
1616
# limitations under the License.
1717
import logging
18+
import random
1819
from http import HTTPStatus
1920

2021
from synapse.api.constants import LoginType
@@ -109,6 +110,9 @@ async def on_POST(self, request):
109110
if self.config.request_token_inhibit_3pid_errors:
110111
# Make the client think the operation succeeded. See the rationale in the
111112
# comments for request_token_inhibit_3pid_errors.
113+
# Also wait for some random amount of time between 100ms and 1s to make it
114+
# look like we did something.
115+
await self.hs.clock.sleep(random.randint(1, 10) / 10)
112116
return 200, {"sid": random_string(16)}
113117

114118
raise SynapseError(400, "Email not found", Codes.THREEPID_NOT_FOUND)
@@ -448,6 +452,9 @@ async def on_POST(self, request):
448452
if self.config.request_token_inhibit_3pid_errors:
449453
# Make the client think the operation succeeded. See the rationale in the
450454
# comments for request_token_inhibit_3pid_errors.
455+
# Also wait for some random amount of time between 100ms and 1s to make it
456+
# look like we did something.
457+
await self.hs.clock.sleep(random.randint(1, 10) / 10)
451458
return 200, {"sid": random_string(16)}
452459

453460
raise SynapseError(400, "Email is already in use", Codes.THREEPID_IN_USE)
@@ -516,6 +523,9 @@ async def on_POST(self, request):
516523
if self.hs.config.request_token_inhibit_3pid_errors:
517524
# Make the client think the operation succeeded. See the rationale in the
518525
# comments for request_token_inhibit_3pid_errors.
526+
# Also wait for some random amount of time between 100ms and 1s to make it
527+
# look like we did something.
528+
await self.hs.clock.sleep(random.randint(1, 10) / 10)
519529
return 200, {"sid": random_string(16)}
520530

521531
raise SynapseError(400, "MSISDN is already in use", Codes.THREEPID_IN_USE)

synapse/rest/client/v2_alpha/register.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import hmac
1818
import logging
19+
import random
1920
from typing import List, Union
2021

2122
import synapse
@@ -131,6 +132,9 @@ async def on_POST(self, request):
131132
if self.hs.config.request_token_inhibit_3pid_errors:
132133
# Make the client think the operation succeeded. See the rationale in the
133134
# comments for request_token_inhibit_3pid_errors.
135+
# Also wait for some random amount of time between 100ms and 1s to make it
136+
# look like we did something.
137+
await self.hs.clock.sleep(random.randint(1, 10) / 10)
134138
return 200, {"sid": random_string(16)}
135139

136140
raise SynapseError(400, "Email is already in use", Codes.THREEPID_IN_USE)
@@ -203,6 +207,9 @@ async def on_POST(self, request):
203207
if self.hs.config.request_token_inhibit_3pid_errors:
204208
# Make the client think the operation succeeded. See the rationale in the
205209
# comments for request_token_inhibit_3pid_errors.
210+
# Also wait for some random amount of time between 100ms and 1s to make it
211+
# look like we did something.
212+
await self.hs.clock.sleep(random.randint(1, 10) / 10)
206213
return 200, {"sid": random_string(16)}
207214

208215
raise SynapseError(

synapse/storage/databases/main/registration.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,7 @@ def __init__(self, database: DatabasePool, db_conn, hs):
889889
super(RegistrationStore, self).__init__(database, db_conn, hs)
890890

891891
self._account_validity = hs.config.account_validity
892+
self._ignore_unknown_session_error = hs.config.request_token_inhibit_3pid_errors
892893

893894
if self._account_validity.enabled:
894895
self._clock.call_later(
@@ -1302,15 +1303,22 @@ def validate_threepid_session_txn(txn):
13021303
)
13031304

13041305
if not row:
1305-
raise ThreepidValidationError(400, "Unknown session_id")
1306+
if self._ignore_unknown_session_error:
1307+
# If we need to inhibit the error caused by an incorrect session ID,
1308+
# use None as placeholder values for the client secret and the
1309+
# validation timestamp.
1310+
# It shouldn't be an issue because they're both only checked after
1311+
# the token check, which should fail. And if it doesn't for some
1312+
# reason, the next check is on the client secret, which is NOT NULL,
1313+
# so we don't have to worry about the client secret matching by
1314+
# accident.
1315+
row = {"client_secret": None, "validated_at": None}
1316+
else:
1317+
raise ThreepidValidationError(400, "Unknown session_id")
1318+
13061319
retrieved_client_secret = row["client_secret"]
13071320
validated_at = row["validated_at"]
13081321

1309-
if retrieved_client_secret != client_secret:
1310-
raise ThreepidValidationError(
1311-
400, "This client_secret does not match the provided session_id"
1312-
)
1313-
13141322
row = self.db_pool.simple_select_one_txn(
13151323
txn,
13161324
table="threepid_validation_token",
@@ -1326,6 +1334,11 @@ def validate_threepid_session_txn(txn):
13261334
expires = row["expires"]
13271335
next_link = row["next_link"]
13281336

1337+
if retrieved_client_secret != client_secret:
1338+
raise ThreepidValidationError(
1339+
400, "This client_secret does not match the provided session_id"
1340+
)
1341+
13291342
# If the session is already validated, no need to revalidate
13301343
if validated_at:
13311344
return next_link

tests/storage/test_registration.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from twisted.internet import defer
1818

1919
from synapse.api.constants import UserTypes
20+
from synapse.api.errors import ThreepidValidationError
2021

2122
from tests import unittest
2223
from tests.utils import setup_test_homeserver
@@ -122,3 +123,33 @@ def test_is_support_user(self):
122123
)
123124
res = yield self.store.is_support_user(SUPPORT_USER)
124125
self.assertTrue(res)
126+
127+
@defer.inlineCallbacks
128+
def test_3pid_inhibit_invalid_validation_session_error(self):
129+
"""Tests that enabling the configuration option to inhibit 3PID errors on
130+
/requestToken also inhibits validation errors caused by an unknown session ID.
131+
"""
132+
133+
# Check that, with the config setting set to false (the default value), a
134+
# validation error is caused by the unknown session ID.
135+
try:
136+
yield defer.ensureDeferred(
137+
self.store.validate_threepid_session(
138+
"fake_sid", "fake_client_secret", "fake_token", 0,
139+
)
140+
)
141+
except ThreepidValidationError as e:
142+
self.assertEquals(e.msg, "Unknown session_id", e)
143+
144+
# Set the config setting to true.
145+
self.store._ignore_unknown_session_error = True
146+
147+
# Check that now the validation error is caused by the token not matching.
148+
try:
149+
yield defer.ensureDeferred(
150+
self.store.validate_threepid_session(
151+
"fake_sid", "fake_client_secret", "fake_token", 0,
152+
)
153+
)
154+
except ThreepidValidationError as e:
155+
self.assertEquals(e.msg, "Validation token not found or has expired", e)

0 commit comments

Comments
 (0)