summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--remoting/client/chromoting_client.cc4
-rw-r--r--remoting/client/client_config.h2
-rw-r--r--remoting/client/plugin/chromoting_instance.h2
-rw-r--r--remoting/protocol/it2me_host_authenticator_factory.cc7
-rw-r--r--remoting/protocol/me2me_host_authenticator_factory.cc6
-rw-r--r--remoting/protocol/negotiating_authenticator.cc261
-rw-r--r--remoting/protocol/negotiating_authenticator_base.cc105
-rw-r--r--remoting/protocol/negotiating_authenticator_base.h (renamed from remoting/protocol/negotiating_authenticator.h)91
-rw-r--r--remoting/protocol/negotiating_authenticator_unittest.cc13
-rw-r--r--remoting/protocol/negotiating_client_authenticator.cc117
-rw-r--r--remoting/protocol/negotiating_client_authenticator.h67
-rw-r--r--remoting/protocol/negotiating_host_authenticator.cc136
-rw-r--r--remoting/protocol/negotiating_host_authenticator.h61
-rw-r--r--remoting/remoting.gyp8
14 files changed, 534 insertions, 346 deletions
diff --git a/remoting/client/chromoting_client.cc b/remoting/client/chromoting_client.cc
index c83002f..f9febdc 100644
--- a/remoting/client/chromoting_client.cc
+++ b/remoting/client/chromoting_client.cc
@@ -14,7 +14,7 @@
#include "remoting/proto/video.pb.h"
#include "remoting/protocol/authentication_method.h"
#include "remoting/protocol/connection_to_host.h"
-#include "remoting/protocol/negotiating_authenticator.h"
+#include "remoting/protocol/negotiating_client_authenticator.h"
#include "remoting/protocol/session_config.h"
#include "remoting/protocol/transport.h"
@@ -53,7 +53,7 @@ void ChromotingClient::Start(
DCHECK(task_runner_->BelongsToCurrentThread());
scoped_ptr<protocol::Authenticator> authenticator(
- protocol::NegotiatingAuthenticator::CreateForClient(
+ new protocol::NegotiatingClientAuthenticator(
config_.authentication_tag, config_.fetch_secret_callback,
config_.authentication_methods));
diff --git a/remoting/client/client_config.h b/remoting/client/client_config.h
index 8cc67b3..a7e87e9 100644
--- a/remoting/client/client_config.h
+++ b/remoting/client/client_config.h
@@ -10,7 +10,7 @@
#include "base/basictypes.h"
#include "remoting/protocol/authentication_method.h"
-#include "remoting/protocol/negotiating_authenticator.h"
+#include "remoting/protocol/negotiating_client_authenticator.h"
namespace remoting {
diff --git a/remoting/client/plugin/chromoting_instance.h b/remoting/client/plugin/chromoting_instance.h
index e814eaf..a57275a 100644
--- a/remoting/client/plugin/chromoting_instance.h
+++ b/remoting/client/plugin/chromoting_instance.h
@@ -39,7 +39,7 @@
#include "remoting/protocol/cursor_shape_stub.h"
#include "remoting/protocol/input_event_tracker.h"
#include "remoting/protocol/mouse_input_filter.h"
-#include "remoting/protocol/negotiating_authenticator.h"
+#include "remoting/protocol/negotiating_client_authenticator.h"
namespace base {
class DictionaryValue;
diff --git a/remoting/protocol/it2me_host_authenticator_factory.cc b/remoting/protocol/it2me_host_authenticator_factory.cc
index 83fa6b6..e9f6c09 100644
--- a/remoting/protocol/it2me_host_authenticator_factory.cc
+++ b/remoting/protocol/it2me_host_authenticator_factory.cc
@@ -6,7 +6,7 @@
#include "base/logging.h"
#include "remoting/base/rsa_key_pair.h"
-#include "remoting/protocol/negotiating_authenticator.h"
+#include "remoting/protocol/negotiating_host_authenticator.h"
namespace remoting {
namespace protocol {
@@ -27,9 +27,8 @@ scoped_ptr<Authenticator> It2MeHostAuthenticatorFactory::CreateAuthenticator(
const std::string& local_jid,
const std::string& remote_jid,
const buzz::XmlElement* first_message) {
- return NegotiatingAuthenticator::CreateForHost(
- local_cert_, key_pair_, shared_secret_,
- AuthenticationMethod::NONE);
+ return scoped_ptr<Authenticator>(new NegotiatingHostAuthenticator(
+ local_cert_, key_pair_, shared_secret_, AuthenticationMethod::NONE));
}
} // namespace protocol
diff --git a/remoting/protocol/me2me_host_authenticator_factory.cc b/remoting/protocol/me2me_host_authenticator_factory.cc
index 9a04d89..4ee7b65 100644
--- a/remoting/protocol/me2me_host_authenticator_factory.cc
+++ b/remoting/protocol/me2me_host_authenticator_factory.cc
@@ -8,7 +8,7 @@
#include "base/string_util.h"
#include "remoting/base/rsa_key_pair.h"
#include "remoting/protocol/channel_authenticator.h"
-#include "remoting/protocol/negotiating_authenticator.h"
+#include "remoting/protocol/negotiating_host_authenticator.h"
#include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
namespace remoting {
@@ -91,9 +91,9 @@ scoped_ptr<Authenticator> Me2MeHostAuthenticatorFactory::CreateAuthenticator(
return scoped_ptr<Authenticator>(new RejectingAuthenticator());
}
- return NegotiatingAuthenticator::CreateForHost(
+ return scoped_ptr<Authenticator>(new NegotiatingHostAuthenticator(
local_cert_, key_pair_, shared_secret_hash_.value,
- shared_secret_hash_.hash_function);
+ shared_secret_hash_.hash_function));
}
} // namespace protocol
diff --git a/remoting/protocol/negotiating_authenticator.cc b/remoting/protocol/negotiating_authenticator.cc
deleted file mode 100644
index c6ecacb..0000000
--- a/remoting/protocol/negotiating_authenticator.cc
+++ /dev/null
@@ -1,261 +0,0 @@
-// Copyright (c) 2012 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/negotiating_authenticator.h"
-
-#include <algorithm>
-#include <sstream>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/logging.h"
-#include "base/strings/string_split.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 {
-
-namespace {
-
-const buzz::StaticQName kMethodAttributeQName = { "", "method" };
-const buzz::StaticQName kSupportedMethodsAttributeQName =
- { "", "supported-methods" };
-
-const char kSupportedMethodsSeparator = ',';
-
-} // namespace
-
-// static
-scoped_ptr<Authenticator> NegotiatingAuthenticator::CreateForClient(
- const std::string& authentication_tag,
- const FetchSecretCallback& fetch_secret_callback,
- const std::vector<AuthenticationMethod>& methods) {
- scoped_ptr<NegotiatingAuthenticator> result(
- new NegotiatingAuthenticator(MESSAGE_READY));
- result->authentication_tag_ = authentication_tag;
- result->fetch_secret_callback_ = fetch_secret_callback;
-
- DCHECK(!methods.empty());
- for (std::vector<AuthenticationMethod>::const_iterator it = methods.begin();
- it != methods.end(); ++it) {
- result->AddMethod(*it);
- }
-
- return scoped_ptr<Authenticator>(result.Pass());
-}
-
-// static
-scoped_ptr<Authenticator> NegotiatingAuthenticator::CreateForHost(
- const std::string& local_cert,
- scoped_refptr<RsaKeyPair> key_pair,
- const std::string& shared_secret_hash,
- AuthenticationMethod::HashFunction hash_function) {
- scoped_ptr<NegotiatingAuthenticator> result(
- new NegotiatingAuthenticator(WAITING_MESSAGE));
- result->local_cert_ = local_cert;
- result->local_key_pair_ = key_pair;
- result->shared_secret_hash_ = shared_secret_hash;
-
- result->AddMethod(AuthenticationMethod::Spake2(hash_function));
-
- return scoped_ptr<Authenticator>(result.Pass());
-}
-
-NegotiatingAuthenticator::NegotiatingAuthenticator(
- Authenticator::State initial_state)
- : current_method_(AuthenticationMethod::Invalid()),
- state_(initial_state),
- rejection_reason_(INVALID_CREDENTIALS),
- weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
-}
-
-NegotiatingAuthenticator::~NegotiatingAuthenticator() {
-}
-
-Authenticator::State NegotiatingAuthenticator::state() const {
- return state_;
-}
-
-Authenticator::RejectionReason
-NegotiatingAuthenticator::rejection_reason() const {
- return rejection_reason_;
-}
-
-void NegotiatingAuthenticator::ProcessMessage(
- const buzz::XmlElement* message,
- const base::Closure& resume_callback) {
- DCHECK_EQ(state(), WAITING_MESSAGE);
-
- std::string method_attr = message->Attr(kMethodAttributeQName);
- AuthenticationMethod method = AuthenticationMethod::FromString(method_attr);
-
- // Check if the remote end specified a method that is not supported locally.
- if (method.is_valid() &&
- std::find(methods_.begin(), methods_.end(), method) == methods_.end()) {
- method = AuthenticationMethod::Invalid();
- }
-
- // If the remote peer did not specify auth method or specified unknown
- // method then select the first known method from the supported-methods
- // attribute.
- if (!method.is_valid()) {
- std::string supported_methods_attr =
- message->Attr(kSupportedMethodsAttributeQName);
- if (supported_methods_attr.empty()) {
- // Message contains neither method nor supported-methods attributes.
- state_ = REJECTED;
- rejection_reason_ = PROTOCOL_ERROR;
- resume_callback.Run();
- return;
- }
-
- // Find the first mutually-supported method in the peer's list of
- // supported-methods.
- std::vector<std::string> supported_methods_strs;
- base::SplitString(supported_methods_attr, kSupportedMethodsSeparator,
- &supported_methods_strs);
- for (std::vector<std::string>::iterator it = supported_methods_strs.begin();
- it != supported_methods_strs.end(); ++it) {
- AuthenticationMethod list_value = AuthenticationMethod::FromString(*it);
- if (list_value.is_valid() &&
- std::find(methods_.begin(),
- methods_.end(), list_value) != methods_.end()) {
- // Found common method.
- method = list_value;
- break;
- }
- }
-
- if (!method.is_valid()) {
- // Failed to find a common auth method.
- state_ = REJECTED;
- rejection_reason_ = PROTOCOL_ERROR;
- resume_callback.Run();
- return;
- }
-
- // Drop the current message because we've chosen a different
- // method.
- current_method_ = method;
- state_ = PROCESSING_MESSAGE;
- CreateAuthenticator(MESSAGE_READY, base::Bind(
- &NegotiatingAuthenticator::UpdateState,
- base::Unretained(this), resume_callback));
- return;
- }
- if (method != current_method_) {
- current_method_ = method;
- state_ = PROCESSING_MESSAGE;
- // Copy the message since the authenticator may process it asynchronously.
- CreateAuthenticator(WAITING_MESSAGE, base::Bind(
- &NegotiatingAuthenticator::ProcessMessageInternal,
- base::Unretained(this), base::Owned(new buzz::XmlElement(*message)),
- resume_callback));
- return;
- }
- ProcessMessageInternal(message, resume_callback);
-}
-
-void NegotiatingAuthenticator::UpdateState(
- const base::Closure& resume_callback) {
- // After the underlying authenticator finishes processing the message, the
- // NegotiatingAuthenticator must update its own state before running the
- // |resume_callback| to resume the session negotiation.
- state_ = current_authenticator_->state();
- if (state_ == REJECTED)
- rejection_reason_ = current_authenticator_->rejection_reason();
- resume_callback.Run();
-}
-
-scoped_ptr<buzz::XmlElement> NegotiatingAuthenticator::GetNextMessage() {
- DCHECK_EQ(state(), MESSAGE_READY);
-
- scoped_ptr<buzz::XmlElement> result;
-
- // No method yet, just send a message with the list of supported methods.
- // Normally happens only on client.
- if (!current_method_.is_valid()) {
- result = CreateEmptyAuthenticatorMessage();
- std::stringstream supported_methods(std::stringstream::out);
- for (std::vector<AuthenticationMethod>::iterator it = methods_.begin();
- it != methods_.end(); ++it) {
- if (it != methods_.begin())
- supported_methods << kSupportedMethodsSeparator;
- supported_methods << it->ToString();
- }
- result->AddAttr(kSupportedMethodsAttributeQName, supported_methods.str());
- state_ = WAITING_MESSAGE;
- } else {
- if (current_authenticator_->state() == MESSAGE_READY) {
- result = current_authenticator_->GetNextMessage();
- } else {
- result = CreateEmptyAuthenticatorMessage();
- }
- state_ = current_authenticator_->state();
- DCHECK(state_ == ACCEPTED || state_ == WAITING_MESSAGE);
- result->AddAttr(kMethodAttributeQName, current_method_.ToString());
- }
-
- return result.Pass();
-}
-
-void NegotiatingAuthenticator::AddMethod(const AuthenticationMethod& method) {
- DCHECK(method.is_valid());
- methods_.push_back(method);
-}
-
-scoped_ptr<ChannelAuthenticator>
-NegotiatingAuthenticator::CreateChannelAuthenticator() const {
- DCHECK_EQ(state(), ACCEPTED);
- return current_authenticator_->CreateChannelAuthenticator();
-}
-
-bool NegotiatingAuthenticator::is_host_side() const {
- return local_key_pair_.get() != NULL;
-}
-
-void NegotiatingAuthenticator::CreateAuthenticator(
- Authenticator::State preferred_initial_state,
- const base::Closure& resume_callback) {
- if (is_host_side()) {
- current_authenticator_ = V2Authenticator::CreateForHost(
- local_cert_, local_key_pair_, shared_secret_hash_,
- preferred_initial_state);
- resume_callback.Run();
- } else {
- fetch_secret_callback_.Run(base::Bind(
- &NegotiatingAuthenticator::CreateV2AuthenticatorWithSecret,
- weak_factory_.GetWeakPtr(), preferred_initial_state, resume_callback));
- }
-}
-
-void NegotiatingAuthenticator::ProcessMessageInternal(
- const buzz::XmlElement* message,
- const base::Closure& resume_callback) {
- if (current_authenticator_->state() == WAITING_MESSAGE) {
- // If the message was not discarded and the authenticator is waiting for it,
- // give it to the underlying authenticator to process.
- // |current_authenticator_| is owned, so Unretained() is safe here.
- current_authenticator_->ProcessMessage(message, base::Bind(
- &NegotiatingAuthenticator::UpdateState,
- base::Unretained(this), resume_callback));
- }
-}
-
-void NegotiatingAuthenticator::CreateV2AuthenticatorWithSecret(
- Authenticator::State initial_state,
- const base::Closure& resume_callback,
- const std::string& shared_secret) {
- current_authenticator_ = V2Authenticator::CreateForClient(
- AuthenticationMethod::ApplyHashFunction(
- current_method_.hash_function(), authentication_tag_, shared_secret),
- initial_state);
- resume_callback.Run();
-}
-
-} // namespace protocol
-} // namespace remoting
diff --git a/remoting/protocol/negotiating_authenticator_base.cc b/remoting/protocol/negotiating_authenticator_base.cc
new file mode 100644
index 0000000..2c2b4c5
--- /dev/null
+++ b/remoting/protocol/negotiating_authenticator_base.cc
@@ -0,0 +1,105 @@
+// Copyright (c) 2012 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/negotiating_authenticator_base.h"
+
+#include <algorithm>
+#include <sstream>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/strings/string_split.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 {
+
+const buzz::StaticQName NegotiatingAuthenticatorBase::kMethodAttributeQName =
+ { "", "method" };
+const buzz::StaticQName
+NegotiatingAuthenticatorBase::kSupportedMethodsAttributeQName =
+ { "", "supported-methods" };
+const char NegotiatingAuthenticatorBase::kSupportedMethodsSeparator = ',';
+
+NegotiatingAuthenticatorBase::NegotiatingAuthenticatorBase(
+ Authenticator::State initial_state)
+ : current_method_(AuthenticationMethod::Invalid()),
+ state_(initial_state),
+ rejection_reason_(INVALID_CREDENTIALS) {
+}
+
+NegotiatingAuthenticatorBase::~NegotiatingAuthenticatorBase() {
+}
+
+Authenticator::State NegotiatingAuthenticatorBase::state() const {
+ return state_;
+}
+
+Authenticator::RejectionReason
+NegotiatingAuthenticatorBase::rejection_reason() const {
+ return rejection_reason_;
+}
+
+void NegotiatingAuthenticatorBase::ProcessMessageInternal(
+ const buzz::XmlElement* message,
+ const base::Closure& resume_callback) {
+ if (current_authenticator_->state() == WAITING_MESSAGE) {
+ // If the message was not discarded and the authenticator is waiting for it,
+ // give it to the underlying authenticator to process.
+ // |current_authenticator_| is owned, so Unretained() is safe here.
+ current_authenticator_->ProcessMessage(message, base::Bind(
+ &NegotiatingAuthenticatorBase::UpdateState,
+ base::Unretained(this), resume_callback));
+ } else {
+ // Otherwise, just discard the message and run the callback.
+ resume_callback.Run();
+ }
+}
+
+void NegotiatingAuthenticatorBase::UpdateState(
+ const base::Closure& resume_callback) {
+ // After the underlying authenticator finishes processing the message, the
+ // NegotiatingAuthenticatorBase must update its own state before running the
+ // |resume_callback| to resume the session negotiation.
+ state_ = current_authenticator_->state();
+ if (state_ == REJECTED)
+ rejection_reason_ = current_authenticator_->rejection_reason();
+ resume_callback.Run();
+}
+
+scoped_ptr<buzz::XmlElement>
+NegotiatingAuthenticatorBase::GetNextMessageInternal() {
+ DCHECK_EQ(state(), MESSAGE_READY);
+ DCHECK(current_method_.is_valid());
+
+ scoped_ptr<buzz::XmlElement> result;
+ if (current_authenticator_->state() == MESSAGE_READY) {
+ result = current_authenticator_->GetNextMessage();
+ } else {
+ result = CreateEmptyAuthenticatorMessage();
+ }
+ state_ = current_authenticator_->state();
+ DCHECK(state_ == ACCEPTED || state_ == WAITING_MESSAGE);
+ result->AddAttr(kMethodAttributeQName, current_method_.ToString());
+ return result.Pass();
+}
+
+void NegotiatingAuthenticatorBase::AddMethod(
+ const AuthenticationMethod& method) {
+ DCHECK(method.is_valid());
+ methods_.push_back(method);
+}
+
+scoped_ptr<ChannelAuthenticator>
+NegotiatingAuthenticatorBase::CreateChannelAuthenticator() const {
+ DCHECK_EQ(state(), ACCEPTED);
+ return current_authenticator_->CreateChannelAuthenticator();
+}
+
+} // namespace protocol
+} // namespace remoting
diff --git a/remoting/protocol/negotiating_authenticator.h b/remoting/protocol/negotiating_authenticator_base.h
index 7166cf5..97209c5 100644
--- a/remoting/protocol/negotiating_authenticator.h
+++ b/remoting/protocol/negotiating_authenticator_base.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef REMOTING_PROTOCOL_NEGOTIATING_AUTHENTICATOR_H_
-#define REMOTING_PROTOCOL_NEGOTIATING_AUTHENTICATOR_H_
+#ifndef REMOTING_PROTOCOL_NEGOTIATING_AUTHENTICATOR_BASE_H_
+#define REMOTING_PROTOCOL_NEGOTIATING_AUTHENTICATOR_BASE_H_
#include <string>
#include <vector>
@@ -11,22 +11,16 @@
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "remoting/protocol/authenticator.h"
#include "remoting/protocol/authentication_method.h"
+#include "remoting/protocol/authenticator.h"
+#include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
namespace remoting {
-
-class RsaKeyPair;
-
namespace protocol {
-typedef base::Callback<void(const std::string& secret)> SecretFetchedCallback;
-typedef base::Callback<void(
- const SecretFetchedCallback& secret_fetched_callback)> FetchSecretCallback;
-
-// This class provides a meta-authenticator that allows clients and hosts that
-// support multiple authentication methods to negotiate a method to use.
+// This class provides the common base for a meta-authenticator that allows
+// clients and hosts that support multiple authentication methods to negotiate a
+// method to use.
//
// The typical flow is:
// * Client sends a message to host with its supported methods.
@@ -64,84 +58,49 @@ typedef base::Callback<void(
// the host picks a method from the client's list, it's final.
// * Any change in this class must maintain compatibility between any version
// mix of webapp, client plugin and host, for both Me2Me and IT2Me.
-class NegotiatingAuthenticator : public Authenticator {
+class NegotiatingAuthenticatorBase : public Authenticator {
public:
- virtual ~NegotiatingAuthenticator();
-
- // Creates a client authenticator for the given methods.
- static scoped_ptr<Authenticator> CreateForClient(
- const std::string& authentication_tag,
- const FetchSecretCallback& fetch_secret_callback,
- const std::vector<AuthenticationMethod>& methods);
-
- // Creates a host authenticator, using a fixed shared secret/PIN hash.
- static scoped_ptr<Authenticator> CreateForHost(
- const std::string& local_cert,
- scoped_refptr<RsaKeyPair> key_pair,
- const std::string& shared_secret_hash,
- AuthenticationMethod::HashFunction hash_function);
+ virtual ~NegotiatingAuthenticatorBase();
// Authenticator interface.
virtual State state() const OVERRIDE;
virtual RejectionReason rejection_reason() const OVERRIDE;
- virtual void ProcessMessage(const buzz::XmlElement* message,
- const base::Closure& resume_callback) OVERRIDE;
- virtual scoped_ptr<buzz::XmlElement> GetNextMessage() OVERRIDE;
virtual scoped_ptr<ChannelAuthenticator>
CreateChannelAuthenticator() const OVERRIDE;
- private:
- explicit NegotiatingAuthenticator(Authenticator::State initial_state);
-
- void AddMethod(const AuthenticationMethod& method);
-
- // (Asynchronously) creates an authenticator, and stores it in
- // |current_authenticator_|. Authenticators that can be started in either
- // state will be created in |preferred_initial_state|.
- // |resume_callback| is called after |current_authenticator_| is set.
- void CreateAuthenticator(Authenticator::State preferred_initial_state,
- const base::Closure& resume_callback);
-
// Calls |current_authenticator_| to process |message|, passing the supplied
// |resume_callback|.
void ProcessMessageInternal(const buzz::XmlElement* message,
- const base::Closure& resume_callback);
+ const base::Closure& resume_callback);
- // Updates |state_| to reflect the current underlying authenticator state.
- // |resume_callback| is called after the state is updated.
- void UpdateState(const base::Closure& resume_callback);
+ protected:
+ static const buzz::StaticQName kMethodAttributeQName;
+ static const buzz::StaticQName kSupportedMethodsAttributeQName;
+ static const char kSupportedMethodsSeparator;
- // Creates a V2Authenticator in state |initial_state| with the given
- // |shared_secret|, then runs |resume_callback|.
- void CreateV2AuthenticatorWithSecret(
- Authenticator::State initial_state,
- const base::Closure& resume_callback,
- const std::string& shared_secret);
+ explicit NegotiatingAuthenticatorBase(Authenticator::State initial_state);
- bool is_host_side() const;
+ void AddMethod(const AuthenticationMethod& method);
- // Used only for host authenticators.
- std::string local_cert_;
- scoped_refptr<RsaKeyPair> local_key_pair_;
- std::string shared_secret_hash_;
+ // Updates |state_| to reflect the current underlying authenticator state.
+ // |resume_callback| is called after the state is updated.
+ void UpdateState(const base::Closure& resume_callback);
- // Used only for client authenticators.
- std::string authentication_tag_;
- FetchSecretCallback fetch_secret_callback_;
+ // Gets the next message from |current_authenticator_|, if any, and fills in
+ // the 'method' tag with |current_method_|.
+ virtual scoped_ptr<buzz::XmlElement> GetNextMessageInternal();
- // Used for both host and client authenticators.
std::vector<AuthenticationMethod> methods_;
AuthenticationMethod current_method_;
scoped_ptr<Authenticator> current_authenticator_;
State state_;
RejectionReason rejection_reason_;
- base::WeakPtrFactory<NegotiatingAuthenticator> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(NegotiatingAuthenticator);
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NegotiatingAuthenticatorBase);
};
} // namespace protocol
} // namespace remoting
-#endif // REMOTING_PROTOCOL_NEGOTIATING_AUTHENTICATOR_H_
+#endif // REMOTING_PROTOCOL_NEGOTIATING_AUTHENTICATOR_BASE_H_
diff --git a/remoting/protocol/negotiating_authenticator_unittest.cc b/remoting/protocol/negotiating_authenticator_unittest.cc
index b17fa6a..1a6e93f 100644
--- a/remoting/protocol/negotiating_authenticator_unittest.cc
+++ b/remoting/protocol/negotiating_authenticator_unittest.cc
@@ -2,14 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "remoting/protocol/negotiating_authenticator.h"
-
#include "base/bind.h"
#include "net/base/net_errors.h"
#include "remoting/base/rsa_key_pair.h"
#include "remoting/protocol/authenticator_test_base.h"
#include "remoting/protocol/channel_authenticator.h"
#include "remoting/protocol/connection_tester.h"
+#include "remoting/protocol/negotiating_authenticator_base.h"
+#include "remoting/protocol/negotiating_client_authenticator.h"
+#include "remoting/protocol/negotiating_host_authenticator.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
@@ -48,8 +49,8 @@ class NegotiatingAuthenticatorTest : public AuthenticatorTestBase {
bool client_hmac_only) {
std::string host_secret_hash = AuthenticationMethod::ApplyHashFunction(
hash_function, kTestHostId, host_secret);
- host_ = NegotiatingAuthenticator::CreateForHost(
- host_cert_, key_pair_, host_secret_hash, hash_function);
+ host_.reset(new NegotiatingHostAuthenticator(
+ host_cert_, key_pair_, host_secret_hash, hash_function));
std::vector<AuthenticationMethod> methods;
methods.push_back(AuthenticationMethod::Spake2(
@@ -58,9 +59,9 @@ class NegotiatingAuthenticatorTest : public AuthenticatorTestBase {
methods.push_back(AuthenticationMethod::Spake2(
AuthenticationMethod::NONE));
}
- client_ = NegotiatingAuthenticator::CreateForClient(
+ client_.reset(new NegotiatingClientAuthenticator(
kTestHostId, base::Bind(&NegotiatingAuthenticatorTest::FetchSecret,
- client_secret), methods);
+ client_secret), methods));
}
static void FetchSecret(
diff --git a/remoting/protocol/negotiating_client_authenticator.cc b/remoting/protocol/negotiating_client_authenticator.cc
new file mode 100644
index 0000000..c7ab0f5
--- /dev/null
+++ b/remoting/protocol/negotiating_client_authenticator.cc
@@ -0,0 +1,117 @@
+// 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/negotiating_client_authenticator.h"
+
+#include <algorithm>
+#include <sstream>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/strings/string_split.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 {
+
+NegotiatingClientAuthenticator::NegotiatingClientAuthenticator(
+ const std::string& authentication_tag,
+ const FetchSecretCallback& fetch_secret_callback,
+ const std::vector<AuthenticationMethod>& methods)
+ : NegotiatingAuthenticatorBase(MESSAGE_READY),
+ authentication_tag_(authentication_tag),
+ fetch_secret_callback_(fetch_secret_callback),
+ method_set_by_host_(false),
+ weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
+ DCHECK(!methods.empty());
+ for (std::vector<AuthenticationMethod>::const_iterator it = methods.begin();
+ it != methods.end(); ++it) {
+ AddMethod(*it);
+ }
+}
+
+NegotiatingClientAuthenticator::~NegotiatingClientAuthenticator() {
+}
+
+void NegotiatingClientAuthenticator::ProcessMessage(
+ const buzz::XmlElement* message,
+ const base::Closure& resume_callback) {
+ DCHECK_EQ(state(), WAITING_MESSAGE);
+
+ std::string method_attr = message->Attr(kMethodAttributeQName);
+ AuthenticationMethod method = AuthenticationMethod::FromString(method_attr);
+
+ // The host picked a method different from the one the client had selected.
+ if (method != current_method_) {
+ // The host must pick a method that is valid and supported by the client,
+ // and it must not change methods after it has picked one.
+ if (method_set_by_host_ || !method.is_valid() ||
+ std::find(methods_.begin(), methods_.end(), method) == methods_.end()) {
+ state_ = REJECTED;
+ rejection_reason_ = PROTOCOL_ERROR;
+ resume_callback.Run();
+ return;
+ }
+
+ current_method_ = method;
+ method_set_by_host_ = true;
+ state_ = PROCESSING_MESSAGE;
+ // Copy the message since the authenticator may process it asynchronously.
+ CreateAuthenticator(WAITING_MESSAGE, base::Bind(
+ &NegotiatingAuthenticatorBase::ProcessMessageInternal,
+ base::Unretained(this), base::Owned(new buzz::XmlElement(*message)),
+ resume_callback));
+ return;
+ }
+ ProcessMessageInternal(message, resume_callback);
+}
+
+scoped_ptr<buzz::XmlElement> NegotiatingClientAuthenticator::GetNextMessage() {
+ DCHECK_EQ(state(), MESSAGE_READY);
+ // This is the first message to the host, send a list of supported methods.
+ if (!current_method_.is_valid()) {
+ // We currently send just an empty message with the supported list, but, in
+ // the future, the client may optimistically pick a method and send its
+ // first message, along with the supported methods. If the host doesn't
+ // support that method, it is free to ignore this first message and pick a
+ // different method from the supported list.
+ scoped_ptr<buzz::XmlElement> result = CreateEmptyAuthenticatorMessage();
+ std::stringstream supported_methods(std::stringstream::out);
+ for (std::vector<AuthenticationMethod>::iterator it = methods_.begin();
+ it != methods_.end(); ++it) {
+ if (it != methods_.begin())
+ supported_methods << kSupportedMethodsSeparator;
+ supported_methods << it->ToString();
+ }
+ result->AddAttr(kSupportedMethodsAttributeQName, supported_methods.str());
+ state_ = WAITING_MESSAGE;
+ return result.Pass();
+ }
+ return GetNextMessageInternal();
+}
+
+void NegotiatingClientAuthenticator::CreateAuthenticator(
+ Authenticator::State preferred_initial_state,
+ const base::Closure& resume_callback) {
+ fetch_secret_callback_.Run(base::Bind(
+ &NegotiatingClientAuthenticator::CreateV2AuthenticatorWithSecret,
+ weak_factory_.GetWeakPtr(), preferred_initial_state, resume_callback));
+}
+
+void NegotiatingClientAuthenticator::CreateV2AuthenticatorWithSecret(
+ Authenticator::State initial_state,
+ const base::Closure& resume_callback,
+ const std::string& shared_secret) {
+ current_authenticator_ = V2Authenticator::CreateForClient(
+ AuthenticationMethod::ApplyHashFunction(
+ current_method_.hash_function(), authentication_tag_, shared_secret),
+ initial_state);
+ resume_callback.Run();
+}
+
+} // namespace protocol
+} // namespace remoting
diff --git a/remoting/protocol/negotiating_client_authenticator.h b/remoting/protocol/negotiating_client_authenticator.h
new file mode 100644
index 0000000..0927bd7
--- /dev/null
+++ b/remoting/protocol/negotiating_client_authenticator.h
@@ -0,0 +1,67 @@
+// 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.
+
+#ifndef REMOTING_PROTOCOL_NEGOTIATING_CLIENT_AUTHENTICATOR_H_
+#define REMOTING_PROTOCOL_NEGOTIATING_CLIENT_AUTHENTICATOR_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "remoting/protocol/authentication_method.h"
+#include "remoting/protocol/authenticator.h"
+#include "remoting/protocol/negotiating_authenticator_base.h"
+
+namespace remoting {
+namespace protocol {
+
+typedef base::Callback<void(const std::string& secret)> SecretFetchedCallback;
+typedef base::Callback<void(
+ const SecretFetchedCallback& secret_fetched_callback)> FetchSecretCallback;
+
+// Client-side implementation of NegotiatingAuthenticatorBase.
+// See comments in negotiating_authenticator_base.h for a general explanation.
+class NegotiatingClientAuthenticator : public NegotiatingAuthenticatorBase {
+ public:
+ NegotiatingClientAuthenticator(
+ const std::string& authentication_tag,
+ const FetchSecretCallback& fetch_secret_callback,
+ const std::vector<AuthenticationMethod>& methods);
+
+ virtual ~NegotiatingClientAuthenticator();
+
+ // Overriden from Authenticator.
+ virtual void ProcessMessage(const buzz::XmlElement* message,
+ const base::Closure& resume_callback) OVERRIDE;
+ virtual scoped_ptr<buzz::XmlElement> GetNextMessage() OVERRIDE;
+
+ private:
+ // (Asynchronously) creates an authenticator, and stores it in
+ // |current_authenticator_|. Authenticators that can be started in either
+ // state will be created in |preferred_initial_state|.
+ // |resume_callback| is called after |current_authenticator_| is set.
+ void CreateAuthenticator(Authenticator::State preferred_initial_state,
+ const base::Closure& resume_callback);
+
+ // Creates a V2Authenticator in state |initial_state| with the given
+ // |shared_secret|, then runs |resume_callback|.
+ void CreateV2AuthenticatorWithSecret(
+ Authenticator::State initial_state,
+ const base::Closure& resume_callback,
+ const std::string& shared_secret);
+
+ std::string authentication_tag_;
+ FetchSecretCallback fetch_secret_callback_;
+ bool method_set_by_host_;
+ base::WeakPtrFactory<NegotiatingClientAuthenticator> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(NegotiatingClientAuthenticator);
+};
+
+} // namespace protocol
+} // namespace remoting
+
+#endif // REMOTING_PROTOCOL_NEGOTIATING_CLIENT_AUTHENTICATOR_H_
diff --git a/remoting/protocol/negotiating_host_authenticator.cc b/remoting/protocol/negotiating_host_authenticator.cc
new file mode 100644
index 0000000..c54b6af
--- /dev/null
+++ b/remoting/protocol/negotiating_host_authenticator.cc
@@ -0,0 +1,136 @@
+// 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/negotiating_host_authenticator.h"
+
+#include <algorithm>
+#include <sstream>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/strings/string_split.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 {
+
+NegotiatingHostAuthenticator::NegotiatingHostAuthenticator(
+ const std::string& local_cert,
+ scoped_refptr<RsaKeyPair> key_pair,
+ const std::string& shared_secret_hash,
+ AuthenticationMethod::HashFunction hash_function)
+ : NegotiatingAuthenticatorBase(WAITING_MESSAGE),
+ local_cert_(local_cert),
+ local_key_pair_(key_pair),
+ shared_secret_hash_(shared_secret_hash) {
+
+ AddMethod(AuthenticationMethod::Spake2(hash_function));
+}
+
+NegotiatingHostAuthenticator::~NegotiatingHostAuthenticator() {
+}
+
+void NegotiatingHostAuthenticator::ProcessMessage(
+ const buzz::XmlElement* message,
+ const base::Closure& resume_callback) {
+ DCHECK_EQ(state(), WAITING_MESSAGE);
+
+ std::string method_attr = message->Attr(kMethodAttributeQName);
+ AuthenticationMethod method = AuthenticationMethod::FromString(method_attr);
+
+ // If the host has already chosen a method, it can't be changed by the client.
+ if (current_method_.is_valid() && method != current_method_) {
+ state_ = REJECTED;
+ rejection_reason_ = PROTOCOL_ERROR;
+ resume_callback.Run();
+ return;
+ }
+
+ // If the client did not specify auth method or specified unknown method,
+ // then select the first known method from the supported-methods attribute.
+ if (!method.is_valid() ||
+ std::find(methods_.begin(), methods_.end(), method) == methods_.end()) {
+
+ method = AuthenticationMethod::Invalid();
+
+ std::string supported_methods_attr =
+ message->Attr(kSupportedMethodsAttributeQName);
+ if (supported_methods_attr.empty()) {
+ // Message contains neither method nor supported-methods attributes.
+ state_ = REJECTED;
+ rejection_reason_ = PROTOCOL_ERROR;
+ resume_callback.Run();
+ return;
+ }
+
+ // Find the first mutually-supported method in the client's list of
+ // supported-methods.
+ std::vector<std::string> supported_methods_strs;
+ base::SplitString(supported_methods_attr, kSupportedMethodsSeparator,
+ &supported_methods_strs);
+ for (std::vector<std::string>::iterator it = supported_methods_strs.begin();
+ it != supported_methods_strs.end(); ++it) {
+ AuthenticationMethod list_value = AuthenticationMethod::FromString(*it);
+ if (list_value.is_valid() &&
+ std::find(methods_.begin(),
+ methods_.end(), list_value) != methods_.end()) {
+ // Found common method.
+ method = list_value;
+ break;
+ }
+ }
+
+ if (!method.is_valid()) {
+ // Failed to find a common auth method.
+ state_ = REJECTED;
+ rejection_reason_ = PROTOCOL_ERROR;
+ resume_callback.Run();
+ return;
+ }
+
+ // Drop the current message because we've chosen a different method.
+ current_method_ = method;
+ state_ = PROCESSING_MESSAGE;
+ CreateAuthenticator(MESSAGE_READY, base::Bind(
+ &NegotiatingHostAuthenticator::UpdateState,
+ base::Unretained(this), resume_callback));
+ return;
+ }
+
+ // If the client specified a supported method, and the host hasn't chosen a
+ // method yet, use the client's preferred method and process the message.
+ if (!current_method_.is_valid()) {
+ current_method_ = method;
+ state_ = PROCESSING_MESSAGE;
+ // Copy the message since the authenticator may process it asynchronously.
+ CreateAuthenticator(WAITING_MESSAGE, base::Bind(
+ &NegotiatingAuthenticatorBase::ProcessMessageInternal,
+ base::Unretained(this), base::Owned(new buzz::XmlElement(*message)),
+ resume_callback));
+ return;
+ }
+
+ // If the client is using the host's current method, just process the message.
+ ProcessMessageInternal(message, resume_callback);
+}
+
+scoped_ptr<buzz::XmlElement> NegotiatingHostAuthenticator::GetNextMessage() {
+ return GetNextMessageInternal();
+}
+
+void NegotiatingHostAuthenticator::CreateAuthenticator(
+ Authenticator::State preferred_initial_state,
+ const base::Closure& resume_callback) {
+ current_authenticator_ = V2Authenticator::CreateForHost(
+ local_cert_, local_key_pair_, shared_secret_hash_,
+ preferred_initial_state);
+ resume_callback.Run();
+}
+
+} // namespace protocol
+} // namespace remoting
diff --git a/remoting/protocol/negotiating_host_authenticator.h b/remoting/protocol/negotiating_host_authenticator.h
new file mode 100644
index 0000000..4ff53f6
--- /dev/null
+++ b/remoting/protocol/negotiating_host_authenticator.h
@@ -0,0 +1,61 @@
+// 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.
+
+#ifndef REMOTING_PROTOCOL_NEGOTIATING_HOST_AUTHENTICATOR_H_
+#define REMOTING_PROTOCOL_NEGOTIATING_HOST_AUTHENTICATOR_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "remoting/protocol/authentication_method.h"
+#include "remoting/protocol/authenticator.h"
+#include "remoting/protocol/negotiating_authenticator_base.h"
+
+namespace remoting {
+
+class RsaKeyPair;
+
+namespace protocol {
+
+// Host-side implementation of NegotiatingAuthenticatorBase.
+// See comments in negotiating_authenticator_base.h for a general explanation.
+class NegotiatingHostAuthenticator : public NegotiatingAuthenticatorBase {
+ public:
+ // Creates a host authenticator, using a fixed shared secret/PIN hash.
+ NegotiatingHostAuthenticator(
+ const std::string& local_cert,
+ scoped_refptr<RsaKeyPair> key_pair,
+ const std::string& shared_secret_hash,
+ AuthenticationMethod::HashFunction hash_function);
+
+ virtual ~NegotiatingHostAuthenticator();
+
+ // Overriden from Authenticator.
+ virtual void ProcessMessage(const buzz::XmlElement* message,
+ const base::Closure& resume_callback) OVERRIDE;
+ virtual scoped_ptr<buzz::XmlElement> GetNextMessage() OVERRIDE;
+
+ private:
+ // (Asynchronously) creates an authenticator, and stores it in
+ // |current_authenticator_|. Authenticators that can be started in either
+ // state will be created in |preferred_initial_state|.
+ // |resume_callback| is called after |current_authenticator_| is set.
+ void CreateAuthenticator(Authenticator::State preferred_initial_state,
+ const base::Closure& resume_callback);
+
+ std::string local_cert_;
+ scoped_refptr<RsaKeyPair> local_key_pair_;
+ std::string shared_secret_hash_;
+
+ DISALLOW_COPY_AND_ASSIGN(NegotiatingHostAuthenticator);
+};
+
+} // namespace protocol
+} // namespace remoting
+
+#endif // REMOTING_PROTOCOL_NEGOTIATING_HOST_AUTHENTICATOR_H_
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp
index 0fe1619..4db9587 100644
--- a/remoting/remoting.gyp
+++ b/remoting/remoting.gyp
@@ -2434,8 +2434,12 @@
'protocol/mouse_input_filter.cc',
'protocol/mouse_input_filter.h',
'protocol/name_value_map.h',
- 'protocol/negotiating_authenticator.cc',
- 'protocol/negotiating_authenticator.h',
+ 'protocol/negotiating_authenticator_base.cc',
+ 'protocol/negotiating_authenticator_base.h',
+ 'protocol/negotiating_client_authenticator.cc',
+ 'protocol/negotiating_client_authenticator.h',
+ 'protocol/negotiating_host_authenticator.cc',
+ 'protocol/negotiating_host_authenticator.h',
'protocol/protobuf_video_reader.cc',
'protocol/protobuf_video_reader.h',
'protocol/protobuf_video_writer.cc',