def onVerify(self, verify): try: receivingServer = jid.JID(verify['from']).host originatingServer = jid.JID(verify['to']).host except (KeyError, jid.InvalidFormat): raise error.StreamError('improper-addressing') if originatingServer not in self.service.domains: raise error.StreamError('host-unknown') if (self.xmlstream.otherEntity and receivingServer != self.xmlstream.otherEntity.host): raise error.StreamError('invalid-from') streamID = verify.getAttribute('id', '') key = unicode(verify) calculatedKey = generateKey(self.service.secret, receivingServer, originatingServer, streamID) validity = (key == calculatedKey) and 'valid' or 'invalid' reply = domish.Element((NS_DIALBACK, 'verify')) reply['from'] = originatingServer reply['to'] = receivingServer reply['id'] = streamID reply['type'] = validity self.xmlstream.send(reply)
def streamStarted(self, rootElement): """ Called by the stream when it has started. This examines the default namespace of the incoming stream and whether there is a requested hostname for the component. Then it generates a stream identifier, sends a response header and adds an observer for the first incoming element, triggering L{onElement}. """ xmlstream.ListenAuthenticator.streamStarted(self, rootElement) # Compatibility fix for pre-8.2 implementations of ListenAuthenticator if not self.xmlstream.sid: from twisted.python import randbytes self.xmlstream.sid = randbytes.secureRandom(8).encode('hex') if rootElement.defaultUri != self.namespace: exc = error.StreamError('invalid-namespace') self.xmlstream.sendStreamError(exc) return # self.xmlstream.thisEntity is set to the address the component # wants to assume. if not self.xmlstream.thisEntity: exc = error.StreamError('improper-addressing') self.xmlstream.sendStreamError(exc) return self.xmlstream.sendHeader() self.xmlstream.addOnetimeObserver('/*', self.onElement)
def streamStarted(self, rootElement): """ Called by the stream when it has started. This examines the default namespace of the incoming stream and whether there is a requested hostname for the component. Then it generates a stream identifier, sends a response header and adds an observer for the first incoming element, triggering L{onElement}. """ xmlstream.ListenAuthenticator.streamStarted(self, rootElement) if rootElement.defaultUri != self.namespace: exc = error.StreamError("invalid-namespace") self.xmlstream.sendStreamError(exc) return # self.xmlstream.thisEntity is set to the address the component # wants to assume. if not self.xmlstream.thisEntity: exc = error.StreamError("improper-addressing") self.xmlstream.sendStreamError(exc) return self.xmlstream.sendHeader() self.xmlstream.addOnetimeObserver("/*", self.onElement)
def dispatch(self, xs, stanza): """ Send a stanza to the router, checking some stuff first. """ log.debug("stanza from %s: %s" % (xs.otherEntity.full(), stanza.toXml())) util.resetNamespace(stanza, xs.namespace) stanzaFrom = stanza.getAttribute('from') stanzaTo = stanza.getAttribute('to') if not stanza.bind and not stanzaFrom or not stanzaTo: xs.sendStreamError(error.StreamError('improper-addressing')) else: try: sender = jid.internJID(stanzaFrom) jid.internJID(stanzaTo) except jid.InvalidFormat: log.debug("dropping stanza with malformed JID") log.debug("sender = %s, otherEntity = %s" % (sender.full(), xs.otherEntity.full())) try: unused, host = util.jid_component(sender.host) if host in self.keyring.hostlist(): self.router.send(stanza) else: raise Exception() except: xs.sendStreamError(error.StreamError('invalid-from'))
def streamStarted(self, rootElement): xmlstream.ListenAuthenticator.streamStarted(self, rootElement) # Compatibility fix for pre-8.2 implementations of ListenAuthenticator if not self.xmlstream.sid: self.xmlstream.sid = randbytes.secureRandom(8).encode('hex') if self.xmlstream.thisEntity: targetDomain = self.xmlstream.thisEntity.host else: targetDomain = self.service.defaultDomain def prepareStream(domain): self.xmlstream.namespace = self.namespace self.xmlstream.prefixes = { xmlstream.NS_STREAMS: 'stream', NS_DIALBACK: 'db' } if domain: self.xmlstream.thisEntity = jid.internJID(domain) try: if xmlstream.NS_STREAMS != rootElement.uri or \ self.namespace != self.xmlstream.namespace or \ ('db', NS_DIALBACK) not in rootElement.localPrefixes.iteritems(): raise error.StreamError('invalid-namespace') if targetDomain and targetDomain not in self.service.domains: raise error.StreamError('host-unknown') except error.StreamError, exc: prepareStream(self.service.defaultDomain) self.xmlstream.sendStreamError(exc) return
def streamStarted(self, rootElement): xmlstream.ListenAuthenticator.streamStarted(self, rootElement) self.xmlstream.sendHeader() try: if self.xmlstream.version < (1, 0): raise error.StreamError('unsupported-version') if self.xmlstream.thisEntity.host != self.network: raise error.StreamError('not-authorized') except error.StreamError, exc: self.xmlstream.sendHeader() self.xmlstream.sendStreamError(exc) return
def test_getElementPlain(self): """ Test namespace of the element representation of an error. """ e = error.StreamError('feature-not-implemented') element = e.getElement() self.assertEqual(element.uri, NS_STREAMS)
def validateConnection(self, xs): otherHost = xs.otherEntity.host if otherHost in self._outgoingStreams: xs.sendStreamError(error.StreamError('conflict')) return False self._outgoingStreams[otherHost] = xs return True
def test_getElementTextNamespace(self): """ Test that the error text element has the correct namespace. """ e = error.StreamError('feature-not-implemented', 'text') element = e.getElement() self.assertEqual(NS_XMPP_STREAMS, element.text.uri)
def onVerify(self, verify): self.xmlstream.removeObserver(xmlstream.STREAM_ERROR_EVENT, self.onStreamError) if verify['id'] != self.originalStreamID: self.xmlstream.sendStreamError(error.StreamError('invalid-id')) self._deferred.errback(DialbackFailed()) elif verify['to'] != self.thisHost: self.xmlstream.sendStreamError(error.StreamError('host-unknown')) self._deferred.errback(DialbackFailed()) elif verify['from'] != self.otherHost: self.xmlstream.sendStreamError(error.StreamError('invalid-from')) self._deferred.errback(DialbackFailed()) elif verify['type'] == 'valid': self._deferred.callback(None) else: self._deferred.errback(DialbackFailed())
def _unauthorized(self, stanza): if not stanza.consumed and (not stanza.hasAttribute('to') or stanza['to'] != self.network): stanza.consumed = True self.xmlstream.sendStreamError(error.StreamError('not-authorized')) # refuse to process any more stanzas self.xmlstream.setDispatchFn(None)
def test_getElementConditionNamespace(self): """ Test that the error condition element has the correct namespace. """ e = error.StreamError('feature-not-implemented') element = e.getElement() self.assertEquals(NS_XMPP_STREAMS, getattr(element, 'feature-not-implemented').uri)
def wrappedObserver(element): try: observer(element) except error.StreamError as exc: xs.sendStreamError(exc) except: log.err() exc = error.StreamError('internal-server-error') xs.sendStreamError(exc)
def _timeout(self): self.ping_timeout = None # send stream error self.xmlstream.sendStreamError(error.StreamError('connection-timeout')) # broadcast unavailable presence if self.xmlstream.otherEntity is not None: stanza = xmppim.UnavailablePresence() stanza['from'] = self.xmlstream.otherEntity.full() self.parent.forward(stanza)
def dispatch(self, xs, stanza): """ Send on element to be routed within the server. """ stanzaFrom = stanza.getAttribute('from') stanzaTo = stanza.getAttribute('to') if not stanzaFrom or not stanzaTo: xs.sendStreamError(error.StreamError('improper-addressing')) else: try: sender = jid.internJID(stanzaFrom) jid.internJID(stanzaTo) except jid.InvalidFormat: log.msg("Dropping error stanza with malformed JID") if sender.host != xs.otherEntity.host: xs.sendStreamError(error.StreamError('invalid-from')) else: self.xmlstream.send(stanza)
def streamStarted(self, rootElement): xmlstream.ListenAuthenticator.streamStarted(self, rootElement) if self.xmlstream.thisEntity: targetDomain = self.xmlstream.thisEntity.host else: targetDomain = self.service.defaultDomain def prepareStream(domain): self.xmlstream.namespace = self.namespace self.xmlstream.prefixes = {xmlstream.NS_STREAMS: 'stream', NS_DIALBACK: 'db'} if domain: self.xmlstream.thisEntity = jid.internJID(domain) try: if xmlstream.NS_STREAMS != rootElement.uri or \ self.namespace != self.xmlstream.namespace or \ ('db', NS_DIALBACK) not in iteritems(rootElement.localPrefixes): raise error.StreamError('invalid-namespace') if targetDomain and targetDomain not in self.service.domains: raise error.StreamError('host-unknown') except error.StreamError as exc: prepareStream(self.service.defaultDomain) self.xmlstream.sendStreamError(exc) return self.xmlstream.addObserver("//verify[@xmlns='%s']" % NS_DIALBACK, trapStreamError(self.xmlstream, self.onVerify)) self.xmlstream.addObserver("//result[@xmlns='%s']" % NS_DIALBACK, self.onResult) prepareStream(targetDomain) self.xmlstream.sendHeader() if self.xmlstream.version >= (1, 0): features = domish.Element((xmlstream.NS_STREAMS, 'features')) self.xmlstream.send(features)
def test_sendStreamErrorReceiving(self): """ Test sendStreamError on a receiving xmlstream with a header sent. An error should be sent out and the connection lost. """ xs = self.xmlstream xs.initiating = False xs.sendHeader() xs.transport.clear() xs.sendStreamError(error.StreamError('version-unsupported')) self.assertNotEqual(b'', xs.transport.value()) self.assertTrue(self.gotStreamEnd)
def onElement(self, element): """ Called on incoming XML Stanzas. The very first element received should be a request for handshake. Otherwise, the stream is dropped with a 'not-authorized' error. If a handshake request was received, the hash is extracted and passed to L{onHandshake}. """ if (element.uri, element.name) == (self.namespace, "handshake"): self.onHandshake(str(element)) else: exc = error.StreamError("not-authorized") self.xmlstream.sendStreamError(exc)
def test_sendStreamErrorReceivingNoHeader(self): """ Test sendStreamError on a receiving xmlstream without having sent a header. In this case, a header should be generated. Then, the error should be sent out on the stream followed by closing the connection. """ xs = self.xmlstream xs.initiating = False xs.transport.clear() xs.sendStreamError(error.StreamError('version-unsupported')) self.assertTrue(xs._headerSent) self.assertNotEqual(b'', xs.transport.value()) self.assertTrue(self.gotStreamEnd)
def dispatch(self, xs, stanza): """ Send a stanza to the router, checking some stuff first. """ util.resetNamespace(stanza, xs.namespace) stanzaFrom = stanza.getAttribute('from') stanzaTo = stanza.getAttribute('to') if not stanzaFrom or not stanzaTo: xs.sendStreamError(error.StreamError('improper-addressing')) else: try: sender = jid.internJID(stanzaFrom) jid.internJID(stanzaTo) except jid.InvalidFormat: log.debug("Dropping error stanza with malformed JID") log.debug("sender = %s, otherEntity = %s" % (sender.full(), xs.otherEntity.full())) if sender.host != xs.otherEntity.host and sender.host != self.defaultDomain: xs.sendStreamError(error.StreamError('invalid-from')) else: self.router.send(stanza)
def test_sendStreamErrorInitiatingNoHeader(self): """ Test sendStreamError on an initiating xmlstream without having sent a header. In this case, no header should be generated. Also, the error should not be sent out on the stream. Just closing the connection. """ xs = self.xmlstream xs.initiating = True xs.transport.clear() xs.sendStreamError(error.StreamError('version-unsupported')) self.assertNot(xs._headerSent) self.assertEqual(b'', xs.transport.value()) self.assertTrue(self.gotStreamEnd)
def onHandshake(self, handshake): """ Called upon receiving the handshake request. This checks that the given hash in C{handshake} is equal to a calculated hash, responding with a handshake reply or a stream error. If the handshake was ok, the stream is authorized, and XML Stanzas may be exchanged. """ calculatedHash = xmlstream.hashPassword(self.xmlstream.sid, str(self.secret)) if handshake != calculatedHash: exc = error.StreamError("not-authorized", text="Invalid hash") self.xmlstream.sendStreamError(exc) else: self.xmlstream.send("<handshake/>") self.xmlstream.dispatch(self.xmlstream, xmlstream.STREAM_AUTHD_EVENT)
def streamStarted(self, rootElement): # TODO same checking code on listening authenticator # check that from attribute is associated to the right key host = rootElement['from'] fingerprint = self.xmlstream.transport.getPeerCertificate().fingerprint log.debug("%s fingerprint is %s" % ( host, fingerprint, )) valid = False # FIXME accessing Keyring internals for fpr, fhost in self.keyring._list.iteritems(): if fhost == host and fpr.upper() == fingerprint: log.debug("fingerprint matching (%s = %s)" % (host, fpr)) valid = True if valid: xmlstream.ConnectAuthenticator.streamStarted(self, rootElement) else: self.xmlstream.sendStreamError(error.StreamError('not-authorized'))
def onElementFallback(self, element): if element.handled: return exc = error.StreamError('not-authorized') self.xmlstream.sendStreamError(exc)
def conflict(self): if self.xmlstream: self.xmlstream.sendStreamError(error.StreamError('conflict')) # refuse to process any more stanzas self.xmlstream.setDispatchFn(None)
def testGetElementPlain(self): e = error.StreamError('feature-not-implemented') element = e.getElement() self.assertEquals(element.uri, NS_STREAMS)
def conflict(self): if self.xmlstream: self.xmlstream.sendStreamError(error.StreamError('conflict'))
def initialize(self): if self.xmlstream.version < (1, 0): raise error.StreamError('unsupported-version')
def _unauthorized(self, stanza): if not stanza.consumed and (not stanza.hasAttribute('to') or stanza['to'] != self.network): stanza.consumed = True self.xmlstream.sendStreamError(error.StreamError('not-authorized'))
This wraps an observer to catch exceptions. In case of a L{error.StreamError}, it is send over the given XML stream. All other exceptions yield a C{'internal-server-error'} stream error, that is sent over the stream, while the exception is logged. @return: Wrapped observer """ def wrappedObserver(element): try: observer(element) except error.StreamError, exc: xs.sendStreamError(exc) except: log.err() exc = error.StreamError('internal-server-error') xs.sendStreamError(exc) return wrappedObserver class XMPPServerConnector(SRVConnector): def __init__(self, reactor, domain, factory): SRVConnector.__init__(self, reactor, 'xmpp-server', domain, factory) def pickServer(self): host, port = SRVConnector.pickServer(self) if not self.servers and not self.orderedServers: # no SRV record, fall back.. port = 5269