summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--synapse/handlers/identity.py23
-rw-r--r--synapse/handlers/room.py4
-rw-r--r--synapse/handlers/room_member.py91
-rw-r--r--synapse/rest/client/v1/room.py1
4 files changed, 102 insertions, 17 deletions
diff --git a/synapse/handlers/identity.py b/synapse/handlers/identity.py
index 622597c863..d081f88fc5 100644
--- a/synapse/handlers/identity.py
+++ b/synapse/handlers/identity.py
@@ -289,7 +289,7 @@ class IdentityHandler(BaseHandler):
             raise e.to_synapse_error()
 
     @defer.inlineCallbacks
-    def lookup_3pid(self, id_server, medium, address):
+    def lookup_3pid(self, id_server, medium, address, id_access_token=None):
         """Looks up a 3pid in the passed identity server.
 
         Args:
@@ -297,16 +297,23 @@ class IdentityHandler(BaseHandler):
                 of the identity server to use.
             medium (str): The type of the third party identifier (e.g. "email").
             address (str): The third party identifier (e.g. "foo@example.com").
+            id_access_token (str|None): The access token to authenticate to the identity
+                server with
 
         Returns:
             str: the matrix ID of the 3pid, or None if it is not recognized.
         """
+        # If an access token is present, add it to the query params of the hash_details request
+        query_params = {}
+        if id_access_token is not None:
+            query_params["id_access_token"] = id_access_token
+
         # Check what hashing details are supported by this identity server
         use_v1 = False
         hash_details = None
         try:
             hash_details = yield self.http_client.get_json(
-                "%s/_matrix/identity/v2/hash_details" % id_server
+                "%s/_matrix/identity/v2/hash_details" % id_server, query_params
             )
         except (HttpResponseException, ValueError) as e:
             # Catch HttpResponseExcept for a non-200 response code
@@ -323,7 +330,11 @@ class IdentityHandler(BaseHandler):
         if use_v1:
             return (yield self._lookup_3pid_v1(id_server, medium, address))
 
-        return (yield self._lookup_3pid_v2(id_server, medium, address, hash_details))
+        return (
+            yield self._lookup_3pid_v2(
+                id_server, id_access_token, medium, address, hash_details
+            )
+        )
 
     @defer.inlineCallbacks
     def _lookup_3pid_v1(self, id_server, medium, address):
@@ -356,12 +367,15 @@ class IdentityHandler(BaseHandler):
         return None
 
     @defer.inlineCallbacks
-    def _lookup_3pid_v2(self, id_server, medium, address, hash_details):
+    def _lookup_3pid_v2(
+        self, id_server, id_access_token, medium, address, hash_details
+    ):
         """Looks up a 3pid in the passed identity server using v2 lookup.
 
         Args:
             id_server (str): The server name (including protocol and port, if required)
                 of the identity server to use.
+            id_access_token (str): The access token to authenticate to the identity server with
             medium (str): The type of the third party identifier (e.g. "email").
             address (str): The third party identifier (e.g. "foo@example.com").
             hash_details (dict[str, str|list]): A dictionary containing hashing information
@@ -406,6 +420,7 @@ class IdentityHandler(BaseHandler):
             lookup_results = yield self.http_client.post_json_get_json(
                 "%s/_matrix/identity/v2/lookup" % id_server,
                 {
+                    "id_access_token": id_access_token,
                     "addresses": [lookup_value],
                     "algorithm": lookup_algorithm,
                     "pepper": lookup_pepper,
diff --git a/synapse/handlers/room.py b/synapse/handlers/room.py
index a509e11d69..970be3c846 100644
--- a/synapse/handlers/room.py
+++ b/synapse/handlers/room.py
@@ -579,8 +579,8 @@ class RoomCreationHandler(BaseHandler):
 
         room_id = yield self._generate_room_id(creator_id=user_id, is_public=is_public)
 
+        directory_handler = self.hs.get_handlers().directory_handler
         if room_alias:
-            directory_handler = self.hs.get_handlers().directory_handler
             yield directory_handler.create_association(
                 requester=requester,
                 room_id=room_id,
@@ -665,6 +665,7 @@ class RoomCreationHandler(BaseHandler):
 
         for invite_3pid in invite_3pid_list:
             id_server = invite_3pid["id_server"]
+            id_access_token = invite_3pid.get("id_access_token")  # optional
             address = invite_3pid["address"]
             medium = invite_3pid["medium"]
             yield self.hs.get_room_member_handler().do_3pid_invite(
@@ -675,6 +676,7 @@ class RoomCreationHandler(BaseHandler):
                 id_server,
                 requester,
                 txn_id=None,
+                id_access_token=id_access_token,
             )
 
         result = {"room_id": room_id}
diff --git a/synapse/handlers/room_member.py b/synapse/handlers/room_member.py
index 3883bcdc97..3160e5fda1 100644
--- a/synapse/handlers/room_member.py
+++ b/synapse/handlers/room_member.py
@@ -643,7 +643,15 @@ class RoomMemberHandler(object):
 
     @defer.inlineCallbacks
     def do_3pid_invite(
-        self, room_id, inviter, medium, address, id_server, requester, txn_id
+        self,
+        room_id,
+        inviter,
+        medium,
+        address,
+        id_server,
+        requester,
+        txn_id,
+        id_access_token=None,
     ):
         if self.config.block_non_admin_invites:
             is_requester_admin = yield self.auth.is_server_admin(requester.user)
@@ -673,7 +681,7 @@ class RoomMemberHandler(object):
 
         id_server_url = id_server_scheme + id_server
         invitee = yield self.identity_handler.lookup_3pid(
-            id_server_url, medium, address
+            id_server_url, medium, address, id_access_token
         )
 
         if invitee:
@@ -682,12 +690,27 @@ class RoomMemberHandler(object):
             )
         else:
             yield self._make_and_store_3pid_invite(
-                requester, id_server, medium, address, room_id, inviter, txn_id=txn_id
+                requester,
+                id_server,
+                medium,
+                address,
+                room_id,
+                inviter,
+                txn_id=txn_id,
+                id_access_token=id_access_token,
             )
 
     @defer.inlineCallbacks
     def _make_and_store_3pid_invite(
-        self, requester, id_server, medium, address, room_id, user, txn_id
+        self,
+        requester,
+        id_server,
+        medium,
+        address,
+        room_id,
+        user,
+        txn_id,
+        id_access_token=None,
     ):
         room_state = yield self.state_handler.get_current_state(room_id)
 
@@ -736,6 +759,7 @@ class RoomMemberHandler(object):
                 room_name=room_name,
                 inviter_display_name=inviter_display_name,
                 inviter_avatar_url=inviter_avatar_url,
+                id_access_token=id_access_token,
             )
         )
 
@@ -773,6 +797,7 @@ class RoomMemberHandler(object):
         room_name,
         inviter_display_name,
         inviter_avatar_url,
+        id_access_token=None,
     ):
         """
         Asks an identity server for a third party invite.
@@ -792,6 +817,8 @@ class RoomMemberHandler(object):
             inviter_display_name (str): The current display name of the
                 inviter.
             inviter_avatar_url (str): The URL of the inviter's avatar.
+            id_access_token (str|None): The access token to authenticate to the identity
+                server with
 
         Returns:
             A deferred tuple containing:
@@ -802,12 +829,6 @@ class RoomMemberHandler(object):
                 display_name (str): A user-friendly name to represent the invited
                     user.
         """
-
-        is_url = "%s%s/_matrix/identity/api/v1/store-invite" % (
-            id_server_scheme,
-            id_server,
-        )
-
         invite_config = {
             "medium": medium,
             "address": address,
@@ -821,11 +842,39 @@ class RoomMemberHandler(object):
             "sender_avatar_url": inviter_avatar_url,
         }
 
+        # Add the identity service access token to the JSON body and use the v2
+        # Identity Service endpoints if id_access_token is present
+        if id_access_token:
+            invite_config["id_access_token"] = id_access_token
+            is_url = "%s%s/_matrix/identity/v2/store-invite" % (
+                id_server_scheme,
+                id_server,
+            )
+            key_validity_url = "%s%s/_matrix/identity/v2/pubkey/isvalid" % (
+                id_server_scheme,
+                id_server,
+            )
+        else:
+            is_url = "%s%s/_matrix/identity/api/v1/store-invite" % (
+                id_server_scheme,
+                id_server,
+            )
+            key_validity_url = "%s%s/_matrix/identity/api/v1/pubkey/isvalid" % (
+                id_server_scheme,
+                id_server,
+            )
+
+        fallback_to_v1 = False
         try:
             data = yield self.simple_http_client.post_json_get_json(
                 is_url, invite_config
             )
         except HttpResponseException as e:
+            if id_access_token and e.code == 404:
+                # This identity server does not support v2 endpoints
+                # Fallback to v1 endpoints
+                fallback_to_v1 = True
+
             # Some identity servers may only support application/x-www-form-urlencoded
             # types. This is especially true with old instances of Sydent, see
             # https://github.com/matrix-org/sydent/pull/170
@@ -838,14 +887,32 @@ class RoomMemberHandler(object):
                 is_url, invite_config
             )
 
+        if fallback_to_v1:
+            return (
+                yield self._ask_id_server_for_third_party_invite(
+                    requester,
+                    id_server,
+                    medium,
+                    address,
+                    room_id,
+                    inviter_user_id,
+                    room_alias,
+                    room_avatar_url,
+                    room_join_rules,
+                    room_name,
+                    inviter_display_name,
+                    inviter_avatar_url,
+                    id_access_token=None,  # force using v1 endpoints
+                )
+            )
+
         # TODO: Check for success
         token = data["token"]
         public_keys = data.get("public_keys", [])
         if "public_key" in data:
             fallback_public_key = {
                 "public_key": data["public_key"],
-                "key_validity_url": "%s%s/_matrix/identity/api/v1/pubkey/isvalid"
-                % (id_server_scheme, id_server),
+                "key_validity_url": key_validity_url,
             }
         else:
             fallback_public_key = public_keys[0]
diff --git a/synapse/rest/client/v1/room.py b/synapse/rest/client/v1/room.py
index 3582259026..a6a7b3b57e 100644
--- a/synapse/rest/client/v1/room.py
+++ b/synapse/rest/client/v1/room.py
@@ -701,6 +701,7 @@ class RoomMembershipRestServlet(TransactionRestServlet):
                 content["id_server"],
                 requester,
                 txn_id,
+                content.get("id_access_token"),
             )
             return 200, {}