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

Unified Diff: remoting/signaling/xmpp_login_handler.cc

Issue 958703003: Remove dependency on XMPP implementation in WebRTC (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: remoting/signaling/xmpp_login_handler.cc
diff --git a/remoting/signaling/xmpp_login_handler.cc b/remoting/signaling/xmpp_login_handler.cc
new file mode 100644
index 0000000000000000000000000000000000000000..948e2fab46b2d0c625aa9b0cb9b9099982637dbf
--- /dev/null
+++ b/remoting/signaling/xmpp_login_handler.cc
@@ -0,0 +1,221 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "remoting/signaling/xmpp_login_handler.h"
+
+#include <set>
+
+#include "base/base64.h"
+#include "base/bind.h"
+#include "base/logging.h"
+#include "remoting/signaling/xmpp_stream_parser.h"
+#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
+
+namespace remoting {
+
+buzz::StaticQName kXmppIqName = {"jabber:client", "iq"};
+
+char kXmppBindNs[] = "urn:ietf:params:xml:ns:xmpp-bind";
+buzz::StaticQName kXmppBindName = {kXmppBindNs, "bind"};
+buzz::StaticQName kXmppJidName = {kXmppBindNs, "jid"};
+
+buzz::StaticQName kJabberFeaturesName = {"http://etherx.jabber.org/streams",
+ "features"};
+
+char kXmppTlsNs[] = "urn:ietf:params:xml:ns:xmpp-tls";
+buzz::StaticQName kStartTlsName = {kXmppTlsNs, "starttls"};
+buzz::StaticQName kTlsProceedName = {kXmppTlsNs, "proceed"};
+
+char kXmppSaslNs[] = "urn:ietf:params:xml:ns:xmpp-sasl";
+buzz::StaticQName kSaslMechanismsName = {kXmppSaslNs, "mechanisms"};
+buzz::StaticQName kSaslMechanismName = {kXmppSaslNs, "mechanism"};
+buzz::StaticQName kSaslSuccessName = {kXmppSaslNs, "success"};
+
+XmppLoginHandler::XmppLoginHandler(const std::string& server,
+ const std::string& username,
+ const std::string& auth_token,
+ const std::string& auth_service,
+ bool need_handshake_before_tls,
+ Delegate* delegate)
+ : server_(server),
+ username_(username),
+ auth_token_(auth_token),
+ auth_service_(auth_service),
+ auth_mechanism_((auth_service == "oauth2") ? "X-OAUTH2"
rmsousa 2015/02/28 06:33:29 nit: if this is for client login, it can be remove
Sergey Ulanov 2015/03/02 18:11:09 Done.
+ : "X-GOOGLE-TOKEN"),
+ need_handshake_before_tls_(need_handshake_before_tls),
+ delegate_(delegate),
+ state_(State::INIT) {
+}
+
+XmppLoginHandler::~XmppLoginHandler() {
+}
+
+void XmppLoginHandler::Start() {
+ if (need_handshake_before_tls_) {
+ state_ = State::WAIT_STREAM_HEADER;
+ StartStream("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>");
+ } else {
+ // If <starttls> handshake is not required then start TLS right away.
+ state_ = State::STARTING_TLS;
+ delegate_->StartTls();
+ }
+}
+
+void XmppLoginHandler::OnDataReceived(const std::string& data) {
+ DCHECK(state_ != State::INIT && state_ != State::DONE &&
+ state_ != State::ERROR);
+ stream_parser_->AppendData(data);
+}
+
+void XmppLoginHandler::OnStanza(scoped_ptr<buzz::XmlElement> stanza) {
+ switch (state_) {
+ case State::WAIT_STREAM_HEADER: {
+ if (stanza->Name() == kJabberFeaturesName &&
+ stanza->FirstNamed(kStartTlsName) != nullptr) {
+ state_ = State::WAIT_STARTTLS_RESPONSE;
+ } else {
+ LOG(ERROR) << "Server doesn't support TLS.";
+ OnError(SignalStrategy::PROTOCOL_ERROR);
+ }
+ break;
+ }
+
+ case State::WAIT_STARTTLS_RESPONSE: {
+ if (stanza->Name() == kTlsProceedName) {
+ state_ = State::STARTING_TLS;
+ delegate_->StartTls();
+ } else {
+ LOG(ERROR) << "Failed to start TLS: " << stanza->Str();
+ OnError(SignalStrategy::PROTOCOL_ERROR);
+ }
+ break;
+ }
+
+ case State::WAIT_STREAM_HEADER_AFTER_TLS: {
+ buzz::XmlElement* mechanisms_element =
+ stanza->FirstNamed(kSaslMechanismsName);
+ std::set<std::string> mechanisms;
+ if (mechanisms_element) {
+ for (buzz::XmlElement* element =
+ mechanisms_element->FirstNamed(kSaslMechanismName);
+ element; element = element->NextNamed(kSaslMechanismName)) {
+ mechanisms.insert(element->BodyText());
+ }
+ }
+
+ if (mechanisms.find(auth_mechanism_) == mechanisms.end()) {
+ LOG(ERROR) << auth_mechanism_
+ << " auth mechanism is not supported by the server.";
+ OnError(SignalStrategy::PROTOCOL_ERROR);
+ return;
+ }
+
+ state_ = State::WAIT_AUTH_RESULT;
+ break;
+ }
+
+ case State::WAIT_AUTH_RESULT: {
+ if (stanza->Name() == kSaslSuccessName) {
+ state_ = State::WAIT_STREAM_HEADER_AFTER_AUTH;
+ StartStream(
+ "<iq type=\"set\" id=\"0\">"
+ "<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\">"
+ "<resource>chromoting</resource>"
+ "</bind>"
+ "</iq>"
+ "<iq type=\"set\" id=\"1\">"
+ "<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/>"
+ "</iq>");
+ } else {
+ OnError(SignalStrategy::AUTHENTICATION_FAILED);
+ }
+ break;
+ }
+
+ case State::WAIT_STREAM_HEADER_AFTER_AUTH:
+ if (stanza->Name() == kJabberFeaturesName &&
+ stanza->FirstNamed(kXmppBindName) != nullptr) {
+ state_ = State::WAIT_BIND_RESULT;
+ } else {
+ LOG(ERROR) << "Server doesn't support bind after authentication.";
+ OnError(SignalStrategy::PROTOCOL_ERROR);
+ }
+ break;
+
+ case State::WAIT_BIND_RESULT: {
+ buzz::XmlElement* bind = stanza->FirstNamed(kXmppBindName);
+ buzz::XmlElement* jid = bind ? bind->FirstNamed(kXmppJidName) : nullptr;
+ if (stanza->Attr(buzz::QName("", "id")) != "0" ||
+ stanza->Attr(buzz::QName("", "type")) != "result" || !jid) {
+ LOG(ERROR) << "Received unexpected response to bind: " << stanza->Str();
+ OnError(SignalStrategy::PROTOCOL_ERROR);
+ return;
+ }
+ jid_ = jid->BodyText();
+ state_ = State::WAIT_SESSION_IQ_RESULT;
+ break;
+ }
+
+ case State::WAIT_SESSION_IQ_RESULT:
+ if (stanza->Name() != kXmppIqName ||
+ stanza->Attr(buzz::QName("", "id")) != "1" ||
+ stanza->Attr(buzz::QName("", "type")) != "result") {
+ LOG(ERROR) << "Failed to start session: " << stanza->Str();
+ OnError(SignalStrategy::PROTOCOL_ERROR);
+ return;
+ }
+ state_ = State::DONE;
+ delegate_->OnHandshakeDone(jid_, stream_parser_.Pass());
+ break;
+
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+void XmppLoginHandler::OnTlsStarted() {
+ DCHECK(state_ == State::STARTING_TLS);
+ state_ = State::WAIT_STREAM_HEADER_AFTER_TLS;
+
+ std::string cookie;
+ base::Base64Encode(
+ std::string("\0", 1) + username_ + std::string("\0", 1) + auth_token_,
+ &cookie);
+ StartStream(
+ "<auth xmlns=\"" + std::string(kXmppSaslNs) + "\" "
+ "mechanism=\"" + auth_mechanism_+ "\" "
+ "auth:service=\"" + auth_service_ + "\" "
+ "auth:allow-generated-jid=\"true\" "
+ "auth:client-uses-full-bind-result=\"true\" "
+ "auth:allow-non-google-login=\"true\" "
+ "xmlns:auth=\"http://www.google.com/talk/protocol/auth\">" +
+ cookie +
+ "</auth>");
+};
+
+void XmppLoginHandler::OnParserError() {
+ OnError(SignalStrategy::PROTOCOL_ERROR);
+}
+
+void XmppLoginHandler::StartStream(const std::string& first_message) {
+ delegate_->SendMessage("<stream:stream to=\"" + server_ +
+ "\" version=\"1.0\" xmlns=\"jabber:client\" "
+ "xmlns:stream=\"http://etherx.jabber.org/streams\">" +
+ first_message);
+ stream_parser_.reset(new XmppStreamParser());
+ stream_parser_->SetCallbacks(
+ base::Bind(&XmppLoginHandler::OnStanza, base::Unretained(this)),
+ base::Bind(&XmppLoginHandler::OnParserError, base::Unretained(this)));
+}
+
+void XmppLoginHandler::OnError(SignalStrategy::Error error) {
+ if (state_ != State::ERROR) {
+ state_ = State::ERROR;
+ delegate_->OnLoginHandlerError(error);
+ }
+}
+
+} // namespace remoting

Powered by Google App Engine
This is Rietveld 408576698