mirror of
https://git.anonymousland.org/anonymousland/synapse.git
synced 2024-12-26 17:09:23 -05:00
Validate client_secret parameter (#6767)
This commit is contained in:
parent
fa4d609e20
commit
9f7aaf90b5
1
changelog.d/6767.bugfix
Normal file
1
changelog.d/6767.bugfix
Normal file
@ -0,0 +1 @@
|
|||||||
|
Validate `client_secret` parameter using the regex provided by the Client-Server API, temporarily allowing `:` characters for older clients. The `:` character will be removed in a future release.
|
@ -38,7 +38,7 @@ from synapse.api.errors import (
|
|||||||
from synapse.config.emailconfig import ThreepidBehaviour
|
from synapse.config.emailconfig import ThreepidBehaviour
|
||||||
from synapse.http.client import SimpleHttpClient
|
from synapse.http.client import SimpleHttpClient
|
||||||
from synapse.util.hash import sha256_and_url_safe_base64
|
from synapse.util.hash import sha256_and_url_safe_base64
|
||||||
from synapse.util.stringutils import random_string
|
from synapse.util.stringutils import assert_valid_client_secret, random_string
|
||||||
|
|
||||||
from ._base import BaseHandler
|
from ._base import BaseHandler
|
||||||
|
|
||||||
@ -84,6 +84,8 @@ class IdentityHandler(BaseHandler):
|
|||||||
raise SynapseError(
|
raise SynapseError(
|
||||||
400, "Missing param client_secret in creds", errcode=Codes.MISSING_PARAM
|
400, "Missing param client_secret in creds", errcode=Codes.MISSING_PARAM
|
||||||
)
|
)
|
||||||
|
assert_valid_client_secret(client_secret)
|
||||||
|
|
||||||
session_id = creds.get("sid")
|
session_id = creds.get("sid")
|
||||||
if not session_id:
|
if not session_id:
|
||||||
raise SynapseError(
|
raise SynapseError(
|
||||||
|
@ -30,6 +30,7 @@ from synapse.http.servlet import (
|
|||||||
)
|
)
|
||||||
from synapse.push.mailer import Mailer, load_jinja2_templates
|
from synapse.push.mailer import Mailer, load_jinja2_templates
|
||||||
from synapse.util.msisdn import phone_number_to_msisdn
|
from synapse.util.msisdn import phone_number_to_msisdn
|
||||||
|
from synapse.util.stringutils import assert_valid_client_secret
|
||||||
from synapse.util.threepids import check_3pid_allowed
|
from synapse.util.threepids import check_3pid_allowed
|
||||||
|
|
||||||
from ._base import client_patterns, interactive_auth_handler
|
from ._base import client_patterns, interactive_auth_handler
|
||||||
@ -81,6 +82,8 @@ class EmailPasswordRequestTokenRestServlet(RestServlet):
|
|||||||
|
|
||||||
# Extract params from body
|
# Extract params from body
|
||||||
client_secret = body["client_secret"]
|
client_secret = body["client_secret"]
|
||||||
|
assert_valid_client_secret(client_secret)
|
||||||
|
|
||||||
email = body["email"]
|
email = body["email"]
|
||||||
send_attempt = body["send_attempt"]
|
send_attempt = body["send_attempt"]
|
||||||
next_link = body.get("next_link") # Optional param
|
next_link = body.get("next_link") # Optional param
|
||||||
@ -166,8 +169,9 @@ class PasswordResetSubmitTokenServlet(RestServlet):
|
|||||||
)
|
)
|
||||||
|
|
||||||
sid = parse_string(request, "sid", required=True)
|
sid = parse_string(request, "sid", required=True)
|
||||||
client_secret = parse_string(request, "client_secret", required=True)
|
|
||||||
token = parse_string(request, "token", required=True)
|
token = parse_string(request, "token", required=True)
|
||||||
|
client_secret = parse_string(request, "client_secret", required=True)
|
||||||
|
assert_valid_client_secret(client_secret)
|
||||||
|
|
||||||
# Attempt to validate a 3PID session
|
# Attempt to validate a 3PID session
|
||||||
try:
|
try:
|
||||||
@ -353,6 +357,8 @@ class EmailThreepidRequestTokenRestServlet(RestServlet):
|
|||||||
body = parse_json_object_from_request(request)
|
body = parse_json_object_from_request(request)
|
||||||
assert_params_in_dict(body, ["client_secret", "email", "send_attempt"])
|
assert_params_in_dict(body, ["client_secret", "email", "send_attempt"])
|
||||||
client_secret = body["client_secret"]
|
client_secret = body["client_secret"]
|
||||||
|
assert_valid_client_secret(client_secret)
|
||||||
|
|
||||||
email = body["email"]
|
email = body["email"]
|
||||||
send_attempt = body["send_attempt"]
|
send_attempt = body["send_attempt"]
|
||||||
next_link = body.get("next_link") # Optional param
|
next_link = body.get("next_link") # Optional param
|
||||||
@ -413,6 +419,8 @@ class MsisdnThreepidRequestTokenRestServlet(RestServlet):
|
|||||||
body, ["client_secret", "country", "phone_number", "send_attempt"]
|
body, ["client_secret", "country", "phone_number", "send_attempt"]
|
||||||
)
|
)
|
||||||
client_secret = body["client_secret"]
|
client_secret = body["client_secret"]
|
||||||
|
assert_valid_client_secret(client_secret)
|
||||||
|
|
||||||
country = body["country"]
|
country = body["country"]
|
||||||
phone_number = body["phone_number"]
|
phone_number = body["phone_number"]
|
||||||
send_attempt = body["send_attempt"]
|
send_attempt = body["send_attempt"]
|
||||||
@ -493,8 +501,9 @@ class AddThreepidEmailSubmitTokenServlet(RestServlet):
|
|||||||
)
|
)
|
||||||
|
|
||||||
sid = parse_string(request, "sid", required=True)
|
sid = parse_string(request, "sid", required=True)
|
||||||
client_secret = parse_string(request, "client_secret", required=True)
|
|
||||||
token = parse_string(request, "token", required=True)
|
token = parse_string(request, "token", required=True)
|
||||||
|
client_secret = parse_string(request, "client_secret", required=True)
|
||||||
|
assert_valid_client_secret(client_secret)
|
||||||
|
|
||||||
# Attempt to validate a 3PID session
|
# Attempt to validate a 3PID session
|
||||||
try:
|
try:
|
||||||
@ -559,6 +568,7 @@ class AddThreepidMsisdnSubmitTokenServlet(RestServlet):
|
|||||||
|
|
||||||
body = parse_json_object_from_request(request)
|
body = parse_json_object_from_request(request)
|
||||||
assert_params_in_dict(body, ["client_secret", "sid", "token"])
|
assert_params_in_dict(body, ["client_secret", "sid", "token"])
|
||||||
|
assert_valid_client_secret(body["client_secret"])
|
||||||
|
|
||||||
# Proxy submit_token request to msisdn threepid delegate
|
# Proxy submit_token request to msisdn threepid delegate
|
||||||
response = await self.identity_handler.proxy_msisdn_submit_token(
|
response = await self.identity_handler.proxy_msisdn_submit_token(
|
||||||
@ -600,8 +610,9 @@ class ThreepidRestServlet(RestServlet):
|
|||||||
)
|
)
|
||||||
assert_params_in_dict(threepid_creds, ["client_secret", "sid"])
|
assert_params_in_dict(threepid_creds, ["client_secret", "sid"])
|
||||||
|
|
||||||
client_secret = threepid_creds["client_secret"]
|
|
||||||
sid = threepid_creds["sid"]
|
sid = threepid_creds["sid"]
|
||||||
|
client_secret = threepid_creds["client_secret"]
|
||||||
|
assert_valid_client_secret(client_secret)
|
||||||
|
|
||||||
validation_session = await self.identity_handler.validate_threepid_session(
|
validation_session = await self.identity_handler.validate_threepid_session(
|
||||||
client_secret, sid
|
client_secret, sid
|
||||||
@ -637,8 +648,9 @@ class ThreepidAddRestServlet(RestServlet):
|
|||||||
body = parse_json_object_from_request(request)
|
body = parse_json_object_from_request(request)
|
||||||
|
|
||||||
assert_params_in_dict(body, ["client_secret", "sid"])
|
assert_params_in_dict(body, ["client_secret", "sid"])
|
||||||
client_secret = body["client_secret"]
|
|
||||||
sid = body["sid"]
|
sid = body["sid"]
|
||||||
|
client_secret = body["client_secret"]
|
||||||
|
assert_valid_client_secret(client_secret)
|
||||||
|
|
||||||
await self.auth_handler.validate_user_via_ui_auth(
|
await self.auth_handler.validate_user_via_ui_auth(
|
||||||
requester, body, self.hs.get_ip_from_request(request)
|
requester, body, self.hs.get_ip_from_request(request)
|
||||||
@ -676,8 +688,9 @@ class ThreepidBindRestServlet(RestServlet):
|
|||||||
assert_params_in_dict(body, ["id_server", "sid", "client_secret"])
|
assert_params_in_dict(body, ["id_server", "sid", "client_secret"])
|
||||||
id_server = body["id_server"]
|
id_server = body["id_server"]
|
||||||
sid = body["sid"]
|
sid = body["sid"]
|
||||||
client_secret = body["client_secret"]
|
|
||||||
id_access_token = body.get("id_access_token") # optional
|
id_access_token = body.get("id_access_token") # optional
|
||||||
|
client_secret = body["client_secret"]
|
||||||
|
assert_valid_client_secret(client_secret)
|
||||||
|
|
||||||
requester = await self.auth.get_user_by_req(request)
|
requester = await self.auth.get_user_by_req(request)
|
||||||
user_id = requester.user.to_string()
|
user_id = requester.user.to_string()
|
||||||
|
@ -49,6 +49,7 @@ from synapse.http.servlet import (
|
|||||||
from synapse.push.mailer import load_jinja2_templates
|
from synapse.push.mailer import load_jinja2_templates
|
||||||
from synapse.util.msisdn import phone_number_to_msisdn
|
from synapse.util.msisdn import phone_number_to_msisdn
|
||||||
from synapse.util.ratelimitutils import FederationRateLimiter
|
from synapse.util.ratelimitutils import FederationRateLimiter
|
||||||
|
from synapse.util.stringutils import assert_valid_client_secret
|
||||||
from synapse.util.threepids import check_3pid_allowed
|
from synapse.util.threepids import check_3pid_allowed
|
||||||
|
|
||||||
from ._base import client_patterns, interactive_auth_handler
|
from ._base import client_patterns, interactive_auth_handler
|
||||||
@ -116,6 +117,8 @@ class EmailRegisterRequestTokenRestServlet(RestServlet):
|
|||||||
|
|
||||||
# Extract params from body
|
# Extract params from body
|
||||||
client_secret = body["client_secret"]
|
client_secret = body["client_secret"]
|
||||||
|
assert_valid_client_secret(client_secret)
|
||||||
|
|
||||||
email = body["email"]
|
email = body["email"]
|
||||||
send_attempt = body["send_attempt"]
|
send_attempt = body["send_attempt"]
|
||||||
next_link = body.get("next_link") # Optional param
|
next_link = body.get("next_link") # Optional param
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright 2014-2016 OpenMarket Ltd
|
# Copyright 2014-2016 OpenMarket Ltd
|
||||||
|
# Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@ -14,14 +15,22 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import random
|
import random
|
||||||
|
import re
|
||||||
import string
|
import string
|
||||||
|
|
||||||
import six
|
import six
|
||||||
from six import PY2, PY3
|
from six import PY2, PY3
|
||||||
from six.moves import range
|
from six.moves import range
|
||||||
|
|
||||||
|
from synapse.api.errors import Codes, SynapseError
|
||||||
|
|
||||||
_string_with_symbols = string.digits + string.ascii_letters + ".,;:^&*-_+=#~@"
|
_string_with_symbols = string.digits + string.ascii_letters + ".,;:^&*-_+=#~@"
|
||||||
|
|
||||||
|
# https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-register-email-requesttoken
|
||||||
|
# Note: The : character is allowed here for older clients, but will be removed in a
|
||||||
|
# future release. Context: https://github.com/matrix-org/synapse/issues/6766
|
||||||
|
client_secret_regex = re.compile(r"^[0-9a-zA-Z\.\=\_\-\:]+$")
|
||||||
|
|
||||||
# random_string and random_string_with_symbols are used for a range of things,
|
# random_string and random_string_with_symbols are used for a range of things,
|
||||||
# some cryptographically important, some less so. We use SystemRandom to make sure
|
# some cryptographically important, some less so. We use SystemRandom to make sure
|
||||||
# we get cryptographically-secure randoms.
|
# we get cryptographically-secure randoms.
|
||||||
@ -109,3 +118,11 @@ def exception_to_unicode(e):
|
|||||||
return msg.decode("utf-8", errors="replace")
|
return msg.decode("utf-8", errors="replace")
|
||||||
else:
|
else:
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
|
|
||||||
|
def assert_valid_client_secret(client_secret):
|
||||||
|
"""Validate that a given string matches the client_secret regex defined by the spec"""
|
||||||
|
if client_secret_regex.match(client_secret) is None:
|
||||||
|
raise SynapseError(
|
||||||
|
400, "Invalid client_secret parameter", errcode=Codes.INVALID_PARAM
|
||||||
|
)
|
||||||
|
51
tests/util/test_stringutils.py
Normal file
51
tests/util/test_stringutils.py
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
from synapse.api.errors import SynapseError
|
||||||
|
from synapse.util.stringutils import assert_valid_client_secret
|
||||||
|
|
||||||
|
from .. import unittest
|
||||||
|
|
||||||
|
|
||||||
|
class StringUtilsTestCase(unittest.TestCase):
|
||||||
|
def test_client_secret_regex(self):
|
||||||
|
"""Ensure that client_secret does not contain illegal characters"""
|
||||||
|
good = [
|
||||||
|
"abcde12345",
|
||||||
|
"ABCabc123",
|
||||||
|
"_--something==_",
|
||||||
|
"...--==-18913",
|
||||||
|
"8Dj2odd-e9asd.cd==_--ddas-secret-",
|
||||||
|
# We temporarily allow : characters: https://github.com/matrix-org/synapse/issues/6766
|
||||||
|
# To be removed in a future release
|
||||||
|
"SECRET:1234567890",
|
||||||
|
]
|
||||||
|
|
||||||
|
bad = [
|
||||||
|
"--+-/secret",
|
||||||
|
"\\dx--dsa288",
|
||||||
|
"",
|
||||||
|
"AAS//",
|
||||||
|
"asdj**",
|
||||||
|
">X><Z<!!-)))",
|
||||||
|
"a@b.com",
|
||||||
|
]
|
||||||
|
|
||||||
|
for client_secret in good:
|
||||||
|
assert_valid_client_secret(client_secret)
|
||||||
|
|
||||||
|
for client_secret in bad:
|
||||||
|
with self.assertRaises(SynapseError):
|
||||||
|
assert_valid_client_secret(client_secret)
|
Loading…
Reference in New Issue
Block a user