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

Commit

Permalink
Don't fail /submit_token requests on incorrect session ID if request_…
Browse files Browse the repository at this point in the history
…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 <1342360+anoadragon453@users.noreply.github.com>

* Incorporate review

Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
  • Loading branch information
babolivier and anoadragon453 authored Aug 24, 2020
1 parent cbbf912 commit 3f49f74
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 6 deletions.
1 change: 1 addition & 0 deletions changelog.d/7991.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Don't fail `/submit_token` requests on incorrect session ID if `request_token_inhibit_3pid_errors` is turned on.
10 changes: 10 additions & 0 deletions synapse/rest/client/v2_alpha/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
import random
from http import HTTPStatus

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

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

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

raise SynapseError(400, "MSISDN is already in use", Codes.THREEPID_IN_USE)
Expand Down
7 changes: 7 additions & 0 deletions synapse/rest/client/v2_alpha/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import hmac
import logging
import random
from typing import List, Union

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

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

raise SynapseError(
Expand Down
25 changes: 19 additions & 6 deletions synapse/storage/databases/main/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,7 @@ def __init__(self, database: DatabasePool, db_conn, hs):
super(RegistrationStore, self).__init__(database, db_conn, hs)

self._account_validity = hs.config.account_validity
self._ignore_unknown_session_error = hs.config.request_token_inhibit_3pid_errors

if self._account_validity.enabled:
self._clock.call_later(
Expand Down Expand Up @@ -1302,15 +1303,22 @@ def validate_threepid_session_txn(txn):
)

if not row:
raise ThreepidValidationError(400, "Unknown session_id")
if self._ignore_unknown_session_error:
# If we need to inhibit the error caused by an incorrect session ID,
# use None as placeholder values for the client secret and the
# validation timestamp.
# It shouldn't be an issue because they're both only checked after
# the token check, which should fail. And if it doesn't for some
# reason, the next check is on the client secret, which is NOT NULL,
# so we don't have to worry about the client secret matching by
# accident.
row = {"client_secret": None, "validated_at": None}
else:
raise ThreepidValidationError(400, "Unknown session_id")

retrieved_client_secret = row["client_secret"]
validated_at = row["validated_at"]

if retrieved_client_secret != client_secret:
raise ThreepidValidationError(
400, "This client_secret does not match the provided session_id"
)

row = self.db_pool.simple_select_one_txn(
txn,
table="threepid_validation_token",
Expand All @@ -1326,6 +1334,11 @@ def validate_threepid_session_txn(txn):
expires = row["expires"]
next_link = row["next_link"]

if retrieved_client_secret != client_secret:
raise ThreepidValidationError(
400, "This client_secret does not match the provided session_id"
)

# If the session is already validated, no need to revalidate
if validated_at:
return next_link
Expand Down
31 changes: 31 additions & 0 deletions tests/storage/test_registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from twisted.internet import defer

from synapse.api.constants import UserTypes
from synapse.api.errors import ThreepidValidationError

from tests import unittest
from tests.utils import setup_test_homeserver
Expand Down Expand Up @@ -122,3 +123,33 @@ def test_is_support_user(self):
)
res = yield self.store.is_support_user(SUPPORT_USER)
self.assertTrue(res)

@defer.inlineCallbacks
def test_3pid_inhibit_invalid_validation_session_error(self):
"""Tests that enabling the configuration option to inhibit 3PID errors on
/requestToken also inhibits validation errors caused by an unknown session ID.
"""

# Check that, with the config setting set to false (the default value), a
# validation error is caused by the unknown session ID.
try:
yield defer.ensureDeferred(
self.store.validate_threepid_session(
"fake_sid", "fake_client_secret", "fake_token", 0,
)
)
except ThreepidValidationError as e:
self.assertEquals(e.msg, "Unknown session_id", e)

# Set the config setting to true.
self.store._ignore_unknown_session_error = True

# Check that now the validation error is caused by the token not matching.
try:
yield defer.ensureDeferred(
self.store.validate_threepid_session(
"fake_sid", "fake_client_secret", "fake_token", 0,
)
)
except ThreepidValidationError as e:
self.assertEquals(e.msg, "Validation token not found or has expired", e)

0 comments on commit 3f49f74

Please sign in to comment.