Third Party authentication protocol.

This adds a new Authenticator, that uses a third-party token service to authenticate clients and hosts and negotiate a shared secret.

The client authenticates with the third-party service, and obtains a token and a shared secret. The token is sent directly to the host, the shared secret is used to initiate a SPAKE authentication.

The host receives the token, and asks the third-party server to exchange it for the shared secret (authenticating itself by signing the request with the host private key). Once it gets the shared secret, client and host are able to finish the SPAKE negotiation.

BUG=115899

Review URL: https://chromiumcodereview.appspot.com/12326090

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@190024 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/remoting/protocol/third_party_authenticator_base.cc b/remoting/protocol/third_party_authenticator_base.cc
new file mode 100644
index 0000000..9d6be72
--- /dev/null
+++ b/remoting/protocol/third_party_authenticator_base.cc
@@ -0,0 +1,91 @@
+// Copyright 2013 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/protocol/third_party_authenticator_base.h"
+
+#include "base/base64.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "remoting/base/constants.h"
+#include "remoting/base/rsa_key_pair.h"
+#include "remoting/protocol/channel_authenticator.h"
+#include "remoting/protocol/v2_authenticator.h"
+#include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
+
+namespace remoting {
+namespace protocol {
+
+// static
+const buzz::StaticQName ThirdPartyAuthenticatorBase::kTokenUrlTag =
+    { remoting::kChromotingXmlNamespace, "third-party-token-url" };
+const buzz::StaticQName ThirdPartyAuthenticatorBase::kTokenScopeTag =
+    { remoting::kChromotingXmlNamespace, "third-party-token-scope" };
+const buzz::StaticQName ThirdPartyAuthenticatorBase::kTokenTag =
+    { remoting::kChromotingXmlNamespace, "third-party-token" };
+
+ThirdPartyAuthenticatorBase::ThirdPartyAuthenticatorBase(
+    Authenticator::State initial_state)
+    : token_state_(initial_state),
+      rejection_reason_(INVALID_CREDENTIALS) {
+}
+
+ThirdPartyAuthenticatorBase::~ThirdPartyAuthenticatorBase() {
+}
+
+Authenticator::State ThirdPartyAuthenticatorBase::state() const {
+  if (token_state_ == ACCEPTED)
+    return underlying_->state();
+  return token_state_;
+}
+
+Authenticator::RejectionReason
+ThirdPartyAuthenticatorBase::rejection_reason() const {
+  DCHECK_EQ(state(), REJECTED);
+
+  if (token_state_ == REJECTED)
+    return rejection_reason_;
+  return underlying_->rejection_reason();
+}
+
+void ThirdPartyAuthenticatorBase::ProcessMessage(
+    const buzz::XmlElement* message,
+    const base::Closure& resume_callback) {
+  DCHECK_EQ(state(), WAITING_MESSAGE);
+
+  if (token_state_ == WAITING_MESSAGE) {
+    ProcessTokenMessage(message, resume_callback);
+  } else {
+    DCHECK_EQ(token_state_, ACCEPTED);
+    DCHECK(underlying_);
+    DCHECK_EQ(underlying_->state(), WAITING_MESSAGE);
+    underlying_->ProcessMessage(message, resume_callback);
+  }
+}
+
+scoped_ptr<buzz::XmlElement> ThirdPartyAuthenticatorBase::GetNextMessage() {
+  DCHECK_EQ(state(), MESSAGE_READY);
+
+  scoped_ptr<buzz::XmlElement> message;
+  if (underlying_ && underlying_->state() == MESSAGE_READY) {
+    message = underlying_->GetNextMessage().Pass();
+  } else {
+    message = CreateEmptyAuthenticatorMessage();
+  }
+
+  if (token_state_ == MESSAGE_READY)
+    AddTokenElements(message.get());
+
+  return message.Pass();
+}
+
+scoped_ptr<ChannelAuthenticator>
+ThirdPartyAuthenticatorBase::CreateChannelAuthenticator() const {
+  DCHECK_EQ(state(), ACCEPTED);
+
+  return underlying_->CreateChannelAuthenticator();
+}
+
+}  // namespace protocol
+}  // namespace remoting