10e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/*
20e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * libjingle
30e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Copyright 2004--2005, Google Inc.
40e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
50e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Redistribution and use in source and binary forms, with or without
60e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * modification, are permitted provided that the following conditions are met:
70e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
80e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *  1. Redistributions of source code must retain the above copyright notice,
90e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *     this list of conditions and the following disclaimer.
100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *  2. Redistributions in binary form must reproduce the above copyright notice,
110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *     this list of conditions and the following disclaimer in the documentation
120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *     and/or other materials provided with the distribution.
130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *  3. The name of the author may not be used to endorse or promote products
140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *     derived from this software without specific prior written permission.
150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org */
270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/xmpp/xmpplogintask.h"
290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include <string>
310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include <vector>
320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3313b2d035e2e7f2f18e3a4d3377bc1a09f43a4ff9buildbot@webrtc.org#include "webrtc/libjingle/xmllite/xmlelement.h"
340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/xmpp/constants.h"
350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/xmpp/jid.h"
360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/xmpp/saslmechanism.h"
370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/xmpp/xmppengineimpl.h"
38cf81adffe15fa8ea0f333432e41f6d504148f18abuildbot@webrtc.org#include "webrtc/base/base64.h"
39cf81adffe15fa8ea0f333432e41f6d504148f18abuildbot@webrtc.org#include "webrtc/base/common.h"
400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
412a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.orgusing rtc::ConstantLabel;
420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgnamespace buzz {
440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#ifdef _DEBUG
460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgconst ConstantLabel XmppLoginTask::LOGINTASK_STATES[] = {
470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  KLABEL(LOGINSTATE_INIT),
480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  KLABEL(LOGINSTATE_STREAMSTART_SENT),
490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  KLABEL(LOGINSTATE_STARTED_XMPP),
500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  KLABEL(LOGINSTATE_TLS_INIT),
510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  KLABEL(LOGINSTATE_AUTH_INIT),
520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  KLABEL(LOGINSTATE_BIND_INIT),
530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  KLABEL(LOGINSTATE_TLS_REQUESTED),
540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  KLABEL(LOGINSTATE_SASL_RUNNING),
550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  KLABEL(LOGINSTATE_BIND_REQUESTED),
560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  KLABEL(LOGINSTATE_SESSION_REQUESTED),
570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  KLABEL(LOGINSTATE_DONE),
580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  LASTLABEL
590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org};
600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#endif  // _DEBUG
610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgXmppLoginTask::XmppLoginTask(XmppEngineImpl * pctx) :
620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  pctx_(pctx),
630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  authNeeded_(true),
640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  allowNonGoogleLogin_(true),
650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  state_(LOGINSTATE_INIT),
660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  pelStanza_(NULL),
670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  isStart_(false),
680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  iqId_(STR_EMPTY),
695c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org  pelFeatures_(),
700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  fullJid_(STR_EMPTY),
710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  streamId_(STR_EMPTY),
720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  pvecQueuedStanzas_(new std::vector<XmlElement *>()),
735c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org  sasl_mech_() {
740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgXmppLoginTask::~XmppLoginTask() {
770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (size_t i = 0; i < pvecQueuedStanzas_->size(); i += 1)
780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    delete (*pvecQueuedStanzas_)[i];
790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid
820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgXmppLoginTask::IncomingStanza(const XmlElement *element, bool isStart) {
830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  pelStanza_ = element;
840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  isStart_ = isStart;
850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  Advance();
860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  pelStanza_ = NULL;
870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  isStart_ = false;
880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgconst XmlElement *
910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgXmppLoginTask::NextStanza() {
920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  const XmlElement * result = pelStanza_;
930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  pelStanza_ = NULL;
940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return result;
950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool
980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgXmppLoginTask::Advance() {
990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (;;) {
1010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const XmlElement * element = NULL;
1030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#if _DEBUG
1050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_VERBOSE) << "XmppLoginTask::Advance - "
1062a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org      << rtc::ErrorName(state_, LOGINTASK_STATES);
1070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#endif  // _DEBUG
1080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    switch (state_) {
1100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      case LOGINSTATE_INIT: {
1120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        pctx_->RaiseReset();
1130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        pelFeatures_.reset(NULL);
1140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        // The proper domain to verify against is the real underlying
1160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        // domain - i.e., the domain that owns the JID.  Our XmppEngineImpl
1170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        // also allows matching against a proxy domain instead, if it is told
1180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        // to do so - see the implementation of XmppEngineImpl::StartTls and
1190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        // XmppEngine::SetTlsServerDomain to see how you can use that feature
1200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        pctx_->InternalSendStart(pctx_->user_jid_.domain());
1210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        state_ = LOGINSTATE_STREAMSTART_SENT;
1220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        break;
1230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
1240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      case LOGINSTATE_STREAMSTART_SENT: {
1260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (NULL == (element = NextStanza()))
1270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          return true;
1280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (!isStart_ || !HandleStartStream(element))
1300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          return Failure(XmppEngine::ERROR_VERSION);
1310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        state_ = LOGINSTATE_STARTED_XMPP;
1330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        return true;
1340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
1350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      case LOGINSTATE_STARTED_XMPP: {
1370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (NULL == (element = NextStanza()))
1380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          return true;
1390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (!HandleFeatures(element))
1410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          return Failure(XmppEngine::ERROR_VERSION);
1420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        bool tls_present = (GetFeature(QN_TLS_STARTTLS) != NULL);
1440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        // Error if TLS required but not present.
1450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (pctx_->tls_option_ == buzz::TLS_REQUIRED && !tls_present) {
1460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          return Failure(XmppEngine::ERROR_TLS);
1470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        }
1480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        // Use TLS if required or enabled, and also available
1490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if ((pctx_->tls_option_ == buzz::TLS_REQUIRED ||
1500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org            pctx_->tls_option_ == buzz::TLS_ENABLED) && tls_present) {
1510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          state_ = LOGINSTATE_TLS_INIT;
1520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          continue;
1530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        }
1540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (authNeeded_) {
1560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          state_ = LOGINSTATE_AUTH_INIT;
1570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          continue;
1580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        }
1590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        state_ = LOGINSTATE_BIND_INIT;
1610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        continue;
1620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
1630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      case LOGINSTATE_TLS_INIT: {
1650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        const XmlElement * pelTls = GetFeature(QN_TLS_STARTTLS);
1660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (!pelTls)
1670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          return Failure(XmppEngine::ERROR_TLS);
1680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        XmlElement el(QN_TLS_STARTTLS, true);
1700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        pctx_->InternalSendStanza(&el);
1710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        state_ = LOGINSTATE_TLS_REQUESTED;
1720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        continue;
1730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
1740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      case LOGINSTATE_TLS_REQUESTED: {
1760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (NULL == (element = NextStanza()))
1770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          return true;
1780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (element->Name() != QN_TLS_PROCEED)
1790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          return Failure(XmppEngine::ERROR_TLS);
1800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        // The proper domain to verify against is the real underlying
1820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        // domain - i.e., the domain that owns the JID.  Our XmppEngineImpl
1830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        // also allows matching against a proxy domain instead, if it is told
1840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        // to do so - see the implementation of XmppEngineImpl::StartTls and
1850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        // XmppEngine::SetTlsServerDomain to see how you can use that feature
1860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        pctx_->StartTls(pctx_->user_jid_.domain());
1870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        pctx_->tls_option_ = buzz::TLS_ENABLED;
1880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        state_ = LOGINSTATE_INIT;
1890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        continue;
1900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
1910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      case LOGINSTATE_AUTH_INIT: {
1930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        const XmlElement * pelSaslAuth = GetFeature(QN_SASL_MECHANISMS);
1940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (!pelSaslAuth) {
1950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          return Failure(XmppEngine::ERROR_AUTH);
1960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        }
1970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        // Collect together the SASL auth mechanisms presented by the server
1990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        std::vector<std::string> mechanisms;
2000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        for (const XmlElement * pelMech =
2010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org             pelSaslAuth->FirstNamed(QN_SASL_MECHANISM);
2020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org             pelMech;
2030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org             pelMech = pelMech->NextNamed(QN_SASL_MECHANISM)) {
2040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          mechanisms.push_back(pelMech->BodyText());
2060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        }
2070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        // Given all the mechanisms, choose the best
2090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        std::string choice(pctx_->ChooseBestSaslMechanism(mechanisms, pctx_->IsEncrypted()));
2100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (choice.empty()) {
2110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          return Failure(XmppEngine::ERROR_AUTH);
2120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        }
2130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        // No recognized auth mechanism - that's an error
2150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        sasl_mech_.reset(pctx_->GetSaslMechanism(choice));
2160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (!sasl_mech_) {
2170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          return Failure(XmppEngine::ERROR_AUTH);
2180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        }
2190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        // OK, let's start it.
2210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        XmlElement * auth = sasl_mech_->StartSaslAuth();
2220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (auth == NULL) {
2230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          return Failure(XmppEngine::ERROR_AUTH);
2240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        }
2250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (allowNonGoogleLogin_) {
2260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          // Setting the following two attributes is required to support
2270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          // non-google ids.
2280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          // Allow login with non-google id accounts.
2300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          auth->SetAttr(QN_GOOGLE_ALLOW_NON_GOOGLE_ID_XMPP_LOGIN, "true");
2310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          // Allow login with either the non-google id or the friendly email.
2330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          auth->SetAttr(QN_GOOGLE_AUTH_CLIENT_USES_FULL_BIND_RESULT, "true");
2340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        }
2350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        pctx_->InternalSendStanza(auth);
2370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        delete auth;
2380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        state_ = LOGINSTATE_SASL_RUNNING;
2390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        continue;
2400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
2410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      case LOGINSTATE_SASL_RUNNING: {
2430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (NULL == (element = NextStanza()))
2440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          return true;
2450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (element->Name().Namespace() != NS_SASL)
2460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          return Failure(XmppEngine::ERROR_AUTH);
2470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (element->Name() == QN_SASL_CHALLENGE) {
2480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          XmlElement * response = sasl_mech_->HandleSaslChallenge(element);
2490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          if (response == NULL) {
2500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org            return Failure(XmppEngine::ERROR_AUTH);
2510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          }
2520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          pctx_->InternalSendStanza(response);
2530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          delete response;
2540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          state_ = LOGINSTATE_SASL_RUNNING;
2550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          continue;
2560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        }
2570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (element->Name() != QN_SASL_SUCCESS) {
2580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          return Failure(XmppEngine::ERROR_UNAUTHORIZED);
2590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        }
2600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        // Authenticated!
2620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        authNeeded_ = false;
2630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        state_ = LOGINSTATE_INIT;
2640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        continue;
2650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
2660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      case LOGINSTATE_BIND_INIT: {
2680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        const XmlElement * pelBindFeature = GetFeature(QN_BIND_BIND);
2690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        const XmlElement * pelSessionFeature = GetFeature(QN_SESSION_SESSION);
2700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (!pelBindFeature || !pelSessionFeature)
2710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          return Failure(XmppEngine::ERROR_BIND);
2720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        XmlElement iq(QN_IQ);
2740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        iq.AddAttr(QN_TYPE, "set");
2750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        iqId_ = pctx_->NextId();
2770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        iq.AddAttr(QN_ID, iqId_);
2780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        iq.AddElement(new XmlElement(QN_BIND_BIND, true));
2790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (pctx_->requested_resource_ != STR_EMPTY) {
2810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          iq.AddElement(new XmlElement(QN_BIND_RESOURCE), 1);
2820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          iq.AddText(pctx_->requested_resource_, 2);
2830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        }
2840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        pctx_->InternalSendStanza(&iq);
2850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        state_ = LOGINSTATE_BIND_REQUESTED;
2860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        continue;
2870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
2880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      case LOGINSTATE_BIND_REQUESTED: {
2900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (NULL == (element = NextStanza()))
2910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          return true;
2920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (element->Name() != QN_IQ || element->Attr(QN_ID) != iqId_ ||
2940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org            element->Attr(QN_TYPE) == "get" || element->Attr(QN_TYPE) == "set")
2950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          return true;
2960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (element->Attr(QN_TYPE) != "result" || element->FirstElement() == NULL ||
2980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org            element->FirstElement()->Name() != QN_BIND_BIND)
2990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          return Failure(XmppEngine::ERROR_BIND);
3000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        fullJid_ = Jid(element->FirstElement()->TextNamed(QN_BIND_JID));
3020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (!fullJid_.IsFull()) {
3030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          return Failure(XmppEngine::ERROR_BIND);
3040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        }
3050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        // now request session
3070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        XmlElement iq(QN_IQ);
3080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        iq.AddAttr(QN_TYPE, "set");
3090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        iqId_ = pctx_->NextId();
3110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        iq.AddAttr(QN_ID, iqId_);
3120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        iq.AddElement(new XmlElement(QN_SESSION_SESSION, true));
3130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        pctx_->InternalSendStanza(&iq);
3140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        state_ = LOGINSTATE_SESSION_REQUESTED;
3160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        continue;
3170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
3180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      case LOGINSTATE_SESSION_REQUESTED: {
3200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (NULL == (element = NextStanza()))
3210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          return true;
3220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (element->Name() != QN_IQ || element->Attr(QN_ID) != iqId_ ||
3230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org            element->Attr(QN_TYPE) == "get" || element->Attr(QN_TYPE) == "set")
3240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          return false;
3250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (element->Attr(QN_TYPE) != "result")
3270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          return Failure(XmppEngine::ERROR_BIND);
3280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        pctx_->SignalBound(fullJid_);
3300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        FlushQueuedStanzas();
3310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        state_ = LOGINSTATE_DONE;
3320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        return true;
3330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
3340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      case LOGINSTATE_DONE:
3360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        return false;
3370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
3380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
3390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
3400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool
3420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgXmppLoginTask::HandleStartStream(const XmlElement *element) {
3430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (element->Name() != QN_STREAM_STREAM)
3450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
3460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (element->Attr(QN_XMLNS) != "jabber:client")
3480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
3490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (element->Attr(QN_VERSION) != "1.0")
3510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
3520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!element->HasAttr(QN_ID))
3540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
3550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  streamId_ = element->Attr(QN_ID);
3570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
3590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
3600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool
3620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgXmppLoginTask::HandleFeatures(const XmlElement *element) {
3630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (element->Name() != QN_STREAM_FEATURES)
3640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
3650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  pelFeatures_.reset(new XmlElement(*element));
3670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
3680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
3690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgconst XmlElement *
3710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgXmppLoginTask::GetFeature(const QName & name) {
3720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return pelFeatures_->FirstNamed(name);
3730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
3740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool
3760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgXmppLoginTask::Failure(XmppEngine::Error reason) {
3770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  state_ = LOGINSTATE_DONE;
3780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  pctx_->SignalError(reason, 0);
3790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return false;
3800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
3810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid
3830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgXmppLoginTask::OutgoingStanza(const XmlElement * element) {
3840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  XmlElement * pelCopy = new XmlElement(*element);
3850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  pvecQueuedStanzas_->push_back(pelCopy);
3860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
3870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid
3890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgXmppLoginTask::FlushQueuedStanzas() {
3900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (size_t i = 0; i < pvecQueuedStanzas_->size(); i += 1) {
3910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    pctx_->InternalSendStanza((*pvecQueuedStanzas_)[i]);
3920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    delete (*pvecQueuedStanzas_)[i];
3930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
3940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  pvecQueuedStanzas_->clear();
3950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
3960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
398