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

Side by Side Diff: third_party/twisted_8_1/twisted/words/protocols/jabber/client.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 # -*- test-case-name: twisted.words.test.test_jabberclient -*-
2 #
3 # Copyright (c) 2001-2005 Twisted Matrix Laboratories.
4 # See LICENSE for details.
5
6 from twisted.internet import defer
7 from twisted.words.xish import domish, xpath, utility
8 from twisted.words.protocols.jabber import xmlstream, sasl, error
9 from twisted.words.protocols.jabber.jid import JID
10
11 NS_XMPP_STREAMS = 'urn:ietf:params:xml:ns:xmpp-streams'
12 NS_XMPP_BIND = 'urn:ietf:params:xml:ns:xmpp-bind'
13 NS_XMPP_SESSION = 'urn:ietf:params:xml:ns:xmpp-session'
14 NS_IQ_AUTH_FEATURE = 'http://jabber.org/features/iq-auth'
15
16 DigestAuthQry = xpath.internQuery("/iq/query/digest")
17 PlaintextAuthQry = xpath.internQuery("/iq/query/password")
18
19 def basicClientFactory(jid, secret):
20 a = BasicAuthenticator(jid, secret)
21 return xmlstream.XmlStreamFactory(a)
22
23 class IQ(domish.Element):
24 """
25 Wrapper for a Info/Query packet.
26
27 This provides the necessary functionality to send IQs and get notified when
28 a result comes back. It's a subclass from L{domish.Element}, so you can use
29 the standard DOM manipulation calls to add data to the outbound request.
30
31 @type callbacks: L{utility.CallbackList}
32 @cvar callbacks: Callback list to be notified when response comes back
33
34 """
35 def __init__(self, xmlstream, type = "set"):
36 """
37 @type xmlstream: L{xmlstream.XmlStream}
38 @param xmlstream: XmlStream to use for transmission of this IQ
39
40 @type type: L{str}
41 @param type: IQ type identifier ('get' or 'set')
42 """
43
44 domish.Element.__init__(self, ("jabber:client", "iq"))
45 self.addUniqueId()
46 self["type"] = type
47 self._xmlstream = xmlstream
48 self.callbacks = utility.CallbackList()
49
50 def addCallback(self, fn, *args, **kwargs):
51 """
52 Register a callback for notification when the IQ result is available.
53 """
54
55 self.callbacks.addCallback(True, fn, *args, **kwargs)
56
57 def send(self, to = None):
58 """
59 Call this method to send this IQ request via the associated XmlStream.
60
61 @param to: Jabber ID of the entity to send the request to
62 @type to: L{str}
63
64 @returns: Callback list for this IQ. Any callbacks added to this list
65 will be fired when the result comes back.
66 """
67 if to != None:
68 self["to"] = to
69 self._xmlstream.addOnetimeObserver("/iq[@id='%s']" % self["id"], \
70 self._resultEvent)
71 self._xmlstream.send(self)
72
73 def _resultEvent(self, iq):
74 self.callbacks.callback(iq)
75 self.callbacks = None
76
77
78
79 class IQAuthInitializer(object):
80 """
81 Non-SASL Authentication initializer for the initiating entity.
82
83 This protocol is defined in
84 U{JEP-0078<http://www.jabber.org/jeps/jep-0078.html>} and mainly serves for
85 compatibility with pre-XMPP-1.0 server implementations.
86 """
87
88 INVALID_USER_EVENT = "//event/client/basicauth/invaliduser"
89 AUTH_FAILED_EVENT = "//event/client/basicauth/authfailed"
90
91 def __init__(self, xs):
92 self.xmlstream = xs
93
94
95 def initialize(self):
96 # Send request for auth fields
97 iq = xmlstream.IQ(self.xmlstream, "get")
98 iq.addElement(("jabber:iq:auth", "query"))
99 jid = self.xmlstream.authenticator.jid
100 iq.query.addElement("username", content = jid.user)
101
102 d = iq.send()
103 d.addCallbacks(self._cbAuthQuery, self._ebAuthQuery)
104 return d
105
106
107 def _cbAuthQuery(self, iq):
108 jid = self.xmlstream.authenticator.jid
109 password = self.xmlstream.authenticator.password
110
111 # Construct auth request
112 reply = xmlstream.IQ(self.xmlstream, "set")
113 reply.addElement(("jabber:iq:auth", "query"))
114 reply.query.addElement("username", content = jid.user)
115 reply.query.addElement("resource", content = jid.resource)
116
117 # Prefer digest over plaintext
118 if DigestAuthQry.matches(iq):
119 digest = xmlstream.hashPassword(self.xmlstream.sid, password)
120 reply.query.addElement("digest", content = digest)
121 else:
122 reply.query.addElement("password", content = password)
123
124 d = reply.send()
125 d.addCallbacks(self._cbAuth, self._ebAuth)
126 return d
127
128
129 def _ebAuthQuery(self, failure):
130 failure.trap(error.StanzaError)
131 e = failure.value
132 if e.condition == 'not-authorized':
133 self.xmlstream.dispatch(e.stanza, self.INVALID_USER_EVENT)
134 else:
135 self.xmlstream.dispatch(e.stanza, self.AUTH_FAILED_EVENT)
136
137 return failure
138
139
140 def _cbAuth(self, iq):
141 pass
142
143
144 def _ebAuth(self, failure):
145 failure.trap(error.StanzaError)
146 self.xmlstream.dispatch(failure.value.stanza, self.AUTH_FAILED_EVENT)
147 return failure
148
149
150
151 class BasicAuthenticator(xmlstream.ConnectAuthenticator):
152 """
153 Authenticates an XmlStream against a Jabber server as a Client.
154
155 This only implements non-SASL authentication, per
156 U{JEP-0078<http://www.jabber.org/jeps/jep-0078.html>}. Additionally, this
157 authenticator provides the ability to perform inline registration, per
158 U{JEP-0077<http://www.jabber.org/jeps/jep-0077.html>}.
159
160 Under normal circumstances, the BasicAuthenticator generates the
161 L{xmlstream.STREAM_AUTHD_EVENT} once the stream has authenticated. However,
162 it can also generate other events, such as:
163 - L{INVALID_USER_EVENT} : Authentication failed, due to invalid username
164 - L{AUTH_FAILED_EVENT} : Authentication failed, due to invalid password
165 - L{REGISTER_FAILED_EVENT} : Registration failed
166
167 If authentication fails for any reason, you can attempt to register by
168 calling the L{registerAccount} method. If the registration succeeds, a
169 L{xmlstream.STREAM_AUTHD_EVENT} will be fired. Otherwise, one of the above
170 errors will be generated (again).
171 """
172
173 namespace = "jabber:client"
174
175 INVALID_USER_EVENT = IQAuthInitializer.INVALID_USER_EVENT
176 AUTH_FAILED_EVENT = IQAuthInitializer.AUTH_FAILED_EVENT
177 REGISTER_FAILED_EVENT = "//event/client/basicauth/registerfailed"
178
179 def __init__(self, jid, password):
180 xmlstream.ConnectAuthenticator.__init__(self, jid.host)
181 self.jid = jid
182 self.password = password
183
184 def associateWithStream(self, xs):
185 xs.version = (0, 0)
186 xmlstream.ConnectAuthenticator.associateWithStream(self, xs)
187
188 inits = [ (xmlstream.TLSInitiatingInitializer, False),
189 (IQAuthInitializer, True),
190 ]
191
192 for initClass, required in inits:
193 init = initClass(xs)
194 init.required = required
195 xs.initializers.append(init)
196
197 # TODO: move registration into an Initializer?
198
199 def registerAccount(self, username = None, password = None):
200 if username:
201 self.jid.user = username
202 if password:
203 self.password = password
204
205 iq = IQ(self.xmlstream, "set")
206 iq.addElement(("jabber:iq:register", "query"))
207 iq.query.addElement("username", content = self.jid.user)
208 iq.query.addElement("password", content = self.password)
209
210 iq.addCallback(self._registerResultEvent)
211
212 iq.send()
213
214 def _registerResultEvent(self, iq):
215 if iq["type"] == "result":
216 # Registration succeeded -- go ahead and auth
217 self.streamStarted()
218 else:
219 # Registration failed
220 self.xmlstream.dispatch(iq, self.REGISTER_FAILED_EVENT)
221
222
223
224 class CheckVersionInitializer(object):
225 """
226 Initializer that checks if the minimum common stream version number is 1.0.
227 """
228
229 def __init__(self, xs):
230 self.xmlstream = xs
231
232
233 def initialize(self):
234 if self.xmlstream.version < (1, 0):
235 raise error.StreamError('unsupported-version')
236
237
238
239 class BindInitializer(xmlstream.BaseFeatureInitiatingInitializer):
240 """
241 Initializer that implements Resource Binding for the initiating entity.
242
243 This protocol is documented in U{RFC 3920, section
244 7<http://www.xmpp.org/specs/rfc3920.html#bind>}.
245 """
246
247 feature = (NS_XMPP_BIND, 'bind')
248
249 def start(self):
250 iq = xmlstream.IQ(self.xmlstream, 'set')
251 bind = iq.addElement((NS_XMPP_BIND, 'bind'))
252 resource = self.xmlstream.authenticator.jid.resource
253 if resource:
254 bind.addElement('resource', content=resource)
255 d = iq.send()
256 d.addCallback(self.onBind)
257 return d
258
259
260 def onBind(self, iq):
261 if iq.bind:
262 self.xmlstream.authenticator.jid = JID(unicode(iq.bind.jid))
263
264
265
266 class SessionInitializer(xmlstream.BaseFeatureInitiatingInitializer):
267 """
268 Initializer that implements session establishment for the initiating
269 entity.
270
271 This protocol is defined in U{RFC 3921, section
272 3<http://www.xmpp.org/specs/rfc3921.html#session>}.
273 """
274
275 feature = (NS_XMPP_SESSION, 'session')
276
277 def start(self):
278 iq = xmlstream.IQ(self.xmlstream, 'set')
279 session = iq.addElement((NS_XMPP_SESSION, 'session'))
280 return iq.send()
281
282
283
284 def XMPPClientFactory(jid, password):
285 """
286 Client factory for XMPP 1.0 (only).
287
288 This returns a L{xmlstream.XmlStreamFactory} with an L{XMPPAuthenticator}
289 object to perform the stream initialization steps (such as authentication).
290
291 @see: The notes at L{XMPPAuthenticator} describe how the L{jid} and
292 L{password} parameters are to be used.
293
294 @param jid: Jabber ID to connect with.
295 @type jid: L{jid.JID}
296 @param password: password to authenticate with.
297 @type password: L{unicode}
298 @return: XML stream factory.
299 @rtype: L{xmlstream.XmlStreamFactory}
300 """
301 a = XMPPAuthenticator(jid, password)
302 return xmlstream.XmlStreamFactory(a)
303
304
305
306 class XMPPAuthenticator(xmlstream.ConnectAuthenticator):
307 """
308 Initializes an XmlStream connecting to an XMPP server as a Client.
309
310 This authenticator performs the initialization steps needed to start
311 exchanging XML stanzas with an XMPP server as an XMPP client. It checks if
312 the server advertises XML stream version 1.0, negotiates TLS (when
313 available), performs SASL authentication, binds a resource and establishes
314 a session.
315
316 Upon successful stream initialization, the L{xmlstream.STREAM_AUTHD_EVENT}
317 event will be dispatched through the XML stream object. Otherwise, the
318 L{xmlstream.INIT_FAILED_EVENT} event will be dispatched with a failure
319 object.
320
321 After inspection of the failure, initialization can then be restarted by
322 calling L{initializeStream}. For example, in case of authentication
323 failure, a user may be given the opportunity to input the correct password.
324 By setting the L{password} instance variable and restarting initialization,
325 the stream authentication step is then retried, and subsequent steps are
326 performed if succesful.
327
328 @ivar jid: Jabber ID to authenticate with. This may contain a resource
329 part, as a suggestion to the server for resource binding. A
330 server may override this, though. If the resource part is left
331 off, the server will generate a unique resource identifier.
332 The server will always return the full Jabber ID in the
333 resource binding step, and this is stored in this instance
334 variable.
335 @type jid: L{jid.JID}
336 @ivar password: password to be used during SASL authentication.
337 @type password: L{unicode}
338 """
339
340 namespace = 'jabber:client'
341
342 def __init__(self, jid, password):
343 xmlstream.ConnectAuthenticator.__init__(self, jid.host)
344 self.jid = jid
345 self.password = password
346
347
348 def associateWithStream(self, xs):
349 """
350 Register with the XML stream.
351
352 Populates stream's list of initializers, along with their
353 requiredness. This list is used by
354 L{ConnectAuthenticator.initializeStream} to perform the initalization
355 steps.
356 """
357 xmlstream.ConnectAuthenticator.associateWithStream(self, xs)
358
359 xs.initializers = [CheckVersionInitializer(xs)]
360 inits = [ (xmlstream.TLSInitiatingInitializer, False),
361 (sasl.SASLInitiatingInitializer, True),
362 (BindInitializer, False),
363 (SessionInitializer, False),
364 ]
365
366 for initClass, required in inits:
367 init = initClass(xs)
368 init.required = required
369 xs.initializers.append(init)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698