From 91aac5b751049af25104ad4ded983946e128c966 Mon Sep 17 00:00:00 2001 From: wolfy1339 Date: Mon, 25 Sep 2017 23:20:03 -0400 Subject: [PATCH 01/12] Update sasl.py --- zirc/ext/sasl.py | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/zirc/ext/sasl.py b/zirc/ext/sasl.py index d0af0e4..2c924e7 100644 --- a/zirc/ext/sasl.py +++ b/zirc/ext/sasl.py @@ -1,6 +1,7 @@ # SASL authentication for zirc import base64 +import pyxmpp2_scram as scram from ..errors import SASLError class Sasl(object): @@ -11,10 +12,11 @@ def __init__(self, username, password, method="plain"): self.password = password self.method = method self.retries = 0 + self.sasl_scram_state = {'step': 'uninitialized'} def run(self, bot, args=None): if args is None: - mechanisms = ["EXTERNAL", "PLAIN"] + mechanisms = ["SCRAM-SHA256-PLUS", "SCRAM-SHA256", "EXTERNAL", "PLAIN"] else: mechanisms = args self.bot = bot @@ -22,7 +24,42 @@ def run(self, bot, args=None): bot.listen(self.on_saslfailed, "saslfailed") bot.listen(self.on_saslsuccess, "saslsuccess") if self.method.upper() in mechanisms: - if self.method in ["plain", "external"]: + if self.method.startswith("scram-"): + step = self.sasl_scram_state['step'] + try: + if step == 'uninitialized': + hash_name = self.mechanism[len('scram-'):] + if hash_name.endswith('-plus'): + hash_name = hash_name[:-len('-plus')] + hash_name = hash_name.upper() + if hash_name not in scram.HASH_FACTORIES: + self.retries += 2 + return + authenticator = scram.SCRAMClientAuthenticator(hash_name, channel_binding=False) + self.sasl_scram_state['authenticator'] = authenticator + client_first = authenticator.start({ + 'username': self.sasl_username, + 'password': self.sasl_password, + }) + self.sendSaslString(client_first) + self.sasl_scram_state['step'] = 'first-sent' + elif step == 'first-sent': + client_final = self.sasl_scram_state['authenticator'].challenge(challenge) + self.sendSaslString(client_final) + self.sasl_scram_state['step'] = 'final-sent' + elif step == 'final-sent': + try: + res = self.sasl_scram_state['authenticator'].finish(data) + except scram.BadSuccessException: + self.retries += 2 + else: + self.sasl_scram_state['step'] = 'authenticated' + else: + assert False + except scram.ScramException: + bot.send('AUTHENTICATE *') + self.retries += 2 + elif self.method in ["plain", "external"]: bot.send("AUTHENTICATE " + self.method.upper()) else: raise SASLError("Not implemented yet") @@ -40,7 +77,7 @@ def on_authenticate(self, event): def on_saslfailed(self, event): self.retries += 1 if self.method == 'external': - if self.retries == 2: + if self.retries >= 2: self.retries = 1 self.method = 'plain' self.bot.send("AUTHENTICATE PLAIN") From 1815973113939d7ccb9a9ddc169094f4f4814c37 Mon Sep 17 00:00:00 2001 From: wolfy1339 <4595477+wolfy1339@users.noreply.github.com> Date: Fri, 3 Nov 2017 12:04:27 -0400 Subject: [PATCH 02/12] Update and rename zirc/ext/sasl.py to zirc/ext/sasl/__init__.py --- zirc/ext/{sasl.py => sasl/__init__.py} | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename zirc/ext/{sasl.py => sasl/__init__.py} (94%) diff --git a/zirc/ext/sasl.py b/zirc/ext/sasl/__init__.py similarity index 94% rename from zirc/ext/sasl.py rename to zirc/ext/sasl/__init__.py index 2c924e7..83c599f 100644 --- a/zirc/ext/sasl.py +++ b/zirc/ext/sasl/__init__.py @@ -2,7 +2,7 @@ import base64 import pyxmpp2_scram as scram -from ..errors import SASLError +from ...errors import SASLError class Sasl(object): name = "sasl" @@ -28,7 +28,7 @@ def run(self, bot, args=None): step = self.sasl_scram_state['step'] try: if step == 'uninitialized': - hash_name = self.mechanism[len('scram-'):] + hash_name = self.method[len('scram-'):] if hash_name.endswith('-plus'): hash_name = hash_name[:-len('-plus')] hash_name = hash_name.upper() @@ -38,8 +38,8 @@ def run(self, bot, args=None): authenticator = scram.SCRAMClientAuthenticator(hash_name, channel_binding=False) self.sasl_scram_state['authenticator'] = authenticator client_first = authenticator.start({ - 'username': self.sasl_username, - 'password': self.sasl_password, + 'username': self.username, + 'password': self.password, }) self.sendSaslString(client_first) self.sasl_scram_state['step'] = 'first-sent' From f071e7c193b2a793b0764dbe74c366bd2a8261e6 Mon Sep 17 00:00:00 2001 From: wolfy1339 <4595477+wolfy1339@users.noreply.github.com> Date: Fri, 3 Nov 2017 12:16:58 -0400 Subject: [PATCH 03/12] Create scram.py --- zirc/ext/sasl/scram.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 zirc/ext/sasl/scram.py diff --git a/zirc/ext/sasl/scram.py b/zirc/ext/sasl/scram.py new file mode 100644 index 0000000..28ac420 --- /dev/null +++ b/zirc/ext/sasl/scram.py @@ -0,0 +1,32 @@ +import pyxmpp2_scram as scram + +def doAuthenticateScramFirst(self, mechanism): + """Handle sending the client-first message of SCRAM auth.""" + hash_name = mechanism[len('scram-'):] + if hash_name.endswith('-plus'): + hash_name = hash_name[:-len('-plus')] + hash_name = hash_name.upper() + if hash_name not in scram.HASH_FACTORIES: + self.retries += 2 + return + authenticator = scram.SCRAMClientAuthenticator(hash_name, channel_binding=False) + self.sasl_scram_state['authenticator'] = authenticator + client_first = authenticator.start({ + 'username': self.sasl_username, + 'password': self.sasl_password, + }) + self.bot.send("AUTHENTICATE {0}".format(client_first)) + self.sasl_scram_state['step'] = 'first-sent' + +def doAuthenticateScramChallenge(self, challenge): + client_final = self.sasl_scram_state['authenticator'].challenge(challenge) + self.bot.send("AUTHENTICATE {0}".format(client_final)) + self.sasl_scram_state['step'] = 'final-sent' + +def doAuthenticateScramFinish(self, data): + try: + res = self.sasl_scram_state['authenticator'].finish(data) + except scram.BadSuccessException as e: + self.retries += 2 + else: + self.sasl_scram_state['step'] = 'authenticated' From cdf0864e5a5e327434aae66eddfbff7b08489547 Mon Sep 17 00:00:00 2001 From: wolfy1339 <4595477+wolfy1339@users.noreply.github.com> Date: Fri, 3 Nov 2017 12:17:00 -0400 Subject: [PATCH 04/12] Update __init__.py --- zirc/ext/sasl/__init__.py | 39 +++++++++------------------------------ 1 file changed, 9 insertions(+), 30 deletions(-) diff --git a/zirc/ext/sasl/__init__.py b/zirc/ext/sasl/__init__.py index 83c599f..191a836 100644 --- a/zirc/ext/sasl/__init__.py +++ b/zirc/ext/sasl/__init__.py @@ -1,7 +1,7 @@ # SASL authentication for zirc import base64 -import pyxmpp2_scram as scram +from . import scram from ...errors import SASLError class Sasl(object): @@ -28,37 +28,16 @@ def run(self, bot, args=None): step = self.sasl_scram_state['step'] try: if step == 'uninitialized': - hash_name = self.method[len('scram-'):] - if hash_name.endswith('-plus'): - hash_name = hash_name[:-len('-plus')] - hash_name = hash_name.upper() - if hash_name not in scram.HASH_FACTORIES: - self.retries += 2 - return - authenticator = scram.SCRAMClientAuthenticator(hash_name, channel_binding=False) - self.sasl_scram_state['authenticator'] = authenticator - client_first = authenticator.start({ - 'username': self.username, - 'password': self.password, - }) - self.sendSaslString(client_first) - self.sasl_scram_state['step'] = 'first-sent' + scram.doAuthenticateScramFirst(self, method) elif step == 'first-sent': - client_final = self.sasl_scram_state['authenticator'].challenge(challenge) - self.sendSaslString(client_final) - self.sasl_scram_state['step'] = 'final-sent' + scram.doAuthenticateScramChallenge(self, string) elif step == 'final-sent': - try: - res = self.sasl_scram_state['authenticator'].finish(data) - except scram.BadSuccessException: - self.retries += 2 - else: - self.sasl_scram_state['step'] = 'authenticated' - else: - assert False - except scram.ScramException: - bot.send('AUTHENTICATE *') - self.retries += 2 + scram.doAuthenticateScramFinish(self, string) + else: + assert False + except scram.ScramException: + bot.send('AUTHENTICATE *') + self.retries += 2 elif self.method in ["plain", "external"]: bot.send("AUTHENTICATE " + self.method.upper()) else: From 93010c4b3f4c3e76532d1b211f2747ab69bf0e6a Mon Sep 17 00:00:00 2001 From: wolfy1339 <4595477+wolfy1339@users.noreply.github.com> Date: Fri, 3 Nov 2017 12:18:34 -0400 Subject: [PATCH 05/12] Update __init__.py --- zirc/ext/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/zirc/ext/__init__.py b/zirc/ext/__init__.py index e69de29..e397f85 100644 --- a/zirc/ext/__init__.py +++ b/zirc/ext/__init__.py @@ -0,0 +1 @@ +from . import sasl From f73e4e17e11f4268f53ea8ba41ae5245c58d4dc0 Mon Sep 17 00:00:00 2001 From: wolfy1339 <4595477+wolfy1339@users.noreply.github.com> Date: Fri, 3 Nov 2017 12:22:14 -0400 Subject: [PATCH 06/12] Update setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 61e6210..a596ca8 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ author_email='me+zirc@lukej.me', license='GNU', packages=find_packages(), - install_requires=['six'], + install_requires=['six', 'pyxmpp2_scram'], extras_require={ 'pysocks': ['pysocks'], 'pysocks:sys_platform=="win32" and python_version == "2.7"': ['win_inet_pton'] From 386ef36a70a758198d8ea7d7933d53178ff42e40 Mon Sep 17 00:00:00 2001 From: wolfy1339 <4595477+wolfy1339@users.noreply.github.com> Date: Fri, 3 Nov 2017 15:17:20 -0400 Subject: [PATCH 07/12] Update __init__.py --- zirc/ext/sasl/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/zirc/ext/sasl/__init__.py b/zirc/ext/sasl/__init__.py index 191a836..440c0f1 100644 --- a/zirc/ext/sasl/__init__.py +++ b/zirc/ext/sasl/__init__.py @@ -1,5 +1,6 @@ # SASL authentication for zirc +from sys import version_info import base64 from . import scram from ...errors import SASLError @@ -16,7 +17,10 @@ def __init__(self, username, password, method="plain"): def run(self, bot, args=None): if args is None: - mechanisms = ["SCRAM-SHA256-PLUS", "SCRAM-SHA256", "EXTERNAL", "PLAIN"] + mechanisms = ["EXTERNAL", "PLAIN"] + if version_info[0] == 3 and not version_info[1] == 2: + mechanisms.insert(0, "SCRAM-SHA256-PLUS") + mechanisms.insert(1, "SCRAM-SHA256") else: mechanisms = args self.bot = bot From 4e88f1efa324c5694179dbe95cc2051c8f905191 Mon Sep 17 00:00:00 2001 From: wolfy1339 <4595477+wolfy1339@users.noreply.github.com> Date: Wed, 15 Nov 2017 12:36:15 -0500 Subject: [PATCH 08/12] Update __init__.py --- zirc/ext/sasl/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zirc/ext/sasl/__init__.py b/zirc/ext/sasl/__init__.py index 440c0f1..573c60f 100644 --- a/zirc/ext/sasl/__init__.py +++ b/zirc/ext/sasl/__init__.py @@ -18,7 +18,7 @@ def __init__(self, username, password, method="plain"): def run(self, bot, args=None): if args is None: mechanisms = ["EXTERNAL", "PLAIN"] - if version_info[0] == 3 and not version_info[1] == 2: + if not (version_info[0] == 3 and version_info[1] == 2): mechanisms.insert(0, "SCRAM-SHA256-PLUS") mechanisms.insert(1, "SCRAM-SHA256") else: From cc8945713227037c6da1bdddb3910c04bd30840b Mon Sep 17 00:00:00 2001 From: wolfy1339 <4595477+wolfy1339@users.noreply.github.com> Date: Wed, 15 Nov 2017 13:20:25 -0500 Subject: [PATCH 09/12] Fix the code so it actually fires --- zirc/ext/sasl/__init__.py | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/zirc/ext/sasl/__init__.py b/zirc/ext/sasl/__init__.py index 573c60f..107b802 100644 --- a/zirc/ext/sasl/__init__.py +++ b/zirc/ext/sasl/__init__.py @@ -28,21 +28,7 @@ def run(self, bot, args=None): bot.listen(self.on_saslfailed, "saslfailed") bot.listen(self.on_saslsuccess, "saslsuccess") if self.method.upper() in mechanisms: - if self.method.startswith("scram-"): - step = self.sasl_scram_state['step'] - try: - if step == 'uninitialized': - scram.doAuthenticateScramFirst(self, method) - elif step == 'first-sent': - scram.doAuthenticateScramChallenge(self, string) - elif step == 'final-sent': - scram.doAuthenticateScramFinish(self, string) - else: - assert False - except scram.ScramException: - bot.send('AUTHENTICATE *') - self.retries += 2 - elif self.method in ["plain", "external"]: + if self.method in ["scram-sha256-plus", "scram-sha256", "plain", "external"]: bot.send("AUTHENTICATE " + self.method.upper()) else: raise SASLError("Not implemented yet") @@ -55,7 +41,24 @@ def on_authenticate(self, event): password = base64.b64encode("{0}\x00{0}\x00{1}".format(self.username, self.password).encode("UTF-8")).decode("UTF-8") elif self.method == 'external': password = "+" + elif self.method.startswith('scram-sha'): + scram.doAuthenticateScramFirst(self, self.method) self.bot.send("AUTHENTICATE {0}".format(password)) + else: + step = self.sasl_scram_state['step'] + string = event.arguments[0] + try: + if step == 'first-sent': + scram.doAuthenticateScramChallenge(self, string) + elif step == 'final-sent': + scram.doAuthenticateScramFinish(self, string) + elif step == "authenticated": + self.bot.send("AUTHENTICATE +") + else: + assert False + except scram.ScramException: + bot.send('AUTHENTICATE *') + self.retries += 2 def on_saslfailed(self, event): self.retries += 1 From af930e5a4440ba2024d4af3907db6391671cc1e2 Mon Sep 17 00:00:00 2001 From: wolfy1339 <4595477+wolfy1339@users.noreply.github.com> Date: Wed, 15 Nov 2017 13:21:09 -0500 Subject: [PATCH 10/12] Update scram.py --- zirc/ext/sasl/scram.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zirc/ext/sasl/scram.py b/zirc/ext/sasl/scram.py index 28ac420..a4327f6 100644 --- a/zirc/ext/sasl/scram.py +++ b/zirc/ext/sasl/scram.py @@ -26,7 +26,8 @@ def doAuthenticateScramChallenge(self, challenge): def doAuthenticateScramFinish(self, data): try: res = self.sasl_scram_state['authenticator'].finish(data) - except scram.BadSuccessException as e: + except scram.BadSuccessException: self.retries += 2 else: self.sasl_scram_state['step'] = 'authenticated' + self.bot.send("AUTHENTICATE +") From 32cfc2a264526546f61377e4cabb5e3271bbfb59 Mon Sep 17 00:00:00 2001 From: wolfy1339 <4595477+wolfy1339@users.noreply.github.com> Date: Thu, 16 Nov 2017 13:19:03 -0500 Subject: [PATCH 11/12] Lock pyxmpp2-sasl to 2.0.2 minimum --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index a596ca8..503b568 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ author_email='me+zirc@lukej.me', license='GNU', packages=find_packages(), - install_requires=['six', 'pyxmpp2_scram'], + install_requires=['six', 'pyxmpp2_scram>=2.0.2'], extras_require={ 'pysocks': ['pysocks'], 'pysocks:sys_platform=="win32" and python_version == "2.7"': ['win_inet_pton'] From 63d9e3f254fea00262dd57985df267f705098269 Mon Sep 17 00:00:00 2001 From: wolfy1339 Date: Thu, 4 Jan 2018 21:51:58 -0500 Subject: [PATCH 12/12] Revert "Update __init__.py" This reverts commit c5a23e3876f49a202cc034e65f461fc7e57fc0d8. --- zirc/ext/sasl/__init__.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/zirc/ext/sasl/__init__.py b/zirc/ext/sasl/__init__.py index 107b802..6a10d0e 100644 --- a/zirc/ext/sasl/__init__.py +++ b/zirc/ext/sasl/__init__.py @@ -1,6 +1,5 @@ # SASL authentication for zirc -from sys import version_info import base64 from . import scram from ...errors import SASLError @@ -17,10 +16,7 @@ def __init__(self, username, password, method="plain"): def run(self, bot, args=None): if args is None: - mechanisms = ["EXTERNAL", "PLAIN"] - if not (version_info[0] == 3 and version_info[1] == 2): - mechanisms.insert(0, "SCRAM-SHA256-PLUS") - mechanisms.insert(1, "SCRAM-SHA256") + mechanisms = ["SCRAM-SHA256-PLUS", "SCRAM-SHA256", "EXTERNAL", "PLAIN"] else: mechanisms = args self.bot = bot