Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(42)

Side by Side Diff: third_party/twisted_8_1/twisted/words/protocols/jabber/sasl.py

Issue 12261012: Remove third_party/twisted_8_1 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 # Copyright (c) 2001-2007 Twisted Matrix Laboratories.
2 # See LICENSE for details.
3
4 """
5 XMPP-specific SASL profile.
6 """
7
8 import re
9 from twisted.internet import defer
10 from twisted.words.protocols.jabber import sasl_mechanisms, xmlstream
11 from twisted.words.xish import domish
12
13 # The b64decode and b64encode functions from the base64 module are new in
14 # Python 2.4. For Python 2.3 compatibility, the legacy interface is used while
15 # working around MIMEisms.
16
17 try:
18 from base64 import b64decode, b64encode
19 except ImportError:
20 import base64
21
22 def b64encode(s):
23 return "".join(base64.encodestring(s).split("\n"))
24
25 b64decode = base64.decodestring
26
27 NS_XMPP_SASL = 'urn:ietf:params:xml:ns:xmpp-sasl'
28
29 def get_mechanisms(xs):
30 """
31 Parse the SASL feature to extract the available mechanism names.
32 """
33 mechanisms = []
34 for element in xs.features[(NS_XMPP_SASL, 'mechanisms')].elements():
35 if element.name == 'mechanism':
36 mechanisms.append(str(element))
37
38 return mechanisms
39
40
41 class SASLError(Exception):
42 """
43 SASL base exception.
44 """
45
46
47 class SASLNoAcceptableMechanism(SASLError):
48 """
49 The server did not present an acceptable SASL mechanism.
50 """
51
52
53 class SASLAuthError(SASLError):
54 """
55 SASL Authentication failed.
56 """
57 def __init__(self, condition=None):
58 self.condition = condition
59
60
61 def __str__(self):
62 return "SASLAuthError with condition %r" % self.condition
63
64
65 class SASLIncorrectEncodingError(SASLError):
66 """
67 SASL base64 encoding was incorrect.
68
69 RFC 3920 specifies that any characters not in the base64 alphabet
70 and padding characters present elsewhere than at the end of the string
71 MUST be rejected. See also L{fromBase64}.
72
73 This exception is raised whenever the encoded string does not adhere
74 to these additional restrictions or when the decoding itself fails.
75
76 The recommended behaviour for so-called receiving entities (like servers in
77 client-to-server connections, see RFC 3920 for terminology) is to fail the
78 SASL negotiation with a C{'incorrect-encoding'} condition. For initiating
79 entities, one should assume the receiving entity to be either buggy or
80 malevolent. The stream should be terminated and reconnecting is not
81 advised.
82 """
83
84 base64Pattern = re.compile("^[0-9A-Za-z+/]*[0-9A-Za-z+/=]{,2}$")
85
86 def fromBase64(s):
87 """
88 Decode base64 encoded string.
89
90 This helper performs regular decoding of a base64 encoded string, but also
91 rejects any characters that are not in the base64 alphabet and padding
92 occurring elsewhere from the last or last two characters, as specified in
93 section 14.9 of RFC 3920. This safeguards against various attack vectors
94 among which the creation of a covert channel that "leaks" information.
95 """
96
97 if base64Pattern.match(s) is None:
98 raise SASLIncorrectEncodingError()
99
100 try:
101 return b64decode(s)
102 except Exception, e:
103 raise SASLIncorrectEncodingError(str(e))
104
105 class SASLInitiatingInitializer(xmlstream.BaseFeatureInitiatingInitializer):
106 """
107 Stream initializer that performs SASL authentication.
108
109 The supported mechanisms by this initializer are C{DIGEST-MD5} and C{PLAIN}
110 which are attemped in that order.
111 """
112 feature = (NS_XMPP_SASL, 'mechanisms')
113 _deferred = None
114
115 def setMechanism(self):
116 """
117 Select and setup authentication mechanism.
118
119 Uses the authenticator's C{jid} and C{password} attribute for the
120 authentication credentials. If no supported SASL mechanisms are
121 advertized by the receiving party, a failing deferred is returned with
122 a L{SASLNoAcceptableMechanism} exception.
123 """
124
125 jid = self.xmlstream.authenticator.jid
126 password = self.xmlstream.authenticator.password
127
128 mechanisms = get_mechanisms(self.xmlstream)
129 if 'DIGEST-MD5' in mechanisms:
130 self.mechanism = sasl_mechanisms.DigestMD5('xmpp', jid.host, None,
131 jid.user, password)
132 elif 'PLAIN' in mechanisms:
133 self.mechanism = sasl_mechanisms.Plain(None, jid.user, password)
134 else:
135 raise SASLNoAcceptableMechanism()
136
137 def start(self):
138 """
139 Start SASL authentication exchange.
140 """
141
142 self.setMechanism()
143 self._deferred = defer.Deferred()
144 self.xmlstream.addObserver('/challenge', self.onChallenge)
145 self.xmlstream.addOnetimeObserver('/success', self.onSuccess)
146 self.xmlstream.addOnetimeObserver('/failure', self.onFailure)
147 self.sendAuth(self.mechanism.getInitialResponse())
148 return self._deferred
149
150 def sendAuth(self, data=None):
151 """
152 Initiate authentication protocol exchange.
153
154 If an initial client response is given in C{data}, it will be
155 sent along.
156
157 @param data: initial client response.
158 @type data: L{str} or L{None}.
159 """
160
161 auth = domish.Element((NS_XMPP_SASL, 'auth'))
162 auth['mechanism'] = self.mechanism.name
163 if data is not None:
164 auth.addContent(b64encode(data) or '=')
165 self.xmlstream.send(auth)
166
167 def sendResponse(self, data=''):
168 """
169 Send response to a challenge.
170
171 @param data: client response.
172 @type data: L{str}.
173 """
174
175 response = domish.Element((NS_XMPP_SASL, 'response'))
176 if data:
177 response.addContent(b64encode(data))
178 self.xmlstream.send(response)
179
180 def onChallenge(self, element):
181 """
182 Parse challenge and send response from the mechanism.
183
184 @param element: the challenge protocol element.
185 @type element: L{domish.Element}.
186 """
187
188 try:
189 challenge = fromBase64(str(element))
190 except SASLIncorrectEncodingError:
191 self._deferred.errback()
192 else:
193 self.sendResponse(self.mechanism.getResponse(challenge))
194
195 def onSuccess(self, success):
196 """
197 Clean up observers, reset the XML stream and send a new header.
198
199 @param success: the success protocol element. For now unused, but
200 could hold additional data.
201 @type success: L{domish.Element}
202 """
203
204 self.xmlstream.removeObserver('/challenge', self.onChallenge)
205 self.xmlstream.removeObserver('/failure', self.onFailure)
206 self.xmlstream.reset()
207 self.xmlstream.sendHeader()
208 self._deferred.callback(xmlstream.Reset)
209
210 def onFailure(self, failure):
211 """
212 Clean up observers, parse the failure and errback the deferred.
213
214 @param failure: the failure protocol element. Holds details on
215 the error condition.
216 @type failure: L{domish.Element}
217 """
218
219 self.xmlstream.removeObserver('/challenge', self.onChallenge)
220 self.xmlstream.removeObserver('/success', self.onSuccess)
221 try:
222 condition = failure.firstChildElement().name
223 except AttributeError:
224 condition = None
225 self._deferred.errback(SASLAuthError(condition))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698