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

Side by Side Diff: third_party/libjingle_xmpp/xmpp/xmpplogintask.cc

Issue 2443903004: Add xmllite and xmpp sources to third_party/ (Closed)
Patch Set: Explicitly use webrtc_overrides/webrtc/base/logging.h Created 3 years, 11 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
OLDNEW
(Empty)
1 /*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "third_party/libjingle_xmpp/xmpp/xmpplogintask.h"
12
13 #include <string>
14 #include <vector>
15
16 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
17 #include "third_party/libjingle_xmpp/xmpp/constants.h"
18 #include "third_party/libjingle_xmpp/xmpp/jid.h"
19 #include "third_party/libjingle_xmpp/xmpp/saslmechanism.h"
20 #include "third_party/libjingle_xmpp/xmpp/xmppengineimpl.h"
21 #include "third_party/webrtc/base/base64.h"
22 #include "third_party/webrtc/base/common.h"
23
24 using rtc::ConstantLabel;
25
26 namespace buzz {
27
28 #if !defined(NDEBUG)
29 const ConstantLabel XmppLoginTask::LOGINTASK_STATES[] = {
30 KLABEL(LOGINSTATE_INIT),
31 KLABEL(LOGINSTATE_STREAMSTART_SENT),
32 KLABEL(LOGINSTATE_STARTED_XMPP),
33 KLABEL(LOGINSTATE_TLS_INIT),
34 KLABEL(LOGINSTATE_AUTH_INIT),
35 KLABEL(LOGINSTATE_BIND_INIT),
36 KLABEL(LOGINSTATE_TLS_REQUESTED),
37 KLABEL(LOGINSTATE_SASL_RUNNING),
38 KLABEL(LOGINSTATE_BIND_REQUESTED),
39 KLABEL(LOGINSTATE_SESSION_REQUESTED),
40 KLABEL(LOGINSTATE_DONE),
41 LASTLABEL
42 };
43 #endif
44 XmppLoginTask::XmppLoginTask(XmppEngineImpl * pctx) :
45 pctx_(pctx),
46 authNeeded_(true),
47 allowNonGoogleLogin_(true),
48 state_(LOGINSTATE_INIT),
49 pelStanza_(NULL),
50 isStart_(false),
51 iqId_(STR_EMPTY),
52 pelFeatures_(),
53 fullJid_(STR_EMPTY),
54 streamId_(STR_EMPTY),
55 pvecQueuedStanzas_(new std::vector<XmlElement *>()),
56 sasl_mech_() {
57 }
58
59 XmppLoginTask::~XmppLoginTask() {
60 for (size_t i = 0; i < pvecQueuedStanzas_->size(); i += 1)
61 delete (*pvecQueuedStanzas_)[i];
62 }
63
64 void
65 XmppLoginTask::IncomingStanza(const XmlElement *element, bool isStart) {
66 pelStanza_ = element;
67 isStart_ = isStart;
68 Advance();
69 pelStanza_ = NULL;
70 isStart_ = false;
71 }
72
73 const XmlElement *
74 XmppLoginTask::NextStanza() {
75 const XmlElement * result = pelStanza_;
76 pelStanza_ = NULL;
77 return result;
78 }
79
80 bool
81 XmppLoginTask::Advance() {
82
83 for (;;) {
84
85 const XmlElement * element = NULL;
86
87 #if !defined(NDEBUG)
88 LOG(LS_VERBOSE) << "XmppLoginTask::Advance - "
89 << rtc::ErrorName(state_, LOGINTASK_STATES);
90 #endif
91
92 switch (state_) {
93
94 case LOGINSTATE_INIT: {
95 pctx_->RaiseReset();
96 pelFeatures_.reset(NULL);
97
98 // The proper domain to verify against is the real underlying
99 // domain - i.e., the domain that owns the JID. Our XmppEngineImpl
100 // also allows matching against a proxy domain instead, if it is told
101 // to do so - see the implementation of XmppEngineImpl::StartTls and
102 // XmppEngine::SetTlsServerDomain to see how you can use that feature
103 pctx_->InternalSendStart(pctx_->user_jid_.domain());
104 state_ = LOGINSTATE_STREAMSTART_SENT;
105 break;
106 }
107
108 case LOGINSTATE_STREAMSTART_SENT: {
109 if (NULL == (element = NextStanza()))
110 return true;
111
112 if (!isStart_ || !HandleStartStream(element))
113 return Failure(XmppEngine::ERROR_VERSION);
114
115 state_ = LOGINSTATE_STARTED_XMPP;
116 return true;
117 }
118
119 case LOGINSTATE_STARTED_XMPP: {
120 if (NULL == (element = NextStanza()))
121 return true;
122
123 if (!HandleFeatures(element))
124 return Failure(XmppEngine::ERROR_VERSION);
125
126 bool tls_present = (GetFeature(QN_TLS_STARTTLS) != NULL);
127 // Error if TLS required but not present.
128 if (pctx_->tls_option_ == buzz::TLS_REQUIRED && !tls_present) {
129 return Failure(XmppEngine::ERROR_TLS);
130 }
131 // Use TLS if required or enabled, and also available
132 if ((pctx_->tls_option_ == buzz::TLS_REQUIRED ||
133 pctx_->tls_option_ == buzz::TLS_ENABLED) && tls_present) {
134 state_ = LOGINSTATE_TLS_INIT;
135 continue;
136 }
137
138 if (authNeeded_) {
139 state_ = LOGINSTATE_AUTH_INIT;
140 continue;
141 }
142
143 state_ = LOGINSTATE_BIND_INIT;
144 continue;
145 }
146
147 case LOGINSTATE_TLS_INIT: {
148 const XmlElement * pelTls = GetFeature(QN_TLS_STARTTLS);
149 if (!pelTls)
150 return Failure(XmppEngine::ERROR_TLS);
151
152 XmlElement el(QN_TLS_STARTTLS, true);
153 pctx_->InternalSendStanza(&el);
154 state_ = LOGINSTATE_TLS_REQUESTED;
155 continue;
156 }
157
158 case LOGINSTATE_TLS_REQUESTED: {
159 if (NULL == (element = NextStanza()))
160 return true;
161 if (element->Name() != QN_TLS_PROCEED)
162 return Failure(XmppEngine::ERROR_TLS);
163
164 // The proper domain to verify against is the real underlying
165 // domain - i.e., the domain that owns the JID. Our XmppEngineImpl
166 // also allows matching against a proxy domain instead, if it is told
167 // to do so - see the implementation of XmppEngineImpl::StartTls and
168 // XmppEngine::SetTlsServerDomain to see how you can use that feature
169 pctx_->StartTls(pctx_->user_jid_.domain());
170 pctx_->tls_option_ = buzz::TLS_ENABLED;
171 state_ = LOGINSTATE_INIT;
172 continue;
173 }
174
175 case LOGINSTATE_AUTH_INIT: {
176 const XmlElement * pelSaslAuth = GetFeature(QN_SASL_MECHANISMS);
177 if (!pelSaslAuth) {
178 return Failure(XmppEngine::ERROR_AUTH);
179 }
180
181 // Collect together the SASL auth mechanisms presented by the server
182 std::vector<std::string> mechanisms;
183 for (const XmlElement * pelMech =
184 pelSaslAuth->FirstNamed(QN_SASL_MECHANISM);
185 pelMech;
186 pelMech = pelMech->NextNamed(QN_SASL_MECHANISM)) {
187
188 mechanisms.push_back(pelMech->BodyText());
189 }
190
191 // Given all the mechanisms, choose the best
192 std::string choice(pctx_->ChooseBestSaslMechanism(mechanisms, pctx_->IsE ncrypted()));
193 if (choice.empty()) {
194 return Failure(XmppEngine::ERROR_AUTH);
195 }
196
197 // No recognized auth mechanism - that's an error
198 sasl_mech_.reset(pctx_->GetSaslMechanism(choice));
199 if (!sasl_mech_) {
200 return Failure(XmppEngine::ERROR_AUTH);
201 }
202
203 // OK, let's start it.
204 XmlElement * auth = sasl_mech_->StartSaslAuth();
205 if (auth == NULL) {
206 return Failure(XmppEngine::ERROR_AUTH);
207 }
208 if (allowNonGoogleLogin_) {
209 // Setting the following two attributes is required to support
210 // non-google ids.
211
212 // Allow login with non-google id accounts.
213 auth->SetAttr(QN_GOOGLE_ALLOW_NON_GOOGLE_ID_XMPP_LOGIN, "true");
214
215 // Allow login with either the non-google id or the friendly email.
216 auth->SetAttr(QN_GOOGLE_AUTH_CLIENT_USES_FULL_BIND_RESULT, "true");
217 }
218
219 pctx_->InternalSendStanza(auth);
220 delete auth;
221 state_ = LOGINSTATE_SASL_RUNNING;
222 continue;
223 }
224
225 case LOGINSTATE_SASL_RUNNING: {
226 if (NULL == (element = NextStanza()))
227 return true;
228 if (element->Name().Namespace() != NS_SASL)
229 return Failure(XmppEngine::ERROR_AUTH);
230 if (element->Name() == QN_SASL_CHALLENGE) {
231 XmlElement * response = sasl_mech_->HandleSaslChallenge(element);
232 if (response == NULL) {
233 return Failure(XmppEngine::ERROR_AUTH);
234 }
235 pctx_->InternalSendStanza(response);
236 delete response;
237 state_ = LOGINSTATE_SASL_RUNNING;
238 continue;
239 }
240 if (element->Name() != QN_SASL_SUCCESS) {
241 return Failure(XmppEngine::ERROR_UNAUTHORIZED);
242 }
243
244 // Authenticated!
245 authNeeded_ = false;
246 state_ = LOGINSTATE_INIT;
247 continue;
248 }
249
250 case LOGINSTATE_BIND_INIT: {
251 const XmlElement * pelBindFeature = GetFeature(QN_BIND_BIND);
252 const XmlElement * pelSessionFeature = GetFeature(QN_SESSION_SESSION);
253 if (!pelBindFeature || !pelSessionFeature)
254 return Failure(XmppEngine::ERROR_BIND);
255
256 XmlElement iq(QN_IQ);
257 iq.AddAttr(QN_TYPE, "set");
258
259 iqId_ = pctx_->NextId();
260 iq.AddAttr(QN_ID, iqId_);
261 iq.AddElement(new XmlElement(QN_BIND_BIND, true));
262
263 if (pctx_->requested_resource_ != STR_EMPTY) {
264 iq.AddElement(new XmlElement(QN_BIND_RESOURCE), 1);
265 iq.AddText(pctx_->requested_resource_, 2);
266 }
267 pctx_->InternalSendStanza(&iq);
268 state_ = LOGINSTATE_BIND_REQUESTED;
269 continue;
270 }
271
272 case LOGINSTATE_BIND_REQUESTED: {
273 if (NULL == (element = NextStanza()))
274 return true;
275
276 if (element->Name() != QN_IQ || element->Attr(QN_ID) != iqId_ ||
277 element->Attr(QN_TYPE) == "get" || element->Attr(QN_TYPE) == "set")
278 return true;
279
280 if (element->Attr(QN_TYPE) != "result" || element->FirstElement() == NUL L ||
281 element->FirstElement()->Name() != QN_BIND_BIND)
282 return Failure(XmppEngine::ERROR_BIND);
283
284 fullJid_ = Jid(element->FirstElement()->TextNamed(QN_BIND_JID));
285 if (!fullJid_.IsFull()) {
286 return Failure(XmppEngine::ERROR_BIND);
287 }
288
289 // now request session
290 XmlElement iq(QN_IQ);
291 iq.AddAttr(QN_TYPE, "set");
292
293 iqId_ = pctx_->NextId();
294 iq.AddAttr(QN_ID, iqId_);
295 iq.AddElement(new XmlElement(QN_SESSION_SESSION, true));
296 pctx_->InternalSendStanza(&iq);
297
298 state_ = LOGINSTATE_SESSION_REQUESTED;
299 continue;
300 }
301
302 case LOGINSTATE_SESSION_REQUESTED: {
303 if (NULL == (element = NextStanza()))
304 return true;
305 if (element->Name() != QN_IQ || element->Attr(QN_ID) != iqId_ ||
306 element->Attr(QN_TYPE) == "get" || element->Attr(QN_TYPE) == "set")
307 return false;
308
309 if (element->Attr(QN_TYPE) != "result")
310 return Failure(XmppEngine::ERROR_BIND);
311
312 pctx_->SignalBound(fullJid_);
313 FlushQueuedStanzas();
314 state_ = LOGINSTATE_DONE;
315 return true;
316 }
317
318 case LOGINSTATE_DONE:
319 return false;
320 }
321 }
322 }
323
324 bool
325 XmppLoginTask::HandleStartStream(const XmlElement *element) {
326
327 if (element->Name() != QN_STREAM_STREAM)
328 return false;
329
330 if (element->Attr(QN_XMLNS) != "jabber:client")
331 return false;
332
333 if (element->Attr(QN_VERSION) != "1.0")
334 return false;
335
336 if (!element->HasAttr(QN_ID))
337 return false;
338
339 streamId_ = element->Attr(QN_ID);
340
341 return true;
342 }
343
344 bool
345 XmppLoginTask::HandleFeatures(const XmlElement *element) {
346 if (element->Name() != QN_STREAM_FEATURES)
347 return false;
348
349 pelFeatures_.reset(new XmlElement(*element));
350 return true;
351 }
352
353 const XmlElement *
354 XmppLoginTask::GetFeature(const QName & name) {
355 return pelFeatures_->FirstNamed(name);
356 }
357
358 bool
359 XmppLoginTask::Failure(XmppEngine::Error reason) {
360 state_ = LOGINSTATE_DONE;
361 pctx_->SignalError(reason, 0);
362 return false;
363 }
364
365 void
366 XmppLoginTask::OutgoingStanza(const XmlElement * element) {
367 XmlElement * pelCopy = new XmlElement(*element);
368 pvecQueuedStanzas_->push_back(pelCopy);
369 }
370
371 void
372 XmppLoginTask::FlushQueuedStanzas() {
373 for (size_t i = 0; i < pvecQueuedStanzas_->size(); i += 1) {
374 pctx_->InternalSendStanza((*pvecQueuedStanzas_)[i]);
375 delete (*pvecQueuedStanzas_)[i];
376 }
377 pvecQueuedStanzas_->clear();
378 }
379
380 }
OLDNEW
« no previous file with comments | « third_party/libjingle_xmpp/xmpp/xmpplogintask.h ('k') | third_party/libjingle_xmpp/xmpp/xmpplogintask_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698