diff --git a/README.rst b/README.rst index 24856f7..67003a3 100644 --- a/README.rst +++ b/README.rst @@ -6,7 +6,7 @@ pure-sasl pure-sasl is a pure python client-side SASL implementation. -At the moment, it supports the following mechanisms: ANONYMOUS, PLAIN, +At the moment, it supports the following mechanisms: ANONYMOUS, PLAIN, EXTERNAL, CRAM-MD5, DIGEST-MD5, and GSSAPI. Support for other mechanisms may be added in the future. Only GSSAPI supports a QOP higher than auth. Always use TLS! diff --git a/puresasl/mechanisms.py b/puresasl/mechanisms.py index 55adc05..7f2ebff 100644 --- a/puresasl/mechanisms.py +++ b/puresasl/mechanisms.py @@ -172,6 +172,25 @@ def dispose(self): self.password = None +class ExternalMechanism(Mechanism): + """ + The EXTERNAL mechanism allows a client to request the server to use + credentials established by means external to the mechanism to + authenticate the client. + """ + name = 'EXTERNAL' + score = 10 + + def wrap(self, outgoing): + return outgoing + + def unwrap(self, incoming): + return incoming + + def process(self, challenge=None): + return b'' + + class CramMD5Mechanism(PlainMechanism): name = "CRAM-MD5" score = 20 @@ -530,6 +549,7 @@ def dispose(self): mechanisms = dict((m.name, m) for m in ( AnonymousMechanism, PlainMechanism, + ExternalMechanism, CramMD5Mechanism, DigestMD5Mechanism)) diff --git a/setup.py b/setup.py index 2cf08d4..586f41f 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ long_description= """This package provides a reasonably high-level SASL client written in pure Python. New mechanisms may be integrated easily, but by default, -support for PLAIN, ANONYMOUS, CRAM-MD5, DIGEST-MD5, and GSSAPI are +support for PLAIN, ANONYMOUS, EXTERNAL, CRAM-MD5, DIGEST-MD5, and GSSAPI are provided.""", license='MIT', url='http://github.com/thobbs/pure-sasl', diff --git a/tests/unit/test_mechanism.py b/tests/unit/test_mechanism.py index 0af19c7..f0ae9c4 100644 --- a/tests/unit/test_mechanism.py +++ b/tests/unit/test_mechanism.py @@ -14,7 +14,7 @@ from puresasl import SASLProtocolException, QOP from puresasl.client import SASLClient -from puresasl.mechanisms import AnonymousMechanism, PlainMechanism, GSSAPIMechanism, DigestMD5Mechanism, CramMD5Mechanism +from puresasl.mechanisms import AnonymousMechanism, PlainMechanism, GSSAPIMechanism, DigestMD5Mechanism, CramMD5Mechanism, ExternalMechanism class _BaseMechanismTests(unittest.TestCase): @@ -91,6 +91,20 @@ def test_wrap_unwrap(self): self.assertIs(self.sasl.wrap(msg), msg) self.assertIs(self.sasl.unwrap(msg), msg) + +class ExternalMechanismTest(_BaseMechanismTests): + + mechanism_class = ExternalMechanism + + def test_process(self): + self.assertIs(self.sasl.process(), b'') + + def test_wrap_unwrap(self): + msg = 'msg' + self.assertIs(self.sasl.wrap(msg), msg) + self.assertIs(self.sasl.unwrap(msg), msg) + + @patch('puresasl.mechanisms.kerberos.authGSSClientStep') @patch('puresasl.mechanisms.kerberos.authGSSClientResponse', return_value=base64.b64encode(six.b('some\x00 response'))) class GSSAPIMechanismTest(_BaseMechanismTests):