From 59bf16eddcb793705ee6bc243a2158824f7e05c8 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 30 Mar 2015 18:13:10 +0100 Subject: New registration for C/S API v2. Only ReCAPTCHA working currently. --- synapse/api/constants.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'synapse/api/constants.py') diff --git a/synapse/api/constants.py b/synapse/api/constants.py index b16bf4247d..3e0ce170a4 100644 --- a/synapse/api/constants.py +++ b/synapse/api/constants.py @@ -62,6 +62,8 @@ class LoginType(object): APPLICATION_SERVICE = u"m.login.application_service" SHARED_SECRET = u"org.matrix.login.shared_secret" + HIDDEN_TYPES = [APPLICATION_SERVICE, SHARED_SECRET] + class EventTypes(object): Member = "m.room.member" -- cgit 1.4.1 From 70a84f17f39bbc5c8a68541874ca4767871f2b79 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 2 Apr 2015 17:01:29 +0100 Subject: Add shared secret auth into register v2 and switch the script over. --- register_new_matrix_user | 5 +-- synapse/api/constants.py | 4 +- synapse/rest/client/v2_alpha/register.py | 69 +++++++++++++++++++++++++++----- 3 files changed, 63 insertions(+), 15 deletions(-) (limited to 'synapse/api/constants.py') diff --git a/register_new_matrix_user b/register_new_matrix_user index daddadc302..f833d2a4db 100755 --- a/register_new_matrix_user +++ b/register_new_matrix_user @@ -33,10 +33,9 @@ def request_registration(user, password, server_location, shared_secret): ).hexdigest() data = { - "user": user, + "username": user, "password": password, "mac": mac, - "type": "org.matrix.login.shared_secret", } server_location = server_location.rstrip("/") @@ -44,7 +43,7 @@ def request_registration(user, password, server_location, shared_secret): print "Sending registration request..." req = urllib2.Request( - "%s/_matrix/client/api/v1/register" % (server_location,), + "%s/_matrix/client/v2_alpha/register" % (server_location,), data=json.dumps(data), headers={'Content-Type': 'application/json'} ) diff --git a/synapse/api/constants.py b/synapse/api/constants.py index 3e0ce170a4..f825c1a58b 100644 --- a/synapse/api/constants.py +++ b/synapse/api/constants.py @@ -60,9 +60,11 @@ class LoginType(object): EMAIL_IDENTITY = u"m.login.email.identity" RECAPTCHA = u"m.login.recaptcha" APPLICATION_SERVICE = u"m.login.application_service" + + # Only for C/S API v1 SHARED_SECRET = u"org.matrix.login.shared_secret" - HIDDEN_TYPES = [APPLICATION_SERVICE, SHARED_SECRET] + HIDDEN_TYPES = [APPLICATION_SERVICE] class EventTypes(object): diff --git a/synapse/rest/client/v2_alpha/register.py b/synapse/rest/client/v2_alpha/register.py index 537918ea27..a69b45f362 100644 --- a/synapse/rest/client/v2_alpha/register.py +++ b/synapse/rest/client/v2_alpha/register.py @@ -22,6 +22,19 @@ from synapse.http.servlet import RestServlet from ._base import client_v2_pattern, parse_request_allow_empty import logging +import hmac +from hashlib import sha1 +from synapse.util.async import run_on_reactor + + +# We ought to be using hmac.compare_digest() but on older pythons it doesn't +# exist. It's a _really minor_ security flaw to use plain string comparison +# because the timing attack is so obscured by all the other code here it's +# unlikely to make much difference +if hasattr(hmac, "compare_digest"): + compare_digest = hmac.compare_digest +else: + compare_digest = lambda a, b: a == b logger = logging.getLogger(__name__) @@ -39,19 +52,30 @@ class RegisterRestServlet(RestServlet): @defer.inlineCallbacks def on_POST(self, request): - body = parse_request_allow_empty(request) + yield run_on_reactor() - authed, result = yield self.auth_handler.check_auth([ - [LoginType.RECAPTCHA], - [LoginType.EMAIL_IDENTITY, LoginType.RECAPTCHA], - [LoginType.APPLICATION_SERVICE] - ], body, self.hs.get_ip_from_request(request)) - - if not authed: - defer.returnValue((401, result)) + body = parse_request_allow_empty(request) - is_application_server = LoginType.APPLICATION_SERVICE in result - is_using_shared_secret = LoginType.SHARED_SECRET in result + is_using_shared_secret = False + is_application_server = False + + if 'mac' in body: + # Check registration-specific shared secret auth + if 'username' not in body: + raise SynapseError(400, "", Codes.MISSING_PARAM) + self._check_shared_secret_auth( + body['username'], body['mac'] + ) + is_using_shared_secret = True + else: + authed, result = yield self.auth_handler.check_auth([ + [LoginType.RECAPTCHA], + [LoginType.EMAIL_IDENTITY, LoginType.RECAPTCHA], + [LoginType.APPLICATION_SERVICE] + ], body, self.hs.get_ip_from_request(request)) + + if not authed: + defer.returnValue((401, result)) can_register = ( not self.hs.config.disable_registration @@ -81,6 +105,29 @@ class RegisterRestServlet(RestServlet): def on_OPTIONS(self, _): return 200, {} + def _check_shared_secret_auth(self, username, mac): + if not self.hs.config.registration_shared_secret: + raise SynapseError(400, "Shared secret registration is not enabled") + + user = username.encode("utf-8") + + # str() because otherwise hmac complains that 'unicode' does not + # have the buffer interface + got_mac = str(mac) + + want_mac = hmac.new( + key=self.hs.config.registration_shared_secret, + msg=user, + digestmod=sha1, + ).hexdigest() + + if compare_digest(want_mac, got_mac): + return True + else: + raise SynapseError( + 403, "HMAC incorrect", + ) + def register_servlets(hs, http_server): RegisterRestServlet(hs).register(http_server) -- cgit 1.4.1 From 4eb6d66b45356efcc87089cb52ca6f51c98cd798 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 2 Apr 2015 17:51:19 +0100 Subject: Add app service auth back in to v2 register --- synapse/api/constants.py | 4 +--- synapse/rest/client/v2_alpha/register.py | 9 +++++++-- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'synapse/api/constants.py') diff --git a/synapse/api/constants.py b/synapse/api/constants.py index f825c1a58b..d29c2dde01 100644 --- a/synapse/api/constants.py +++ b/synapse/api/constants.py @@ -59,13 +59,11 @@ class LoginType(object): EMAIL_URL = u"m.login.email.url" EMAIL_IDENTITY = u"m.login.email.identity" RECAPTCHA = u"m.login.recaptcha" - APPLICATION_SERVICE = u"m.login.application_service" # Only for C/S API v1 + APPLICATION_SERVICE = u"m.login.application_service" SHARED_SECRET = u"org.matrix.login.shared_secret" - HIDDEN_TYPES = [APPLICATION_SERVICE] - class EventTypes(object): Member = "m.room.member" diff --git a/synapse/rest/client/v2_alpha/register.py b/synapse/rest/client/v2_alpha/register.py index a69b45f362..72319a3bb2 100644 --- a/synapse/rest/client/v2_alpha/register.py +++ b/synapse/rest/client/v2_alpha/register.py @@ -59,7 +59,13 @@ class RegisterRestServlet(RestServlet): is_using_shared_secret = False is_application_server = False - if 'mac' in body: + service = None + if 'access_token' in request.args: + service = yield self.auth.get_appservice_by_req(request) + + if service: + is_application_server = True + elif 'mac' in body: # Check registration-specific shared secret auth if 'username' not in body: raise SynapseError(400, "", Codes.MISSING_PARAM) @@ -71,7 +77,6 @@ class RegisterRestServlet(RestServlet): authed, result = yield self.auth_handler.check_auth([ [LoginType.RECAPTCHA], [LoginType.EMAIL_IDENTITY, LoginType.RECAPTCHA], - [LoginType.APPLICATION_SERVICE] ], body, self.hs.get_ip_from_request(request)) if not authed: -- cgit 1.4.1 From 766bd8e88077cbeabffc353d9735a3af190abe61 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 15 Apr 2015 17:14:25 +0100 Subject: Dummy login so we can do the first POST request to get login flows without it just succeeding --- synapse/api/constants.py | 1 + synapse/handlers/auth.py | 6 ++++++ synapse/handlers/identity.py | 6 +++--- synapse/rest/client/v2_alpha/register.py | 18 ++++++++++++++---- 4 files changed, 24 insertions(+), 7 deletions(-) (limited to 'synapse/api/constants.py') diff --git a/synapse/api/constants.py b/synapse/api/constants.py index d29c2dde01..d8a18ee87b 100644 --- a/synapse/api/constants.py +++ b/synapse/api/constants.py @@ -59,6 +59,7 @@ class LoginType(object): EMAIL_URL = u"m.login.email.url" EMAIL_IDENTITY = u"m.login.email.identity" RECAPTCHA = u"m.login.recaptcha" + DUMMY = u"m.login.dummy" # Only for C/S API v1 APPLICATION_SERVICE = u"m.login.application_service" diff --git a/synapse/handlers/auth.py b/synapse/handlers/auth.py index 2cc54707a2..87866f298d 100644 --- a/synapse/handlers/auth.py +++ b/synapse/handlers/auth.py @@ -42,6 +42,7 @@ class AuthHandler(BaseHandler): LoginType.PASSWORD: self._check_password_auth, LoginType.RECAPTCHA: self._check_recaptcha, LoginType.EMAIL_IDENTITY: self._check_email_identity, + LoginType.DUMMY: self._check_dummy_auth, } self.sessions = {} @@ -202,6 +203,11 @@ class AuthHandler(BaseHandler): defer.returnValue(threepid) + @defer.inlineCallbacks + def _check_dummy_auth(self, authdict, _): + yield run_on_reactor() + defer.returnValue(True) + def _get_params_recaptcha(self): return {"public_key": self.hs.config.recaptcha_public_key} diff --git a/synapse/handlers/identity.py b/synapse/handlers/identity.py index 671d366e40..19896ce90d 100644 --- a/synapse/handlers/identity.py +++ b/synapse/handlers/identity.py @@ -42,8 +42,8 @@ class IdentityHandler(BaseHandler): # each request http_client = SimpleHttpClient(self.hs) # XXX: make this configurable! - #trustedIdServers = ['matrix.org', 'localhost:8090'] - trustedIdServers = ['matrix.org'] + trustedIdServers = ['matrix.org', 'localhost:8090'] + #trustedIdServers = ['matrix.org'] if not creds['idServer'] in trustedIdServers: logger.warn('%s is not a trusted ID server: rejecting 3pid ' + 'credentials', creds['idServer']) @@ -52,7 +52,7 @@ class IdentityHandler(BaseHandler): data = {} try: data = yield http_client.get_json( - "https://%s%s" % ( + "http://%s%s" % ( creds['idServer'], "/_matrix/identity/api/v1/3pid/getValidated3pid" ), diff --git a/synapse/rest/client/v2_alpha/register.py b/synapse/rest/client/v2_alpha/register.py index d7a20fc964..ee99b74fd6 100644 --- a/synapse/rest/client/v2_alpha/register.py +++ b/synapse/rest/client/v2_alpha/register.py @@ -63,6 +63,17 @@ class RegisterRestServlet(RestServlet): if 'access_token' in request.args: service = yield self.auth.get_appservice_by_req(request) + if self.hs.config.enable_registration_captcha: + flows = [ + [LoginType.RECAPTCHA], + [LoginType.EMAIL_IDENTITY, LoginType.RECAPTCHA] + ] + else: + flows = [ + [LoginType.DUMMY], + [LoginType.EMAIL_IDENTITY] + ] + if service: is_application_server = True elif 'mac' in body: @@ -74,10 +85,9 @@ class RegisterRestServlet(RestServlet): ) is_using_shared_secret = True else: - authed, result, params = yield self.auth_handler.check_auth([ - [LoginType.RECAPTCHA], - [LoginType.EMAIL_IDENTITY, LoginType.RECAPTCHA], - ], body, self.hs.get_ip_from_request(request)) + authed, result, params = yield self.auth_handler.check_auth( + flows, body, self.hs.get_ip_from_request(request) + ) if not authed: defer.returnValue((401, result)) -- cgit 1.4.1