Mercurial > libervia-pubsub
comparison 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 |
comparison
equal
deleted
inserted
replaced
459:cebcb7f56889 | 460:607616f9ef5b |
---|---|
53 class DelegationsHandler(XMPPHandler): | 53 class DelegationsHandler(XMPPHandler): |
54 _service_hacked = False | 54 _service_hacked = False |
55 | 55 |
56 def __init__(self): | 56 def __init__(self): |
57 super(DelegationsHandler, self).__init__() | 57 super(DelegationsHandler, self).__init__() |
58 self.backend = None | |
58 | 59 |
59 def _service_hack(self): | 60 def _service_hack(self): |
60 """Patch the request classes of services to track delegated stanzas""" | 61 """Patch the request classes of services to track delegated stanzas""" |
61 # XXX: we need to monkey patch to track origin of the stanza in PubSubRequest. | 62 # XXX: we need to monkey patch to track origin of the stanza in PubSubRequest. |
62 # As PubSubRequest from sat.tmp.wokkel.pubsub use _request_class while | 63 # As PubSubRequest from sat.tmp.wokkel.pubsub use _request_class while |
100 setattr(module, default_base_cls, RequestWithDelegation) | 101 setattr(module, default_base_cls, RequestWithDelegation) |
101 module_patched = True | 102 module_patched = True |
102 DelegationsHandler._service_hacked = True | 103 DelegationsHandler._service_hacked = True |
103 | 104 |
104 def connectionInitialized(self): | 105 def connectionInitialized(self): |
106 self.backend = self.parent.parent.getServiceNamed('backend') | |
105 if not self._service_hacked: | 107 if not self._service_hacked: |
106 self._service_hack() | 108 self._service_hack() |
107 self.xmlstream.addObserver(DELEGATION_ADV_XPATH, self.onAdvertise) | 109 self.xmlstream.addObserver(DELEGATION_ADV_XPATH, self.onAdvertise) |
108 self.xmlstream.addObserver(DELEGATION_FWD_XPATH, self._obsWrapper, 0, self.onForward) | 110 self.xmlstream.addObserver(DELEGATION_FWD_XPATH, self._obsWrapper, 0, self.onForward) |
109 self._current_iqs = {} # dict of iq being handler by delegation | 111 self._current_iqs = {} # dict of iq being handler by delegation |
148 self._xs_send(error_elt) | 150 self._xs_send(error_elt) |
149 stanza.handled = True | 151 stanza.handled = True |
150 | 152 |
151 def onAdvertise(self, message): | 153 def onAdvertise(self, message): |
152 """Manage the <message/> advertising delegations""" | 154 """Manage the <message/> advertising delegations""" |
155 if self.backend.config["server_jid"] is None: | |
156 # if server_jid is not specified in config, we use the advertising message | |
157 # to get it (and replace the one found from this component jid) | |
158 self.backend.server_jid = self.backend.config["server_jid"] = jid.JID( | |
159 message["from"] | |
160 ) | |
161 else: | |
162 if jid.JID(message["from"]) != self.backend.server_jid: | |
163 log.err( | |
164 f"Delagation advertising message received from {message['from']}, " | |
165 f"while expected server jid is {self.backend.server_jid}, this may " | |
166 "be a security threat, please check your configuration and network." | |
167 ) | |
168 raise error.StanzaError("not-allowed") | |
153 delegation_elt = next(message.elements(DELEGATION_NS, 'delegation')) | 169 delegation_elt = next(message.elements(DELEGATION_NS, 'delegation')) |
154 delegated = {} | 170 delegated = {} |
155 for delegated_elt in delegation_elt.elements(DELEGATION_NS): | 171 for delegated_elt in delegation_elt.elements(DELEGATION_NS): |
156 try: | 172 try: |
157 if delegated_elt.name != 'delegated': | 173 if delegated_elt.name != 'delegated': |
180 def onForward(self, iq): | 196 def onForward(self, iq): |
181 """Manage forwarded iq | 197 """Manage forwarded iq |
182 | 198 |
183 @param iq(domish.Element): full delegation stanza | 199 @param iq(domish.Element): full delegation stanza |
184 """ | 200 """ |
185 | 201 if jid.JID(iq['from']) != self.backend.server_jid: |
186 # FIXME: we use a hack supposing that our delegation come from hostname | 202 log.err("SECURITY WARNING: forwarded stanza doesn't come from our server: " |
187 # and we are a component named [name].hostname | 203 f"{iq.toXml()}") |
188 # but we need to manage properly allowed servers | |
189 # TODO: do proper origin security check | |
190 _, allowed = iq['to'].split('.', 1) | |
191 if jid.JID(iq['from']) != jid.JID(allowed): | |
192 log.msg(("SECURITY WARNING: forwarded stanza doesn't come from our server: {}" | |
193 .format(iq.toXml())).encode('utf-8')) | |
194 raise error.StanzaError('not-allowed') | 204 raise error.StanzaError('not-allowed') |
195 | 205 |
196 try: | 206 try: |
197 delegation_elt = next(iq.elements(DELEGATION_NS, 'delegation')) | 207 delegation_elt = next(iq.elements(DELEGATION_NS, 'delegation')) |
198 forwarded_elt = next(delegation_elt.elements(FORWARDED_NS, 'forwarded')) | 208 forwarded_elt = next(delegation_elt.elements(FORWARDED_NS, 'forwarded')) |
222 | 232 |
223 The same features/identities are returned for main and bare nodes | 233 The same features/identities are returned for main and bare nodes |
224 """ | 234 """ |
225 if not nodeIdentifier.startswith(DELEGATION_NS): | 235 if not nodeIdentifier.startswith(DELEGATION_NS): |
226 return [] | 236 return [] |
227 | |
228 try: | 237 try: |
229 _, namespace = nodeIdentifier.split(DELEGATION_MAIN_SEP, 1) | 238 _, namespace = nodeIdentifier.split(DELEGATION_MAIN_SEP, 1) |
230 except ValueError: | 239 except ValueError: |
231 try: | 240 try: |
232 _, namespace = nodeIdentifier.split(DELEGATION_BARE_SEP, 1) | 241 _, namespace = nodeIdentifier.split(DELEGATION_BARE_SEP, 1) |