Skip to content

Commit

Permalink
Validate client_secret parameter according to spec (#246)
Browse files Browse the repository at this point in the history
  • Loading branch information
anoadragon453 authored Jan 24, 2020
1 parent b00dd0b commit 7a49644
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 5 deletions.
17 changes: 16 additions & 1 deletion sydent/http/servlets/emailservlet.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

from twisted.web.resource import Resource

from sydent.util.stringutils import is_valid_client_secret
from sydent.util.emailutils import EmailAddressException, EmailSendException
from sydent.validators.emailvalidator import SessionExpiredException
from sydent.validators.emailvalidator import IncorrectClientSecretException
Expand All @@ -39,8 +40,15 @@ def render_POST(self, request):
args = get_args(request, ('email', 'client_secret', 'send_attempt'))

email = args['email']
clientSecret = args['client_secret']
sendAttempt = args['send_attempt']
clientSecret = args['client_secret']

if not is_valid_client_secret(clientSecret):
request.setResponseCode(400)
return {
'errcode': 'M_INVALID_PARAM',
'error': 'Invalid client_secret provided'
}

ipaddress = self.sydent.ip_from_request(request)

Expand Down Expand Up @@ -114,6 +122,13 @@ def do_validate_request(self, request):
tokenString = args['token']
clientSecret = args['client_secret']

if not is_valid_client_secret(clientSecret):
request.setResponseCode(400)
return {
'errcode': 'M_INVALID_PARAM',
'error': 'Invalid client_secret provided'
}

try:
resp = self.sydent.validators.email.validateSessionWithToken(sid, clientSecret, tokenString)
except IncorrectClientSecretException:
Expand Down
8 changes: 8 additions & 0 deletions sydent/http/servlets/getvalidated3pidservlet.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from sydent.http.servlets import jsonwrap, get_args
from sydent.http.auth import authIfV2
from sydent.db.valsession import ThreePidValSessionStore
from sydent.util.stringutils import is_valid_client_secret
from sydent.validators import SessionExpiredException, IncorrectClientSecretException, InvalidSessionIdException,\
SessionNotValidatedException

Expand All @@ -37,6 +38,13 @@ def render_GET(self, request):
sid = args['sid']
clientSecret = args['client_secret']

if not is_valid_client_secret(clientSecret):
request.setResponseCode(400)
return {
'errcode': 'M_INVALID_PARAM',
'error': 'Invalid client_secret provided'
}

valSessionStore = ThreePidValSessionStore(self.sydent)

noMatchError = {'errcode': 'M_NO_VALID_SESSION',
Expand Down
17 changes: 16 additions & 1 deletion sydent/http/servlets/msisdnservlet.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

from sydent.http.servlets import get_args, jsonwrap, send_cors
from sydent.http.auth import authIfV2
from sydent.util.stringutils import is_valid_client_secret


logger = logging.getLogger(__name__)
Expand All @@ -46,8 +47,15 @@ def render_POST(self, request):

raw_phone_number = args['phone_number']
country = args['country']
clientSecret = args['client_secret']
sendAttempt = args['send_attempt']
clientSecret = args['client_secret']

if not is_valid_client_secret(clientSecret):
request.setResponseCode(400)
return {
'errcode': 'M_INVALID_PARAM',
'error': 'Invalid client_secret provided'
}

try:
phone_number_object = phonenumbers.parse(raw_phone_number, country)
Expand Down Expand Up @@ -116,6 +124,7 @@ def render_GET(self, request):
request.setResponseCode(302)
request.setHeader("Location", next_link)
else:
request.setResponseCode(400)
msg = "Verification failed: you may need to request another verification text"

templateFile = self.sydent.cfg.get('http', 'verify_response_template')
Expand All @@ -138,6 +147,12 @@ def do_validate_request(self, args):
tokenString = args['token']
clientSecret = args['client_secret']

if not is_valid_client_secret(clientSecret):
return {
'errcode': 'M_INVALID_PARAM',
'error': 'Invalid client_secret provided'
}

try:
resp = self.sydent.validators.msisdn.validateSessionWithToken(sid, clientSecret, tokenString)
except IncorrectClientSecretException:
Expand Down
9 changes: 9 additions & 0 deletions sydent/http/servlets/threepidbindservlet.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@
from sydent.db.valsession import ThreePidValSessionStore
from sydent.http.servlets import get_args, jsonwrap, send_cors, MatrixRestError
from sydent.http.auth import authIfV2
from sydent.util.stringutils import is_valid_client_secret
from sydent.validators import SessionExpiredException, IncorrectClientSecretException, InvalidSessionIdException,\
SessionNotValidatedException


class ThreePidBindServlet(Resource):
def __init__(self, sydent):
self.sydent = sydent
Expand All @@ -39,6 +41,13 @@ def render_POST(self, request):
mxid = args['mxid']
clientSecret = args['client_secret']

if not is_valid_client_secret(clientSecret):
request.setResponseCode(400)
return {
'errcode': 'M_INVALID_PARAM',
'error': 'Invalid client_secret provided'
}

# Return the same error for not found / bad client secret otherwise people can get information about
# sessions without knowing the secret
noMatchError = {'errcode': 'M_NO_VALID_SESSION',
Expand Down
18 changes: 15 additions & 3 deletions sydent/http/servlets/threepidunbindservlet.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@
import json
import logging

from sydent.http.servlets import get_args, jsonwrap
from sydent.hs_federation.verifier import NoAuthenticationError
from signedjson.sign import SignatureVerifyException
from sydent.db.valsession import ThreePidValSessionStore
from sydent.validators import SessionExpiredException, IncorrectClientSecretException, InvalidSessionIdException,\
SessionNotValidatedException
from sydent.util.stringutils import is_valid_client_secret
from sydent.validators import (
IncorrectClientSecretException,
InvalidSessionIdException,
SessionNotValidatedException,
)

from twisted.web.resource import Resource
from twisted.web import server
Expand Down Expand Up @@ -85,6 +88,15 @@ def _async_render_POST(self, request):
sid = body['sid']
client_secret = body['client_secret']

if not is_valid_client_secret(client_secret):
request.setResponseCode(400)
request.write(json.dumps({
'errcode': 'M_INVALID_PARAM',
'error': 'Invalid client_secret provided'
}))
request.finish()
return

valSessionStore = ThreePidValSessionStore(self.sydent)

noMatchError = {'errcode': 'M_NO_VALID_SESSION',
Expand Down
30 changes: 30 additions & 0 deletions sydent/util/stringutils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# -*- 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.
import re

# 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/sydent/issues/247
client_secret_regex = re.compile(r"^[0-9a-zA-Z\.\=\_\-\:]+$")


def is_valid_client_secret(client_secret):
"""Validate that a given string matches the client_secret regex defined by the spec
:param client_secret: The client_secret to validate
:type client_secret: str
:returns: Whether the client_secret is valid
:rtype: bool
"""
return client_secret_regex.match(client_secret) is not None

0 comments on commit 7a49644

Please sign in to comment.