def process(server_name, json_object): """Process an entry in the request list Given a (server_name, json_object) pair from the request list, adds a key request to verify_requests, and returns a deferred which will complete or fail (in the sentinel context) when verification completes. """ key_ids = signature_ids(json_object, server_name) if not key_ids: return defer.fail( SynapseError( 400, "Not signed by %s" % (server_name, ), Codes.UNAUTHORIZED, )) logger.debug("Verifying for %s with key_ids %s", server_name, key_ids) # add the key request to the queue, but don't start it off yet. verify_request = VerifyKeyRequest( server_name, key_ids, json_object, defer.Deferred(), ) verify_requests.append(verify_request) # now run _handle_key_deferred, which will wait for the key request # to complete and then do the verification. # # We want _handle_key_request to log to the right context, so we # wrap it with preserve_fn (aka run_in_background) return handle(verify_request)
def process(server_name, json_object): """Process an entry in the request list Given a (server_name, json_object) pair from the request list, adds a key request to verify_requests, and returns a deferred which will complete or fail (in the sentinel context) when verification completes. """ key_ids = signature_ids(json_object, server_name) if not key_ids: return defer.fail( SynapseError( 400, "Not signed by %s" % (server_name,), Codes.UNAUTHORIZED, ) ) logger.debug("Verifying for %s with key_ids %s", server_name, key_ids) # add the key request to the queue, but don't start it off yet. verify_request = VerifyKeyRequest( server_name, key_ids, json_object, defer.Deferred(), ) verify_requests.append(verify_request) # now run _handle_key_deferred, which will wait for the key request # to complete and then do the verification. # # We want _handle_key_request to log to the right context, so we # wrap it with preserve_fn (aka run_in_background) return handle(verify_request)
def from_json_object( server_name: str, json_object: JsonDict, minimum_valid_until_ms: int, ) -> "VerifyJsonRequest": """Create a VerifyJsonRequest to verify all signatures on a signed JSON object for the given server. """ key_ids = signature_ids(json_object, server_name) return VerifyJsonRequest( server_name, lambda: json_object, minimum_valid_until_ms, key_ids=key_ids, )
def verify_json_objects_for_server(self, server_and_json): """Bulk verifies signatures of json objects, bulk fetching keys as necessary. Args: server_and_json (list): List of pairs of (server_name, json_object) Returns: List<Deferred>: for each input pair, a deferred indicating success or failure to verify each json object's signature for the given server_name. The deferreds run their callbacks in the sentinel logcontext. """ verify_requests = [] for server_name, json_object in server_and_json: key_ids = signature_ids(json_object, server_name) if not key_ids: logger.warn("Request from %s: no supported signature keys", server_name) deferred = defer.fail(SynapseError( 400, "Not signed with a supported algorithm", Codes.UNAUTHORIZED, )) else: deferred = defer.Deferred() logger.debug("Verifying for %s with key_ids %s", server_name, key_ids) verify_request = VerifyKeyRequest( server_name, key_ids, json_object, deferred ) verify_requests.append(verify_request) run_in_background(self._start_key_lookups, verify_requests) # Pass those keys to handle_key_deferred so that the json object # signatures can be verified handle = preserve_fn(_handle_key_deferred) return [ handle(rq) for rq in verify_requests ]
def test_signature_ids(self): key_ids = signature_ids( self.signed, 'Alice', supported_algorithms=['mock'] ) self.assertListEqual(key_ids, ['mock:test'])
def verify_json_objects_for_server(self, server_and_json): """Bulk verfies signatures of json objects, bulk fetching keys as necessary. Args: server_and_json (list): List of pairs of (server_name, json_object) Returns: list of deferreds indicating success or failure to verify each json object's signature for the given server_name. """ group_id_to_json = {} group_id_to_group = {} group_ids = [] next_group_id = 0 deferreds = {} for server_name, json_object in server_and_json: logger.debug("Verifying for %s", server_name) group_id = next_group_id next_group_id += 1 group_ids.append(group_id) key_ids = signature_ids(json_object, server_name) if not key_ids: deferreds[group_id] = defer.fail( SynapseError( 400, "Not signed with a supported algorithm", Codes.UNAUTHORIZED, )) else: deferreds[group_id] = defer.Deferred() group = KeyGroup(server_name, group_id, key_ids) group_id_to_group[group_id] = group group_id_to_json[group_id] = json_object @defer.inlineCallbacks def handle_key_deferred(group, deferred): server_name = group.server_name try: _, _, key_id, verify_key = yield deferred except IOError as e: logger.warn( "Got IOError when downloading keys for %s: %s %s", server_name, type(e).__name__, str(e.message), ) raise SynapseError( 502, "Error downloading keys for %s" % (server_name, ), Codes.UNAUTHORIZED, ) except Exception as e: logger.exception( "Got Exception when downloading keys for %s: %s %s", server_name, type(e).__name__, str(e.message), ) raise SynapseError( 401, "No key for %s with id %s" % (server_name, key_ids), Codes.UNAUTHORIZED, ) json_object = group_id_to_json[group.group_id] try: verify_signed_json(json_object, server_name, verify_key) except: raise SynapseError( 401, "Invalid signature for server %s with key %s:%s" % (server_name, verify_key.alg, verify_key.version), Codes.UNAUTHORIZED, ) server_to_deferred = { server_name: defer.Deferred() for server_name, _ in server_and_json } # We want to wait for any previous lookups to complete before # proceeding. wait_on_deferred = self.wait_for_previous_lookups( [server_name for server_name, _ in server_and_json], server_to_deferred, ) # Actually start fetching keys. wait_on_deferred.addBoth(lambda _: self.get_server_verify_keys( group_id_to_group, deferreds)) # When we've finished fetching all the keys for a given server_name, # resolve the deferred passed to `wait_for_previous_lookups` so that # any lookups waiting will proceed. server_to_gids = {} def remove_deferreds(res, server_name, group_id): server_to_gids[server_name].discard(group_id) if not server_to_gids[server_name]: d = server_to_deferred.pop(server_name, None) if d: d.callback(None) return res for g_id, deferred in deferreds.items(): server_name = group_id_to_group[g_id].server_name server_to_gids.setdefault(server_name, set()).add(g_id) deferred.addBoth(remove_deferreds, server_name, g_id) # Pass those keys to handle_key_deferred so that the json object # signatures can be verified return [ handle_key_deferred( group_id_to_group[g_id], deferreds[g_id], ) for g_id in group_ids ]
def __attrs_post_init__(self): self.key_ids = signature_ids(self.json_object, self.server_name)
def test_signature_ids(self): key_ids = signature_ids(self.signed, 'Alice', supported_algorithms=['mock']) self.assertListEqual(key_ids, ['mock:test'])
def verify_json_objects_for_server(self, server_and_json): """Bulk verfies signatures of json objects, bulk fetching keys as necessary. Args: server_and_json (list): List of pairs of (server_name, json_object) Returns: list of deferreds indicating success or failure to verify each json object's signature for the given server_name. """ verify_requests = [] for server_name, json_object in server_and_json: logger.debug("Verifying for %s", server_name) key_ids = signature_ids(json_object, server_name) if not key_ids: deferred = defer.fail(SynapseError( 400, "Not signed with a supported algorithm", Codes.UNAUTHORIZED, )) else: deferred = defer.Deferred() verify_request = VerifyKeyRequest( server_name, key_ids, json_object, deferred ) verify_requests.append(verify_request) @defer.inlineCallbacks def handle_key_deferred(verify_request): server_name = verify_request.server_name try: _, key_id, verify_key = yield verify_request.deferred except IOError as e: logger.warn( "Got IOError when downloading keys for %s: %s %s", server_name, type(e).__name__, str(e.message), ) raise SynapseError( 502, "Error downloading keys for %s" % (server_name,), Codes.UNAUTHORIZED, ) except Exception as e: logger.exception( "Got Exception when downloading keys for %s: %s %s", server_name, type(e).__name__, str(e.message), ) raise SynapseError( 401, "No key for %s with id %s" % (server_name, key_ids), Codes.UNAUTHORIZED, ) json_object = verify_request.json_object try: verify_signed_json(json_object, server_name, verify_key) except: raise SynapseError( 401, "Invalid signature for server %s with key %s:%s" % ( server_name, verify_key.alg, verify_key.version ), Codes.UNAUTHORIZED, ) server_to_deferred = { server_name: defer.Deferred() for server_name, _ in server_and_json } with PreserveLoggingContext(): # We want to wait for any previous lookups to complete before # proceeding. wait_on_deferred = self.wait_for_previous_lookups( [server_name for server_name, _ in server_and_json], server_to_deferred, ) # Actually start fetching keys. wait_on_deferred.addBoth( lambda _: self.get_server_verify_keys(verify_requests) ) # When we've finished fetching all the keys for a given server_name, # resolve the deferred passed to `wait_for_previous_lookups` so that # any lookups waiting will proceed. server_to_request_ids = {} def remove_deferreds(res, server_name, verify_request): request_id = id(verify_request) server_to_request_ids[server_name].discard(request_id) if not server_to_request_ids[server_name]: d = server_to_deferred.pop(server_name, None) if d: d.callback(None) return res for verify_request in verify_requests: server_name = verify_request.server_name request_id = id(verify_request) server_to_request_ids.setdefault(server_name, set()).add(request_id) deferred.addBoth(remove_deferreds, server_name, verify_request) # Pass those keys to handle_key_deferred so that the json object # signatures can be verified return [ preserve_context_over_fn(handle_key_deferred, verify_request) for verify_request in verify_requests ]
def verify_json_objects_for_server(self, server_and_json): """Bulk verfies signatures of json objects, bulk fetching keys as necessary. Args: server_and_json (list): List of pairs of (server_name, json_object) Returns: list of deferreds indicating success or failure to verify each json object's signature for the given server_name. """ verify_requests = [] for server_name, json_object in server_and_json: key_ids = signature_ids(json_object, server_name) if not key_ids: logger.warn("Request from %s: no supported signature keys", server_name) deferred = defer.fail(SynapseError( 400, "Not signed with a supported algorithm", Codes.UNAUTHORIZED, )) else: deferred = defer.Deferred() logger.debug("Verifying for %s with key_ids %s", server_name, key_ids) verify_request = VerifyKeyRequest( server_name, key_ids, json_object, deferred ) verify_requests.append(verify_request) @defer.inlineCallbacks def handle_key_deferred(verify_request): server_name = verify_request.server_name try: _, key_id, verify_key = yield verify_request.deferred except IOError as e: logger.warn( "Got IOError when downloading keys for %s: %s %s", server_name, type(e).__name__, str(e.message), ) raise SynapseError( 502, "Error downloading keys for %s" % (server_name,), Codes.UNAUTHORIZED, ) except Exception as e: logger.exception( "Got Exception when downloading keys for %s: %s %s", server_name, type(e).__name__, str(e.message), ) raise SynapseError( 401, "No key for %s with id %s" % (server_name, key_ids), Codes.UNAUTHORIZED, ) json_object = verify_request.json_object logger.debug("Got key %s %s:%s for server %s, verifying" % ( key_id, verify_key.alg, verify_key.version, server_name, )) try: verify_signed_json(json_object, server_name, verify_key) except: raise SynapseError( 401, "Invalid signature for server %s with key %s:%s" % ( server_name, verify_key.alg, verify_key.version ), Codes.UNAUTHORIZED, ) server_to_deferred = { server_name: defer.Deferred() for server_name, _ in server_and_json } with PreserveLoggingContext(): # We want to wait for any previous lookups to complete before # proceeding. wait_on_deferred = self.wait_for_previous_lookups( [server_name for server_name, _ in server_and_json], server_to_deferred, ) # Actually start fetching keys. wait_on_deferred.addBoth( lambda _: self.get_server_verify_keys(verify_requests) ) # When we've finished fetching all the keys for a given server_name, # resolve the deferred passed to `wait_for_previous_lookups` so that # any lookups waiting will proceed. server_to_request_ids = {} def remove_deferreds(res, server_name, verify_request): request_id = id(verify_request) server_to_request_ids[server_name].discard(request_id) if not server_to_request_ids[server_name]: d = server_to_deferred.pop(server_name, None) if d: d.callback(None) return res for verify_request in verify_requests: server_name = verify_request.server_name request_id = id(verify_request) server_to_request_ids.setdefault(server_name, set()).add(request_id) deferred.addBoth(remove_deferreds, server_name, verify_request) # Pass those keys to handle_key_deferred so that the json object # signatures can be verified return [ preserve_context_over_fn(handle_key_deferred, verify_request) for verify_request in verify_requests ]