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

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, 9 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
« no previous file with comments | « remoting/signaling/xmpp_login_handler.h ('k') | remoting/signaling/xmpp_login_handler_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..cc3ae94a4e0ab63405f6c571236e2114b5c2253a
--- /dev/null
+++ b/remoting/signaling/xmpp_login_handler.cc
@@ -0,0 +1,241 @@
+// 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 "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"
+
+// Undefine SendMessage and ERROR defined in Windows headers.
+#ifdef SendMessage
+#undef SendMessage
+#endif
+
+#ifdef ERROR
+#undef ERROR
+#endif
+
+namespace remoting {
+
+const char kOAuthMechanism[] = "X-OAUTH2";
+
+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,
+ TlsMode tls_mode,
+ Delegate* delegate)
+ : server_(server),
+ username_(username),
+ auth_token_(auth_token),
+ tls_mode_(tls_mode),
+ delegate_(delegate),
+ state_(State::INIT) {
+}
+
+XmppLoginHandler::~XmppLoginHandler() {
+}
+
+void XmppLoginHandler::Start() {
+ switch (tls_mode_) {
+ case TlsMode::NO_TLS:
+ state_ = State::WAIT_STREAM_HEADER_AFTER_TLS;
+ StartAuthHandshake();
+ break;
+ case TlsMode::WITH_HANDSHAKE:
+ state_ = State::WAIT_STREAM_HEADER;
+ StartStream("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>");
+ break;
+ case TlsMode::WITHOUT_HANDSHAKE:
+ // If <starttls> handshake is not required then start TLS right away.
+ state_ = State::STARTING_TLS;
+ delegate_->StartTls();
+ break;
+ }
+}
+
+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);
+ bool oauth_supported = false;
+ if (mechanisms_element) {
+ for (buzz::XmlElement* element =
+ mechanisms_element->FirstNamed(kSaslMechanismName);
+ element; element = element->NextNamed(kSaslMechanismName)) {
+ if (element->BodyText() == kOAuthMechanism) {
+ oauth_supported = true;
+ break;
+ }
+ }
+ }
+
+ if (!oauth_supported) {
+ LOG(ERROR) << kOAuthMechanism
+ << " 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;
+ StartAuthHandshake();
+}
+
+void XmppLoginHandler::StartAuthHandshake() {
+ DCHECK(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=\"" + "X-OAUTH2" + "\" "
+ "auth:service=\"oauth2\" "
+ "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
« no previous file with comments | « remoting/signaling/xmpp_login_handler.h ('k') | remoting/signaling/xmpp_login_handler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698