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

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

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

Powered by Google App Engine
This is Rietveld 408576698