diff sat_pubsub/delegation.py @ 460:607616f9ef5b

backend: new `server_jid` option: Server domain must be known to validate requests, this can be done explicitely by using the `server_jid` option. If this option is not set, the server domain is found: - by using the `from` name of the initial delegation advertising message - or it fallbacks to using the part after initial `.` (`pubsub.example.org` would give `example.org`)
author Goffi <goffi@goffi.org>
date Fri, 15 Oct 2021 09:32:07 +0200
parents cebcb7f56889
children b544109ab4c4
line wrap: on
line diff
--- a/sat_pubsub/delegation.py	Fri Oct 15 09:32:04 2021 +0200
+++ b/sat_pubsub/delegation.py	Fri Oct 15 09:32:07 2021 +0200
@@ -55,6 +55,7 @@
 
     def __init__(self):
         super(DelegationsHandler, self).__init__()
+        self.backend = None
 
     def _service_hack(self):
         """Patch the request classes of services to track delegated stanzas"""
@@ -102,6 +103,7 @@
         DelegationsHandler._service_hacked = True
 
     def connectionInitialized(self):
+        self.backend = self.parent.parent.getServiceNamed('backend')
         if not self._service_hacked:
             self._service_hack()
         self.xmlstream.addObserver(DELEGATION_ADV_XPATH, self.onAdvertise)
@@ -150,6 +152,20 @@
 
     def onAdvertise(self, message):
         """Manage the <message/> advertising delegations"""
+        if self.backend.config["server_jid"] is None:
+            # if server_jid is not specified in config, we use the advertising message
+            # to get it (and replace the one found from this component jid)
+            self.backend.server_jid = self.backend.config["server_jid"] = jid.JID(
+                message["from"]
+            )
+        else:
+            if jid.JID(message["from"]) != self.backend.server_jid:
+                log.err(
+                    f"Delagation advertising message received from {message['from']}, "
+                    f"while expected server jid is {self.backend.server_jid}, this may "
+                    "be a security threat, please check your configuration and network."
+                )
+                raise error.StanzaError("not-allowed")
         delegation_elt = next(message.elements(DELEGATION_NS, 'delegation'))
         delegated = {}
         for delegated_elt in delegation_elt.elements(DELEGATION_NS):
@@ -182,15 +198,9 @@
 
         @param iq(domish.Element): full delegation stanza
         """
-
-        # FIXME: we use a hack supposing that our delegation come from hostname
-        #        and we are a component named [name].hostname
-        #        but we need to manage properly allowed servers
-        # TODO: do proper origin security check
-        _, allowed = iq['to'].split('.', 1)
-        if jid.JID(iq['from']) != jid.JID(allowed):
-            log.msg(("SECURITY WARNING: forwarded stanza doesn't come from our server: {}"
-                     .format(iq.toXml())).encode('utf-8'))
+        if jid.JID(iq['from']) != self.backend.server_jid:
+            log.err("SECURITY WARNING: forwarded stanza doesn't come from our server: "
+                    f"{iq.toXml()}")
             raise error.StanzaError('not-allowed')
 
         try:
@@ -224,7 +234,6 @@
         """
         if not nodeIdentifier.startswith(DELEGATION_NS):
             return []
-
         try:
             _, namespace = nodeIdentifier.split(DELEGATION_MAIN_SEP, 1)
         except ValueError: