summary refs log tree commit diff
path: root/synapse/handlers
diff options
context:
space:
mode:
Diffstat (limited to 'synapse/handlers')
-rw-r--r--synapse/handlers/__init__.py2
-rw-r--r--synapse/handlers/auth.py64
-rw-r--r--synapse/handlers/identity.py66
-rw-r--r--synapse/handlers/register.py6
4 files changed, 116 insertions, 22 deletions
diff --git a/synapse/handlers/__init__.py b/synapse/handlers/__init__.py
index 336ce15701..d1b0e032a3 100644
--- a/synapse/handlers/__init__.py
+++ b/synapse/handlers/__init__.py
@@ -30,6 +30,7 @@ from .admin import AdminHandler
 from .appservice import ApplicationServicesHandler
 from .sync import SyncHandler
 from .auth import AuthHandler
+from .identity import IdentityHandler
 
 
 class Handlers(object):
@@ -60,3 +61,4 @@ class Handlers(object):
         )
         self.sync_handler = SyncHandler(hs)
         self.auth_handler = AuthHandler(hs)
+        self.identity_handler = IdentityHandler(hs)
diff --git a/synapse/handlers/auth.py b/synapse/handlers/auth.py
index 3d2461dd7d..2cc54707a2 100644
--- a/synapse/handlers/auth.py
+++ b/synapse/handlers/auth.py
@@ -20,6 +20,7 @@ from synapse.api.constants import LoginType
 from synapse.types import UserID
 from synapse.api.errors import LoginError, Codes
 from synapse.http.client import SimpleHttpClient
+from synapse.util.async import run_on_reactor
 
 from twisted.web.client import PartialDownloadError
 
@@ -40,6 +41,7 @@ class AuthHandler(BaseHandler):
         self.checkers = {
             LoginType.PASSWORD: self._check_password_auth,
             LoginType.RECAPTCHA: self._check_recaptcha,
+            LoginType.EMAIL_IDENTITY: self._check_email_identity,
         }
         self.sessions = {}
 
@@ -54,24 +56,37 @@ class AuthHandler(BaseHandler):
             authdict: The dictionary from the client root level, not the
                       'auth' key: this method prompts for auth if none is sent.
         Returns:
-            A tuple of authed, dict where authed is true if the client
-            has successfully completed an auth flow. If it is true, the dict
-            contains the authenticated credentials of each stage.
-            If authed is false, the dictionary is the server response to the
-            login request and should be passed back to the client.
+            A tuple of authed, dict, dict where authed is true if the client
+            has successfully completed an auth flow. If it is true, the first
+            dict contains the authenticated credentials of each stage.
+
+            If authed is false, the first dictionary is the server response to
+            the login request and should be passed back to the client.
+
+            In either case, the second dict contains the parameters for this
+            request (which may have been given only in a previous call).
         """
 
-        if not clientdict or 'auth' not in clientdict:
-            sess = self._get_session_info(None)
+        authdict = None
+        sid = None
+        if clientdict and 'auth' in clientdict:
+            authdict = clientdict['auth']
+            del clientdict['auth']
+            if 'session' in authdict:
+                sid = authdict['session']
+        sess = self._get_session_info(sid)
+
+        if len(clientdict) > 0:
+            sess['clientdict'] = clientdict
+            self._save_session(sess)
+        elif 'clientdict' in sess:
+            clientdict = sess['clientdict']
+
+        if not authdict:
             defer.returnValue(
-                (False, self._auth_dict_for_flows(flows, sess))
+                (False, self._auth_dict_for_flows(flows, sess), clientdict)
             )
 
-        authdict = clientdict['auth']
-
-        sess = self._get_session_info(
-            authdict['session'] if 'session' in authdict else None
-        )
         if 'creds' not in sess:
             sess['creds'] = {}
         creds = sess['creds']
@@ -89,11 +104,11 @@ class AuthHandler(BaseHandler):
             if len(set(f) - set(creds.keys())) == 0:
                 logger.info("Auth completed with creds: %r", creds)
                 self._remove_session(sess)
-                defer.returnValue((True, creds))
+                defer.returnValue((True, creds, clientdict))
 
         ret = self._auth_dict_for_flows(flows, sess)
         ret['completed'] = creds.keys()
-        defer.returnValue((False, ret))
+        defer.returnValue((False, ret, clientdict))
 
     @defer.inlineCallbacks
     def add_oob_auth(self, stagetype, authdict, clientip):
@@ -175,18 +190,25 @@ class AuthHandler(BaseHandler):
             defer.returnValue(True)
         raise LoginError(401, "", errcode=Codes.UNAUTHORIZED)
 
+    @defer.inlineCallbacks
+    def _check_email_identity(self, authdict, _):
+        yield run_on_reactor()
+
+        threepidCreds = authdict['threepidCreds']
+        identity_handler = self.hs.get_handlers().identity_handler
+
+        logger.debug("Getting validated threepid. threepidcreds: %r" % (threepidCreds,))
+        threepid = yield identity_handler.threepid_from_creds(threepidCreds)
+
+        defer.returnValue(threepid)
+
     def _get_params_recaptcha(self):
         return {"public_key": self.hs.config.recaptcha_public_key}
 
     def _auth_dict_for_flows(self, flows, session):
         public_flows = []
         for f in flows:
-            hidden = False
-            for stagetype in f:
-                if stagetype in LoginType.HIDDEN_TYPES:
-                    hidden = True
-            if not hidden:
-                public_flows.append(f)
+            public_flows.append(f)
 
         get_params = {
             LoginType.RECAPTCHA: self._get_params_recaptcha,
diff --git a/synapse/handlers/identity.py b/synapse/handlers/identity.py
new file mode 100644
index 0000000000..671d366e40
--- /dev/null
+++ b/synapse/handlers/identity.py
@@ -0,0 +1,66 @@
+# -*- coding: utf-8 -*-
+# Copyright 2015 OpenMarket Ltd
+#
+# 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.
+
+"""Utilities for interacting with Identity Servers"""
+from twisted.internet import defer
+
+from synapse.api.errors import (
+    CodeMessageException
+)
+from ._base import BaseHandler
+from synapse.http.client import SimpleHttpClient
+from synapse.util.async import run_on_reactor
+
+import json
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+class IdentityHandler(BaseHandler):
+
+    def __init__(self, hs):
+        super(IdentityHandler, self).__init__(hs)
+
+    @defer.inlineCallbacks
+    def threepid_from_creds(self, creds):
+        yield run_on_reactor()
+
+        # TODO: get this from the homeserver rather than creating a new one for
+        # each request
+        http_client = SimpleHttpClient(self.hs)
+        # XXX: make this configurable!
+        #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'])
+            defer.returnValue(None)
+
+        data = {}
+        try:
+            data = yield http_client.get_json(
+                "https://%s%s" % (
+                    creds['idServer'],
+                    "/_matrix/identity/api/v1/3pid/getValidated3pid"
+                ),
+                {'sid': creds['sid'], 'clientSecret': creds['clientSecret']}
+            )
+        except CodeMessageException as e:
+            data = json.loads(e.msg)
+
+        if 'medium' in data:
+            defer.returnValue(data)
+        defer.returnValue(None)
\ No newline at end of file
diff --git a/synapse/handlers/register.py b/synapse/handlers/register.py
index 542759a827..6759a8c582 100644
--- a/synapse/handlers/register.py
+++ b/synapse/handlers/register.py
@@ -180,7 +180,11 @@ class RegistrationHandler(BaseHandler):
 
     @defer.inlineCallbacks
     def register_email(self, threepidCreds):
-        """Registers emails with an identity server."""
+        """
+        Registers emails with an identity server.
+
+        Used only by c/s api v1
+        """
 
         for c in threepidCreds:
             logger.info("validating theeepidcred sid %s on id server %s",