1269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org/*
2269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org *
4269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org *  Use of this source code is governed by a BSD-style license
5269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org *  that can be found in the LICENSE file in the root of the source
6269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org *  tree. An additional intellectual property rights grant can be found
7269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org *  in the file PATENTS.  All contributing project authors may
8269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org */
10269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
11269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/libjingle/xmpp/xmpplogintask.h"
12269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
13269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include <string>
14269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include <vector>
15269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
16269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/libjingle/xmllite/xmlelement.h"
17269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/libjingle/xmpp/constants.h"
18269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/libjingle/xmpp/jid.h"
19269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/libjingle/xmpp/saslmechanism.h"
20269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/libjingle/xmpp/xmppengineimpl.h"
21269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/base/base64.h"
22269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org#include "webrtc/base/common.h"
23269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
24269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgusing rtc::ConstantLabel;
25269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
26269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgnamespace buzz {
27269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
28a41ab9326c8f0f7eb738e5d51a239a2b9e276361tfarina#if !defined(NDEBUG)
29269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgconst ConstantLabel XmppLoginTask::LOGINTASK_STATES[] = {
30269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  KLABEL(LOGINSTATE_INIT),
31269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  KLABEL(LOGINSTATE_STREAMSTART_SENT),
32269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  KLABEL(LOGINSTATE_STARTED_XMPP),
33269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  KLABEL(LOGINSTATE_TLS_INIT),
34269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  KLABEL(LOGINSTATE_AUTH_INIT),
35269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  KLABEL(LOGINSTATE_BIND_INIT),
36269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  KLABEL(LOGINSTATE_TLS_REQUESTED),
37269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  KLABEL(LOGINSTATE_SASL_RUNNING),
38269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  KLABEL(LOGINSTATE_BIND_REQUESTED),
39269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  KLABEL(LOGINSTATE_SESSION_REQUESTED),
40269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  KLABEL(LOGINSTATE_DONE),
41269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  LASTLABEL
42269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org};
43a41ab9326c8f0f7eb738e5d51a239a2b9e276361tfarina#endif
44269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgXmppLoginTask::XmppLoginTask(XmppEngineImpl * pctx) :
45269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  pctx_(pctx),
46269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  authNeeded_(true),
47269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  allowNonGoogleLogin_(true),
48269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  state_(LOGINSTATE_INIT),
49269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  pelStanza_(NULL),
50269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  isStart_(false),
51269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  iqId_(STR_EMPTY),
52269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  pelFeatures_(),
53269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  fullJid_(STR_EMPTY),
54269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  streamId_(STR_EMPTY),
55269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  pvecQueuedStanzas_(new std::vector<XmlElement *>()),
56269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  sasl_mech_() {
57269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
58269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
59269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgXmppLoginTask::~XmppLoginTask() {
60269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  for (size_t i = 0; i < pvecQueuedStanzas_->size(); i += 1)
61269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    delete (*pvecQueuedStanzas_)[i];
62269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
63269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
64269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid
65269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgXmppLoginTask::IncomingStanza(const XmlElement *element, bool isStart) {
66269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  pelStanza_ = element;
67269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  isStart_ = isStart;
68269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  Advance();
69269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  pelStanza_ = NULL;
70269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  isStart_ = false;
71269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
72269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
73269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgconst XmlElement *
74269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgXmppLoginTask::NextStanza() {
75269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  const XmlElement * result = pelStanza_;
76269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  pelStanza_ = NULL;
77269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return result;
78269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
79269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
80269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgbool
81269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgXmppLoginTask::Advance() {
82269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
83269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  for (;;) {
84269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
85269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    const XmlElement * element = NULL;
86269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
87a41ab9326c8f0f7eb738e5d51a239a2b9e276361tfarina#if !defined(NDEBUG)
88269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    LOG(LS_VERBOSE) << "XmppLoginTask::Advance - "
89269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      << rtc::ErrorName(state_, LOGINTASK_STATES);
90a41ab9326c8f0f7eb738e5d51a239a2b9e276361tfarina#endif
91269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
92269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    switch (state_) {
93269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
94269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      case LOGINSTATE_INIT: {
95269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        pctx_->RaiseReset();
96269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        pelFeatures_.reset(NULL);
97269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
98269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        // The proper domain to verify against is the real underlying
99269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        // domain - i.e., the domain that owns the JID.  Our XmppEngineImpl
100269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        // also allows matching against a proxy domain instead, if it is told
101269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        // to do so - see the implementation of XmppEngineImpl::StartTls and
102269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        // XmppEngine::SetTlsServerDomain to see how you can use that feature
103269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        pctx_->InternalSendStart(pctx_->user_jid_.domain());
104269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        state_ = LOGINSTATE_STREAMSTART_SENT;
105269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        break;
106269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      }
107269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
108269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      case LOGINSTATE_STREAMSTART_SENT: {
109269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (NULL == (element = NextStanza()))
110269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          return true;
111269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
112269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (!isStart_ || !HandleStartStream(element))
113269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          return Failure(XmppEngine::ERROR_VERSION);
114269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
115269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        state_ = LOGINSTATE_STARTED_XMPP;
116269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        return true;
117269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      }
118269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
119269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      case LOGINSTATE_STARTED_XMPP: {
120269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (NULL == (element = NextStanza()))
121269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          return true;
122269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
123269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (!HandleFeatures(element))
124269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          return Failure(XmppEngine::ERROR_VERSION);
125269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
126269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        bool tls_present = (GetFeature(QN_TLS_STARTTLS) != NULL);
127269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        // Error if TLS required but not present.
128269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (pctx_->tls_option_ == buzz::TLS_REQUIRED && !tls_present) {
129269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          return Failure(XmppEngine::ERROR_TLS);
130269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        }
131269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        // Use TLS if required or enabled, and also available
132269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if ((pctx_->tls_option_ == buzz::TLS_REQUIRED ||
133269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org            pctx_->tls_option_ == buzz::TLS_ENABLED) && tls_present) {
134269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          state_ = LOGINSTATE_TLS_INIT;
135269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          continue;
136269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        }
137269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
138269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (authNeeded_) {
139269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          state_ = LOGINSTATE_AUTH_INIT;
140269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          continue;
141269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        }
142269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
143269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        state_ = LOGINSTATE_BIND_INIT;
144269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        continue;
145269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      }
146269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
147269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      case LOGINSTATE_TLS_INIT: {
148269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        const XmlElement * pelTls = GetFeature(QN_TLS_STARTTLS);
149269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (!pelTls)
150269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          return Failure(XmppEngine::ERROR_TLS);
151269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
152269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        XmlElement el(QN_TLS_STARTTLS, true);
153269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        pctx_->InternalSendStanza(&el);
154269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        state_ = LOGINSTATE_TLS_REQUESTED;
155269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        continue;
156269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      }
157269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
158269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      case LOGINSTATE_TLS_REQUESTED: {
159269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (NULL == (element = NextStanza()))
160269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          return true;
161269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (element->Name() != QN_TLS_PROCEED)
162269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          return Failure(XmppEngine::ERROR_TLS);
163269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
164269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        // The proper domain to verify against is the real underlying
165269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        // domain - i.e., the domain that owns the JID.  Our XmppEngineImpl
166269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        // also allows matching against a proxy domain instead, if it is told
167269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        // to do so - see the implementation of XmppEngineImpl::StartTls and
168269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        // XmppEngine::SetTlsServerDomain to see how you can use that feature
169269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        pctx_->StartTls(pctx_->user_jid_.domain());
170269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        pctx_->tls_option_ = buzz::TLS_ENABLED;
171269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        state_ = LOGINSTATE_INIT;
172269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        continue;
173269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      }
174269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
175269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      case LOGINSTATE_AUTH_INIT: {
176269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        const XmlElement * pelSaslAuth = GetFeature(QN_SASL_MECHANISMS);
177269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (!pelSaslAuth) {
178269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          return Failure(XmppEngine::ERROR_AUTH);
179269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        }
180269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
181269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        // Collect together the SASL auth mechanisms presented by the server
182269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        std::vector<std::string> mechanisms;
183269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        for (const XmlElement * pelMech =
184269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org             pelSaslAuth->FirstNamed(QN_SASL_MECHANISM);
185269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org             pelMech;
186269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org             pelMech = pelMech->NextNamed(QN_SASL_MECHANISM)) {
187269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
188269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          mechanisms.push_back(pelMech->BodyText());
189269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        }
190269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
191269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        // Given all the mechanisms, choose the best
192269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        std::string choice(pctx_->ChooseBestSaslMechanism(mechanisms, pctx_->IsEncrypted()));
193269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (choice.empty()) {
194269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          return Failure(XmppEngine::ERROR_AUTH);
195269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        }
196269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
197269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        // No recognized auth mechanism - that's an error
198269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        sasl_mech_.reset(pctx_->GetSaslMechanism(choice));
199269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (!sasl_mech_) {
200269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          return Failure(XmppEngine::ERROR_AUTH);
201269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        }
202269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
203269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        // OK, let's start it.
204269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        XmlElement * auth = sasl_mech_->StartSaslAuth();
205269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (auth == NULL) {
206269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          return Failure(XmppEngine::ERROR_AUTH);
207269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        }
208269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (allowNonGoogleLogin_) {
209269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          // Setting the following two attributes is required to support
210269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          // non-google ids.
211269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
212269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          // Allow login with non-google id accounts.
213269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          auth->SetAttr(QN_GOOGLE_ALLOW_NON_GOOGLE_ID_XMPP_LOGIN, "true");
214269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
215269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          // Allow login with either the non-google id or the friendly email.
216269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          auth->SetAttr(QN_GOOGLE_AUTH_CLIENT_USES_FULL_BIND_RESULT, "true");
217269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        }
218269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
219269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        pctx_->InternalSendStanza(auth);
220269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        delete auth;
221269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        state_ = LOGINSTATE_SASL_RUNNING;
222269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        continue;
223269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      }
224269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
225269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      case LOGINSTATE_SASL_RUNNING: {
226269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (NULL == (element = NextStanza()))
227269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          return true;
228269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (element->Name().Namespace() != NS_SASL)
229269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          return Failure(XmppEngine::ERROR_AUTH);
230269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (element->Name() == QN_SASL_CHALLENGE) {
231269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          XmlElement * response = sasl_mech_->HandleSaslChallenge(element);
232269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          if (response == NULL) {
233269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org            return Failure(XmppEngine::ERROR_AUTH);
234269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          }
235269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          pctx_->InternalSendStanza(response);
236269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          delete response;
237269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          state_ = LOGINSTATE_SASL_RUNNING;
238269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          continue;
239269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        }
240269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (element->Name() != QN_SASL_SUCCESS) {
241269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          return Failure(XmppEngine::ERROR_UNAUTHORIZED);
242269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        }
243269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
244269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        // Authenticated!
245269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        authNeeded_ = false;
246269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        state_ = LOGINSTATE_INIT;
247269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        continue;
248269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      }
249269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
250269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      case LOGINSTATE_BIND_INIT: {
251269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        const XmlElement * pelBindFeature = GetFeature(QN_BIND_BIND);
252269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        const XmlElement * pelSessionFeature = GetFeature(QN_SESSION_SESSION);
253269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (!pelBindFeature || !pelSessionFeature)
254269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          return Failure(XmppEngine::ERROR_BIND);
255269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
256269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        XmlElement iq(QN_IQ);
257269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        iq.AddAttr(QN_TYPE, "set");
258269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
259269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        iqId_ = pctx_->NextId();
260269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        iq.AddAttr(QN_ID, iqId_);
261269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        iq.AddElement(new XmlElement(QN_BIND_BIND, true));
262269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
263269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (pctx_->requested_resource_ != STR_EMPTY) {
264269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          iq.AddElement(new XmlElement(QN_BIND_RESOURCE), 1);
265269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          iq.AddText(pctx_->requested_resource_, 2);
266269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        }
267269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        pctx_->InternalSendStanza(&iq);
268269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        state_ = LOGINSTATE_BIND_REQUESTED;
269269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        continue;
270269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      }
271269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
272269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      case LOGINSTATE_BIND_REQUESTED: {
273269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (NULL == (element = NextStanza()))
274269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          return true;
275269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
276269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (element->Name() != QN_IQ || element->Attr(QN_ID) != iqId_ ||
277269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org            element->Attr(QN_TYPE) == "get" || element->Attr(QN_TYPE) == "set")
278269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          return true;
279269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
280269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (element->Attr(QN_TYPE) != "result" || element->FirstElement() == NULL ||
281269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org            element->FirstElement()->Name() != QN_BIND_BIND)
282269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          return Failure(XmppEngine::ERROR_BIND);
283269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
284269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        fullJid_ = Jid(element->FirstElement()->TextNamed(QN_BIND_JID));
285269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (!fullJid_.IsFull()) {
286269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          return Failure(XmppEngine::ERROR_BIND);
287269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        }
288269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
289269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        // now request session
290269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        XmlElement iq(QN_IQ);
291269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        iq.AddAttr(QN_TYPE, "set");
292269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
293269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        iqId_ = pctx_->NextId();
294269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        iq.AddAttr(QN_ID, iqId_);
295269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        iq.AddElement(new XmlElement(QN_SESSION_SESSION, true));
296269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        pctx_->InternalSendStanza(&iq);
297269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
298269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        state_ = LOGINSTATE_SESSION_REQUESTED;
299269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        continue;
300269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      }
301269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
302269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      case LOGINSTATE_SESSION_REQUESTED: {
303269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (NULL == (element = NextStanza()))
304269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          return true;
305269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (element->Name() != QN_IQ || element->Attr(QN_ID) != iqId_ ||
306269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org            element->Attr(QN_TYPE) == "get" || element->Attr(QN_TYPE) == "set")
307269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          return false;
308269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
309269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        if (element->Attr(QN_TYPE) != "result")
310269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org          return Failure(XmppEngine::ERROR_BIND);
311269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
312269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        pctx_->SignalBound(fullJid_);
313269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        FlushQueuedStanzas();
314269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        state_ = LOGINSTATE_DONE;
315269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        return true;
316269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      }
317269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
318269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org      case LOGINSTATE_DONE:
319269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org        return false;
320269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    }
321269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
322269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
323269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
324269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgbool
325269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgXmppLoginTask::HandleStartStream(const XmlElement *element) {
326269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
327269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (element->Name() != QN_STREAM_STREAM)
328269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return false;
329269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
330269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (element->Attr(QN_XMLNS) != "jabber:client")
331269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return false;
332269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
333269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (element->Attr(QN_VERSION) != "1.0")
334269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return false;
335269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
336269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (!element->HasAttr(QN_ID))
337269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return false;
338269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
339269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  streamId_ = element->Attr(QN_ID);
340269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
341269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return true;
342269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
343269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
344269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgbool
345269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgXmppLoginTask::HandleFeatures(const XmlElement *element) {
346269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  if (element->Name() != QN_STREAM_FEATURES)
347269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    return false;
348269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
349269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  pelFeatures_.reset(new XmlElement(*element));
350269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return true;
351269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
352269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
353269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgconst XmlElement *
354269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgXmppLoginTask::GetFeature(const QName & name) {
355269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return pelFeatures_->FirstNamed(name);
356269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
357269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
358269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgbool
359269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgXmppLoginTask::Failure(XmppEngine::Error reason) {
360269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  state_ = LOGINSTATE_DONE;
361269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  pctx_->SignalError(reason, 0);
362269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  return false;
363269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
364269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
365269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid
366269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgXmppLoginTask::OutgoingStanza(const XmlElement * element) {
367269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  XmlElement * pelCopy = new XmlElement(*element);
368269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  pvecQueuedStanzas_->push_back(pelCopy);
369269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
370269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
371269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgvoid
372269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.orgXmppLoginTask::FlushQueuedStanzas() {
373269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  for (size_t i = 0; i < pvecQueuedStanzas_->size(); i += 1) {
374269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    pctx_->InternalSendStanza((*pvecQueuedStanzas_)[i]);
375269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org    delete (*pvecQueuedStanzas_)[i];
376269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  }
377269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org  pvecQueuedStanzas_->clear();
378269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
379269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org
380269fb4bc90b79bebbb8311da0110ccd6803fd0a8henrike@webrtc.org}
381