From b898b14b77d739cb1c118c9e3648aa268348d293 Mon Sep 17 00:00:00 2001 From: Lance Stout Date: Sat, 2 Jul 2011 22:30:34 -0700 Subject: [PATCH] Use a set to track negotiated features. Added guards to prevent renegotiating STARTTLS or SASL in cases where servers don't behave properly. --- sleekxmpp/clientxmpp.py | 4 ++-- sleekxmpp/features/feature_bind/bind.py | 2 ++ sleekxmpp/features/feature_mechanisms/mechanisms.py | 7 ++++++- sleekxmpp/features/feature_session/session.py | 2 ++ sleekxmpp/features/feature_starttls/starttls.py | 8 ++++++-- 5 files changed, 18 insertions(+), 5 deletions(-) diff --git a/sleekxmpp/clientxmpp.py b/sleekxmpp/clientxmpp.py index 5b36e845..5eb9c90a 100644 --- a/sleekxmpp/clientxmpp.py +++ b/sleekxmpp/clientxmpp.py @@ -83,7 +83,7 @@ class ClientXMPP(BaseXMPP): "xmlns='%s'" % self.default_ns) self.stream_footer = "" - self.features = [] + self.features = set() self._stream_feature_handlers = {} self._stream_feature_order = [] @@ -273,7 +273,7 @@ class ClientXMPP(BaseXMPP): self.sessionstarted = False self.bound = False self.bindfail = False - self.features = [] + self.features = set() def session_timeout(): if not self.session_started_event.isSet(): diff --git a/sleekxmpp/features/feature_bind/bind.py b/sleekxmpp/features/feature_bind/bind.py index e177d7b2..c5d9395f 100644 --- a/sleekxmpp/features/feature_bind/bind.py +++ b/sleekxmpp/features/feature_bind/bind.py @@ -53,6 +53,8 @@ class feature_bind(base_plugin): self.xmpp.set_jid(response['bind']['jid']) self.xmpp.bound = True + self.features.add('bind') + log.info("Node set to: %s" % self.xmpp.boundjid.full) if 'session' not in features['features']: diff --git a/sleekxmpp/features/feature_mechanisms/mechanisms.py b/sleekxmpp/features/feature_mechanisms/mechanisms.py index a8a046e4..011010fb 100644 --- a/sleekxmpp/features/feature_mechanisms/mechanisms.py +++ b/sleekxmpp/features/feature_mechanisms/mechanisms.py @@ -90,6 +90,11 @@ class feature_mechanisms(base_plugin): Arguments: features -- The stream features stanza. """ + if 'mechanisms' in self.xmpp.features: + # SASL authentication has already succeeded, but the + # server has incorrectly offered it again. + return False + for priority, mech in self._mechanism_priorities: if mech in features['mechanisms']: log.debug('Attempt to use SASL %s' % mech) @@ -105,7 +110,7 @@ class feature_mechanisms(base_plugin): def _handle_success(self, stanza): """SASL authentication succeeded. Restart the stream.""" self.xmpp.authenticated = True - self.xmpp.features.append('mechanisms') + self.xmpp.features.add('mechanisms') raise RestartStream() def _handle_fail(self, stanza): diff --git a/sleekxmpp/features/feature_session/session.py b/sleekxmpp/features/feature_session/session.py index 4d17b2d2..9c5e0448 100644 --- a/sleekxmpp/features/feature_session/session.py +++ b/sleekxmpp/features/feature_session/session.py @@ -48,6 +48,8 @@ class feature_session(base_plugin): iq.enable('session') response = iq.send(now=True) + self.xmpp.features.add('session') + log.debug("Established Session") self.xmpp.sessionstarted = True self.xmpp.session_started_event.set() diff --git a/sleekxmpp/features/feature_starttls/starttls.py b/sleekxmpp/features/feature_starttls/starttls.py index cbb94be0..841e7a8d 100644 --- a/sleekxmpp/features/feature_starttls/starttls.py +++ b/sleekxmpp/features/feature_starttls/starttls.py @@ -48,7 +48,11 @@ class feature_starttls(base_plugin): Arguments: features -- The stream:features element. """ - if not self.xmpp.use_tls: + if 'starttls' in self.xmpp.features: + # We have already negotiated TLS, but the server is + # offering it again, against spec. + return False + elif not self.xmpp.use_tls: return False elif self.xmpp.ssl_support: self.xmpp.send(features['starttls'], now=True) @@ -62,5 +66,5 @@ class feature_starttls(base_plugin): """Restart the XML stream when TLS is accepted.""" log.debug("Starting TLS") if self.xmpp.start_tls(): - self.xmpp.features.append('starttls') + self.xmpp.features.add('starttls') raise RestartStream()