| Index: third_party/twisted_8_1/twisted/words/protocols/jabber/sasl.py
|
| diff --git a/third_party/twisted_8_1/twisted/words/protocols/jabber/sasl.py b/third_party/twisted_8_1/twisted/words/protocols/jabber/sasl.py
|
| deleted file mode 100644
|
| index 9a9b8e342dd0e6242c53ae8e7b642241ccf2a4d5..0000000000000000000000000000000000000000
|
| --- a/third_party/twisted_8_1/twisted/words/protocols/jabber/sasl.py
|
| +++ /dev/null
|
| @@ -1,225 +0,0 @@
|
| -# Copyright (c) 2001-2007 Twisted Matrix Laboratories.
|
| -# See LICENSE for details.
|
| -
|
| -"""
|
| -XMPP-specific SASL profile.
|
| -"""
|
| -
|
| -import re
|
| -from twisted.internet import defer
|
| -from twisted.words.protocols.jabber import sasl_mechanisms, xmlstream
|
| -from twisted.words.xish import domish
|
| -
|
| -# The b64decode and b64encode functions from the base64 module are new in
|
| -# Python 2.4. For Python 2.3 compatibility, the legacy interface is used while
|
| -# working around MIMEisms.
|
| -
|
| -try:
|
| - from base64 import b64decode, b64encode
|
| -except ImportError:
|
| - import base64
|
| -
|
| - def b64encode(s):
|
| - return "".join(base64.encodestring(s).split("\n"))
|
| -
|
| - b64decode = base64.decodestring
|
| -
|
| -NS_XMPP_SASL = 'urn:ietf:params:xml:ns:xmpp-sasl'
|
| -
|
| -def get_mechanisms(xs):
|
| - """
|
| - Parse the SASL feature to extract the available mechanism names.
|
| - """
|
| - mechanisms = []
|
| - for element in xs.features[(NS_XMPP_SASL, 'mechanisms')].elements():
|
| - if element.name == 'mechanism':
|
| - mechanisms.append(str(element))
|
| -
|
| - return mechanisms
|
| -
|
| -
|
| -class SASLError(Exception):
|
| - """
|
| - SASL base exception.
|
| - """
|
| -
|
| -
|
| -class SASLNoAcceptableMechanism(SASLError):
|
| - """
|
| - The server did not present an acceptable SASL mechanism.
|
| - """
|
| -
|
| -
|
| -class SASLAuthError(SASLError):
|
| - """
|
| - SASL Authentication failed.
|
| - """
|
| - def __init__(self, condition=None):
|
| - self.condition = condition
|
| -
|
| -
|
| - def __str__(self):
|
| - return "SASLAuthError with condition %r" % self.condition
|
| -
|
| -
|
| -class SASLIncorrectEncodingError(SASLError):
|
| - """
|
| - SASL base64 encoding was incorrect.
|
| -
|
| - RFC 3920 specifies that any characters not in the base64 alphabet
|
| - and padding characters present elsewhere than at the end of the string
|
| - MUST be rejected. See also L{fromBase64}.
|
| -
|
| - This exception is raised whenever the encoded string does not adhere
|
| - to these additional restrictions or when the decoding itself fails.
|
| -
|
| - The recommended behaviour for so-called receiving entities (like servers in
|
| - client-to-server connections, see RFC 3920 for terminology) is to fail the
|
| - SASL negotiation with a C{'incorrect-encoding'} condition. For initiating
|
| - entities, one should assume the receiving entity to be either buggy or
|
| - malevolent. The stream should be terminated and reconnecting is not
|
| - advised.
|
| - """
|
| -
|
| -base64Pattern = re.compile("^[0-9A-Za-z+/]*[0-9A-Za-z+/=]{,2}$")
|
| -
|
| -def fromBase64(s):
|
| - """
|
| - Decode base64 encoded string.
|
| -
|
| - This helper performs regular decoding of a base64 encoded string, but also
|
| - rejects any characters that are not in the base64 alphabet and padding
|
| - occurring elsewhere from the last or last two characters, as specified in
|
| - section 14.9 of RFC 3920. This safeguards against various attack vectors
|
| - among which the creation of a covert channel that "leaks" information.
|
| - """
|
| -
|
| - if base64Pattern.match(s) is None:
|
| - raise SASLIncorrectEncodingError()
|
| -
|
| - try:
|
| - return b64decode(s)
|
| - except Exception, e:
|
| - raise SASLIncorrectEncodingError(str(e))
|
| -
|
| -class SASLInitiatingInitializer(xmlstream.BaseFeatureInitiatingInitializer):
|
| - """
|
| - Stream initializer that performs SASL authentication.
|
| -
|
| - The supported mechanisms by this initializer are C{DIGEST-MD5} and C{PLAIN}
|
| - which are attemped in that order.
|
| - """
|
| - feature = (NS_XMPP_SASL, 'mechanisms')
|
| - _deferred = None
|
| -
|
| - def setMechanism(self):
|
| - """
|
| - Select and setup authentication mechanism.
|
| -
|
| - Uses the authenticator's C{jid} and C{password} attribute for the
|
| - authentication credentials. If no supported SASL mechanisms are
|
| - advertized by the receiving party, a failing deferred is returned with
|
| - a L{SASLNoAcceptableMechanism} exception.
|
| - """
|
| -
|
| - jid = self.xmlstream.authenticator.jid
|
| - password = self.xmlstream.authenticator.password
|
| -
|
| - mechanisms = get_mechanisms(self.xmlstream)
|
| - if 'DIGEST-MD5' in mechanisms:
|
| - self.mechanism = sasl_mechanisms.DigestMD5('xmpp', jid.host, None,
|
| - jid.user, password)
|
| - elif 'PLAIN' in mechanisms:
|
| - self.mechanism = sasl_mechanisms.Plain(None, jid.user, password)
|
| - else:
|
| - raise SASLNoAcceptableMechanism()
|
| -
|
| - def start(self):
|
| - """
|
| - Start SASL authentication exchange.
|
| - """
|
| -
|
| - self.setMechanism()
|
| - self._deferred = defer.Deferred()
|
| - self.xmlstream.addObserver('/challenge', self.onChallenge)
|
| - self.xmlstream.addOnetimeObserver('/success', self.onSuccess)
|
| - self.xmlstream.addOnetimeObserver('/failure', self.onFailure)
|
| - self.sendAuth(self.mechanism.getInitialResponse())
|
| - return self._deferred
|
| -
|
| - def sendAuth(self, data=None):
|
| - """
|
| - Initiate authentication protocol exchange.
|
| -
|
| - If an initial client response is given in C{data}, it will be
|
| - sent along.
|
| -
|
| - @param data: initial client response.
|
| - @type data: L{str} or L{None}.
|
| - """
|
| -
|
| - auth = domish.Element((NS_XMPP_SASL, 'auth'))
|
| - auth['mechanism'] = self.mechanism.name
|
| - if data is not None:
|
| - auth.addContent(b64encode(data) or '=')
|
| - self.xmlstream.send(auth)
|
| -
|
| - def sendResponse(self, data=''):
|
| - """
|
| - Send response to a challenge.
|
| -
|
| - @param data: client response.
|
| - @type data: L{str}.
|
| - """
|
| -
|
| - response = domish.Element((NS_XMPP_SASL, 'response'))
|
| - if data:
|
| - response.addContent(b64encode(data))
|
| - self.xmlstream.send(response)
|
| -
|
| - def onChallenge(self, element):
|
| - """
|
| - Parse challenge and send response from the mechanism.
|
| -
|
| - @param element: the challenge protocol element.
|
| - @type element: L{domish.Element}.
|
| - """
|
| -
|
| - try:
|
| - challenge = fromBase64(str(element))
|
| - except SASLIncorrectEncodingError:
|
| - self._deferred.errback()
|
| - else:
|
| - self.sendResponse(self.mechanism.getResponse(challenge))
|
| -
|
| - def onSuccess(self, success):
|
| - """
|
| - Clean up observers, reset the XML stream and send a new header.
|
| -
|
| - @param success: the success protocol element. For now unused, but
|
| - could hold additional data.
|
| - @type success: L{domish.Element}
|
| - """
|
| -
|
| - self.xmlstream.removeObserver('/challenge', self.onChallenge)
|
| - self.xmlstream.removeObserver('/failure', self.onFailure)
|
| - self.xmlstream.reset()
|
| - self.xmlstream.sendHeader()
|
| - self._deferred.callback(xmlstream.Reset)
|
| -
|
| - def onFailure(self, failure):
|
| - """
|
| - Clean up observers, parse the failure and errback the deferred.
|
| -
|
| - @param failure: the failure protocol element. Holds details on
|
| - the error condition.
|
| - @type failure: L{domish.Element}
|
| - """
|
| -
|
| - self.xmlstream.removeObserver('/challenge', self.onChallenge)
|
| - self.xmlstream.removeObserver('/success', self.onSuccess)
|
| - try:
|
| - condition = failure.firstChildElement().name
|
| - except AttributeError:
|
| - condition = None
|
| - self._deferred.errback(SASLAuthError(condition))
|
|
|