Commit 799f491e authored by Ryan Hansberry's avatar Ryan Hansberry Committed by Commit Bot

[CrOS Multidevice] Integrate the SecureChannel API into proximity_auth::Messenger.

This injects a ClientChannel into Messenger, which is used if the
chromeos::features::kMultiDeviceApi is enabled. The ClientChannel is used
to send and receive messages with the remote device.

R=jhawkins@chromium.org, khorimoto@chromium.org

Bug: 824568, 752273
Change-Id: If927eb84d013657db823f8538d138beb9c2c16be
Reviewed-on: https://chromium-review.googlesource.com/1107482
Commit-Queue: Ryan Hansberry <hansberry@chromium.org>
Reviewed-by: default avatarKyle Horimoto <khorimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#569798}
parent 84f58fd6
...@@ -5,6 +5,12 @@ ...@@ -5,6 +5,12 @@
#ifndef CHROMEOS_COMPONENTS_PROXIMITY_AUTH_MESSENGER_H_ #ifndef CHROMEOS_COMPONENTS_PROXIMITY_AUTH_MESSENGER_H_
#define CHROMEOS_COMPONENTS_PROXIMITY_AUTH_MESSENGER_H_ #define CHROMEOS_COMPONENTS_PROXIMITY_AUTH_MESSENGER_H_
namespace chromeos {
namespace secure_channel {
class ClientChannel;
} // namespace secure_channel
} // namespace chromeos
namespace cryptauth { namespace cryptauth {
class Connection; class Connection;
class SecureContext; class SecureContext;
...@@ -48,6 +54,8 @@ class Messenger { ...@@ -48,6 +54,8 @@ class Messenger {
// |GetSecureContext()| instead if you want to send and receive messages // |GetSecureContext()| instead if you want to send and receive messages
// securely. // securely.
virtual cryptauth::Connection* GetConnection() const = 0; virtual cryptauth::Connection* GetConnection() const = 0;
virtual chromeos::secure_channel::ClientChannel* GetChannel() const = 0;
}; };
} // namespace proximity_auth } // namespace proximity_auth
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "base/location.h" #include "base/location.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "base/values.h" #include "base/values.h"
#include "chromeos/chromeos_features.h"
#include "chromeos/components/proximity_auth/logging/logging.h" #include "chromeos/components/proximity_auth/logging/logging.h"
#include "chromeos/components/proximity_auth/messenger_observer.h" #include "chromeos/components/proximity_auth/messenger_observer.h"
#include "chromeos/components/proximity_auth/remote_status_update.h" #include "chromeos/components/proximity_auth/remote_status_update.h"
...@@ -23,6 +24,7 @@ ...@@ -23,6 +24,7 @@
#include "components/cryptauth/wire_message.h" #include "components/cryptauth/wire_message.h"
namespace proximity_auth { namespace proximity_auth {
namespace { namespace {
// The key names of JSON fields for messages sent between the devices. // The key names of JSON fields for messages sent between the devices.
...@@ -63,17 +65,27 @@ std::string GetMessageType(const base::DictionaryValue& message) { ...@@ -63,17 +65,27 @@ std::string GetMessageType(const base::DictionaryValue& message) {
MessengerImpl::MessengerImpl( MessengerImpl::MessengerImpl(
std::unique_ptr<cryptauth::Connection> connection, std::unique_ptr<cryptauth::Connection> connection,
std::unique_ptr<cryptauth::SecureContext> secure_context) std::unique_ptr<cryptauth::SecureContext> secure_context,
std::unique_ptr<chromeos::secure_channel::ClientChannel> channel)
: connection_(std::move(connection)), : connection_(std::move(connection)),
secure_context_(std::move(secure_context)), secure_context_(std::move(secure_context)),
channel_(std::move(channel)),
weak_ptr_factory_(this) { weak_ptr_factory_(this) {
if (base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)) {
DCHECK(!channel_->is_disconnected());
channel_->AddObserver(this);
} else {
DCHECK(connection_->IsConnected()); DCHECK(connection_->IsConnected());
connection_->AddObserver(this); connection_->AddObserver(this);
}
} }
MessengerImpl::~MessengerImpl() { MessengerImpl::~MessengerImpl() {
if (connection_) if (base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)) {
channel_->RemoveObserver(this);
} else if (connection_) {
connection_->RemoveObserver(this); connection_->RemoveObserver(this);
}
} }
void MessengerImpl::AddObserver(MessengerObserver* observer) { void MessengerImpl::AddObserver(MessengerObserver* observer) {
...@@ -85,6 +97,9 @@ void MessengerImpl::RemoveObserver(MessengerObserver* observer) { ...@@ -85,6 +97,9 @@ void MessengerImpl::RemoveObserver(MessengerObserver* observer) {
} }
bool MessengerImpl::SupportsSignIn() const { bool MessengerImpl::SupportsSignIn() const {
if (base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi))
return true;
return (secure_context_->GetProtocolVersion() == return (secure_context_->GetProtocolVersion() ==
cryptauth::SecureContext::PROTOCOL_VERSION_THREE_ONE); cryptauth::SecureContext::PROTOCOL_VERSION_THREE_ONE);
} }
...@@ -135,14 +150,25 @@ void MessengerImpl::RequestUnlock() { ...@@ -135,14 +150,25 @@ void MessengerImpl::RequestUnlock() {
} }
cryptauth::SecureContext* MessengerImpl::GetSecureContext() const { cryptauth::SecureContext* MessengerImpl::GetSecureContext() const {
DCHECK(!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi));
return secure_context_.get(); return secure_context_.get();
} }
cryptauth::Connection* MessengerImpl::GetConnection() const { cryptauth::Connection* MessengerImpl::GetConnection() const {
DCHECK(!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi));
return connection_.get(); return connection_.get();
} }
MessengerImpl::PendingMessage::PendingMessage() {} chromeos::secure_channel::ClientChannel* MessengerImpl::GetChannel() const {
if (channel_->is_disconnected())
return nullptr;
return channel_.get();
}
MessengerImpl::PendingMessage::PendingMessage() = default;
MessengerImpl::PendingMessage::~PendingMessage() = default;
MessengerImpl::PendingMessage::PendingMessage( MessengerImpl::PendingMessage::PendingMessage(
const base::DictionaryValue& message) const base::DictionaryValue& message)
...@@ -152,83 +178,41 @@ MessengerImpl::PendingMessage::PendingMessage( ...@@ -152,83 +178,41 @@ MessengerImpl::PendingMessage::PendingMessage(
MessengerImpl::PendingMessage::PendingMessage(const std::string& message) MessengerImpl::PendingMessage::PendingMessage(const std::string& message)
: json_message(message), type(std::string()) {} : json_message(message), type(std::string()) {}
MessengerImpl::PendingMessage::~PendingMessage() {}
void MessengerImpl::ProcessMessageQueue() { void MessengerImpl::ProcessMessageQueue() {
if (pending_message_ || queued_messages_.empty() || if (pending_message_ || queued_messages_.empty())
connection_->is_sending_message())
return; return;
pending_message_.reset(new PendingMessage(queued_messages_.front())); if (base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi) &&
queued_messages_.pop_front(); channel_->is_disconnected()) {
secure_context_->Encode(pending_message_->json_message,
base::Bind(&MessengerImpl::OnMessageEncoded,
weak_ptr_factory_.GetWeakPtr()));
}
void MessengerImpl::OnMessageEncoded(const std::string& encoded_message) {
connection_->SendMessage(std::make_unique<cryptauth::WireMessage>(
encoded_message, std::string(kEasyUnlockFeatureName)));
}
void MessengerImpl::OnMessageDecoded(const std::string& decoded_message) {
// The decoded message should be a JSON string.
std::unique_ptr<base::Value> message_value =
base::JSONReader::Read(decoded_message);
if (!message_value || !message_value->is_dict()) {
PA_LOG(ERROR) << "Unable to parse message as JSON:\n" << decoded_message;
return; return;
} }
base::DictionaryValue* message; if (!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi) &&
bool success = message_value->GetAsDictionary(&message); connection_->is_sending_message()) {
DCHECK(success);
std::string type;
if (!message->GetString(kTypeKey, &type)) {
PA_LOG(ERROR) << "Missing '" << kTypeKey << "' key in message:\n "
<< decoded_message;
return;
}
// Remote status updates can be received out of the blue.
if (type == kMessageTypeRemoteStatusUpdate) {
HandleRemoteStatusUpdateMessage(*message);
return; return;
} }
// All other messages should only be received in response to a message that pending_message_.reset(new PendingMessage(queued_messages_.front()));
// the messenger sent. queued_messages_.pop_front();
if (!pending_message_) {
PA_LOG(WARNING) << "Unexpected message received:\n" << decoded_message;
return;
}
std::string expected_type;
if (pending_message_->type == kMessageTypeDecryptRequest)
expected_type = kMessageTypeDecryptResponse;
else if (pending_message_->type == kMessageTypeUnlockRequest)
expected_type = kMessageTypeUnlockResponse;
else
NOTREACHED(); // There are no other message types that expect a response.
if (type != expected_type) { if (base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)) {
PA_LOG(ERROR) << "Unexpected '" << kTypeKey << "' value in message. " channel_->SendMessage(
<< "Expected '" << expected_type << "' but received '" << type pending_message_->json_message,
<< "'."; base::BindOnce(&MessengerImpl::OnSendMessageResult,
return; weak_ptr_factory_.GetWeakPtr(), true /* success */));
} else {
secure_context_->Encode(
pending_message_->json_message,
base::BindRepeating(&MessengerImpl::OnMessageEncoded,
weak_ptr_factory_.GetWeakPtr()));
} }
}
if (type == kMessageTypeDecryptResponse) void MessengerImpl::OnMessageEncoded(const std::string& encoded_message) {
HandleDecryptResponseMessage(*message); DCHECK(!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi));
else if (type == kMessageTypeUnlockResponse)
HandleUnlockResponseMessage(*message);
else
NOTREACHED(); // There are no other message types that expect a response.
pending_message_.reset(); connection_->SendMessage(std::make_unique<cryptauth::WireMessage>(
ProcessMessageQueue(); encoded_message, kEasyUnlockFeatureName));
} }
void MessengerImpl::HandleRemoteStatusUpdateMessage( void MessengerImpl::HandleRemoteStatusUpdateMessage(
...@@ -270,6 +254,8 @@ void MessengerImpl::OnConnectionStatusChanged( ...@@ -270,6 +254,8 @@ void MessengerImpl::OnConnectionStatusChanged(
cryptauth::Connection* connection, cryptauth::Connection* connection,
cryptauth::Connection::Status old_status, cryptauth::Connection::Status old_status,
cryptauth::Connection::Status new_status) { cryptauth::Connection::Status new_status) {
DCHECK(!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi));
DCHECK_EQ(connection, connection_.get()); DCHECK_EQ(connection, connection_.get());
if (new_status == cryptauth::Connection::Status::DISCONNECTED) { if (new_status == cryptauth::Connection::Status::DISCONNECTED) {
PA_LOG(INFO) << "Secure channel disconnected..."; PA_LOG(INFO) << "Secure channel disconnected...";
...@@ -284,14 +270,92 @@ void MessengerImpl::OnConnectionStatusChanged( ...@@ -284,14 +270,92 @@ void MessengerImpl::OnConnectionStatusChanged(
void MessengerImpl::OnMessageReceived( void MessengerImpl::OnMessageReceived(
const cryptauth::Connection& connection, const cryptauth::Connection& connection,
const cryptauth::WireMessage& wire_message) { const cryptauth::WireMessage& wire_message) {
DCHECK(!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi));
secure_context_->Decode(wire_message.payload(), secure_context_->Decode(wire_message.payload(),
base::Bind(&MessengerImpl::OnMessageDecoded, base::BindRepeating(&MessengerImpl::HandleMessage,
weak_ptr_factory_.GetWeakPtr())); weak_ptr_factory_.GetWeakPtr()));
} }
void MessengerImpl::OnSendCompleted(const cryptauth::Connection& connection, void MessengerImpl::OnSendCompleted(const cryptauth::Connection& connection,
const cryptauth::WireMessage& wire_message, const cryptauth::WireMessage& wire_message,
bool success) { bool success) {
DCHECK(!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi));
OnSendMessageResult(success);
}
void MessengerImpl::OnDisconnected() {
DCHECK(base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi));
for (auto& observer : observers_)
observer.OnDisconnected();
}
void MessengerImpl::OnMessageReceived(const std::string& payload) {
DCHECK(base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi));
HandleMessage(payload);
}
void MessengerImpl::HandleMessage(const std::string& message) {
// The decoded message should be a JSON string.
std::unique_ptr<base::Value> message_value = base::JSONReader::Read(message);
if (!message_value || !message_value->is_dict()) {
PA_LOG(ERROR) << "Unable to parse message as JSON:\n" << message;
return;
}
base::DictionaryValue* message_dictionary;
bool success = message_value->GetAsDictionary(&message_dictionary);
DCHECK(success);
std::string type;
if (!message_dictionary->GetString(kTypeKey, &type)) {
PA_LOG(ERROR) << "Missing '" << kTypeKey << "' key in message:\n "
<< message;
return;
}
// Remote status updates can be received out of the blue.
if (type == kMessageTypeRemoteStatusUpdate) {
HandleRemoteStatusUpdateMessage(*message_dictionary);
return;
}
// All other messages should only be received in response to a message that
// the messenger sent.
if (!pending_message_) {
PA_LOG(WARNING) << "Unexpected message received: " << message;
return;
}
std::string expected_type;
if (pending_message_->type == kMessageTypeDecryptRequest)
expected_type = kMessageTypeDecryptResponse;
else if (pending_message_->type == kMessageTypeUnlockRequest)
expected_type = kMessageTypeUnlockResponse;
else
NOTREACHED(); // There are no other message types that expect a response.
if (type != expected_type) {
PA_LOG(ERROR) << "Unexpected '" << kTypeKey << "' value in message. "
<< "Expected '" << expected_type << "' but received '" << type
<< "'.";
return;
}
if (type == kMessageTypeDecryptResponse)
HandleDecryptResponseMessage(*message_dictionary);
else if (type == kMessageTypeUnlockResponse)
HandleUnlockResponseMessage(*message_dictionary);
else
NOTREACHED(); // There are no other message types that expect a response.
pending_message_.reset();
ProcessMessageQueue();
}
void MessengerImpl::OnSendMessageResult(bool success) {
if (!pending_message_) { if (!pending_message_) {
PA_LOG(ERROR) << "Unexpected message sent."; PA_LOG(ERROR) << "Unexpected message sent.";
return; return;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/observer_list.h" #include "base/observer_list.h"
#include "chromeos/components/proximity_auth/messenger.h" #include "chromeos/components/proximity_auth/messenger.h"
#include "chromeos/services/secure_channel/public/cpp/client/client_channel.h"
#include "components/cryptauth/connection.h" #include "components/cryptauth/connection.h"
#include "components/cryptauth/connection_observer.h" #include "components/cryptauth/connection_observer.h"
...@@ -26,14 +27,24 @@ class SecureContext; ...@@ -26,14 +27,24 @@ class SecureContext;
namespace proximity_auth { namespace proximity_auth {
// Concrete implementation of the Messenger interface. // Concrete implementation of the Messenger interface.
class MessengerImpl : public Messenger, public cryptauth::ConnectionObserver { class MessengerImpl : public Messenger,
public cryptauth::ConnectionObserver,
public chromeos::secure_channel::ClientChannel::Observer {
public: public:
// Constructs a messenger that sends and receives messages over the given // Constructs a messenger that sends and receives messages.
// |connection|, using the |secure_context| to encrypt and decrypt the //
// messages. The |connection| must be connected. The messenger begins // If the |chromeos::features::kMultiDeviceApi| flag is enabled, messages are
// observing messages as soon as it is constructed. // relayed over the provided |channel|, and |connection| and |secure_context|
MessengerImpl(std::unique_ptr<cryptauth::Connection> connection, // are ignored.
std::unique_ptr<cryptauth::SecureContext> secure_context); //
// If not, messages are relayed over |connection|, using the |secure_context|
// to encrypt and decrypt the messages. |channel| is ignored.
//
// The messenger begins observing messages as soon as it is constructed.
MessengerImpl(
std::unique_ptr<cryptauth::Connection> connection,
std::unique_ptr<cryptauth::SecureContext> secure_context,
std::unique_ptr<chromeos::secure_channel::ClientChannel> channel);
~MessengerImpl() override; ~MessengerImpl() override;
// Messenger: // Messenger:
...@@ -45,6 +56,7 @@ class MessengerImpl : public Messenger, public cryptauth::ConnectionObserver { ...@@ -45,6 +56,7 @@ class MessengerImpl : public Messenger, public cryptauth::ConnectionObserver {
void RequestUnlock() override; void RequestUnlock() override;
cryptauth::SecureContext* GetSecureContext() const override; cryptauth::SecureContext* GetSecureContext() const override;
cryptauth::Connection* GetConnection() const override; cryptauth::Connection* GetConnection() const override;
chromeos::secure_channel::ClientChannel* GetChannel() const override;
// Exposed for testing. // Exposed for testing.
cryptauth::Connection* connection() { return connection_.get(); } cryptauth::Connection* connection() { return connection_.get(); }
...@@ -72,9 +84,6 @@ class MessengerImpl : public Messenger, public cryptauth::ConnectionObserver { ...@@ -72,9 +84,6 @@ class MessengerImpl : public Messenger, public cryptauth::ConnectionObserver {
// Called when the message is encoded so it can be sent over the connection. // Called when the message is encoded so it can be sent over the connection.
void OnMessageEncoded(const std::string& encoded_message); void OnMessageEncoded(const std::string& encoded_message);
// Called when the message is decoded so it can be parsed.
void OnMessageDecoded(const std::string& decoded_message);
// Handles an incoming "status_update" |message|, parsing and notifying // Handles an incoming "status_update" |message|, parsing and notifying
// observers of the content. // observers of the content.
void HandleRemoteStatusUpdateMessage(const base::DictionaryValue& message); void HandleRemoteStatusUpdateMessage(const base::DictionaryValue& message);
...@@ -98,6 +107,17 @@ class MessengerImpl : public Messenger, public cryptauth::ConnectionObserver { ...@@ -98,6 +107,17 @@ class MessengerImpl : public Messenger, public cryptauth::ConnectionObserver {
const cryptauth::WireMessage& wire_message, const cryptauth::WireMessage& wire_message,
bool success) override; bool success) override;
// chromeos::secure_channel::ClientChannel::Observer:
void OnDisconnected() override;
void OnMessageReceived(const std::string& payload) override;
// Called when a message has been recevied from the remote device. The message
// should be a valid JSON string.
void HandleMessage(const std::string& message);
// Called when a message has been sent to the remote device.
void OnSendMessageResult(bool success);
// The connection used to send and receive events and status updates. // The connection used to send and receive events and status updates.
std::unique_ptr<cryptauth::Connection> connection_; std::unique_ptr<cryptauth::Connection> connection_;
...@@ -105,6 +125,10 @@ class MessengerImpl : public Messenger, public cryptauth::ConnectionObserver { ...@@ -105,6 +125,10 @@ class MessengerImpl : public Messenger, public cryptauth::ConnectionObserver {
// |connection_|. // |connection_|.
std::unique_ptr<cryptauth::SecureContext> secure_context_; std::unique_ptr<cryptauth::SecureContext> secure_context_;
// Authenticated end-to-end channel used to communicate with the remote
// device.
std::unique_ptr<chromeos::secure_channel::ClientChannel> channel_;
// The registered observers of |this_| messenger. // The registered observers of |this_| messenger.
base::ObserverList<MessengerObserver> observers_; base::ObserverList<MessengerObserver> observers_;
......
...@@ -8,8 +8,11 @@ ...@@ -8,8 +8,11 @@
#include "base/callback.h" #include "base/callback.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/test/scoped_feature_list.h"
#include "chromeos/chromeos_features.h"
#include "chromeos/components/proximity_auth/messenger_observer.h" #include "chromeos/components/proximity_auth/messenger_observer.h"
#include "chromeos/components/proximity_auth/remote_status_update.h" #include "chromeos/components/proximity_auth/remote_status_update.h"
#include "chromeos/services/secure_channel/public/cpp/client/fake_client_channel.h"
#include "components/cryptauth/connection.h" #include "components/cryptauth/connection.h"
#include "components/cryptauth/fake_connection.h" #include "components/cryptauth/fake_connection.h"
#include "components/cryptauth/fake_secure_context.h" #include "components/cryptauth/fake_secure_context.h"
...@@ -29,6 +32,7 @@ using testing::Return; ...@@ -29,6 +32,7 @@ using testing::Return;
using testing::StrictMock; using testing::StrictMock;
namespace proximity_auth { namespace proximity_auth {
namespace { namespace {
const char kTestFeature[] = "testFeature"; const char kTestFeature[] = "testFeature";
...@@ -62,16 +66,15 @@ class MockMessengerObserver : public MessengerObserver { ...@@ -62,16 +66,15 @@ class MockMessengerObserver : public MessengerObserver {
class TestMessenger : public MessengerImpl { class TestMessenger : public MessengerImpl {
public: public:
TestMessenger() TestMessenger(
std::unique_ptr<chromeos::secure_channel::ClientChannel> channel)
: MessengerImpl(std::make_unique<cryptauth::FakeConnection>( : MessengerImpl(std::make_unique<cryptauth::FakeConnection>(
cryptauth::CreateRemoteDeviceRefForTest()), cryptauth::CreateRemoteDeviceRefForTest()),
std::make_unique<cryptauth::FakeSecureContext>()) {} std::make_unique<cryptauth::FakeSecureContext>(),
explicit TestMessenger(std::unique_ptr<cryptauth::Connection> connection) std::move(channel)) {}
: MessengerImpl(std::move(connection),
std::make_unique<cryptauth::FakeSecureContext>()) {}
~TestMessenger() override {} ~TestMessenger() override {}
// Simple getters for the mock objects owned by |this| messenger. // Simple getters for the fake objects owned by |this| messenger_->
cryptauth::FakeConnection* GetFakeConnection() { cryptauth::FakeConnection* GetFakeConnection() {
return static_cast<cryptauth::FakeConnection*>(connection()); return static_cast<cryptauth::FakeConnection*>(connection());
} }
...@@ -85,35 +88,88 @@ class TestMessenger : public MessengerImpl { ...@@ -85,35 +88,88 @@ class TestMessenger : public MessengerImpl {
} // namespace } // namespace
TEST(ProximityAuthMessengerImplTest, SupportsSignIn_ProtocolVersionThreeZero) { class ProximityAuthMessengerImplTest : public testing::Test {
TestMessenger messenger; protected:
messenger.GetFakeSecureContext()->set_protocol_version( ProximityAuthMessengerImplTest() = default;
void SetMultiDeviceApiEnabled() {
scoped_feature_list_.InitAndEnableFeature(
chromeos::features::kMultiDeviceApi);
}
void CreateMessenger(bool is_multi_device_api_enabled) {
if (is_multi_device_api_enabled)
SetMultiDeviceApiEnabled();
auto fake_channel =
std::make_unique<chromeos::secure_channel::FakeClientChannel>();
fake_channel_ = fake_channel.get();
messenger_ = std::make_unique<TestMessenger>(std::move(fake_channel));
observer_ = std::make_unique<MockMessengerObserver>(messenger_.get());
}
std::string GetLastSentMessage() {
std::vector<std::pair<std::string, base::OnceClosure>>&
message_and_callbacks = fake_channel_->sent_messages();
std::move(message_and_callbacks[0].second).Run();
std::string message_copy = message_and_callbacks[0].first;
message_and_callbacks.erase(message_and_callbacks.begin());
return message_copy;
}
chromeos::secure_channel::FakeClientChannel* fake_channel_;
std::unique_ptr<TestMessenger> messenger_;
std::unique_ptr<MockMessengerObserver> observer_;
private:
base::test::ScopedFeatureList scoped_feature_list_;
DISALLOW_COPY_AND_ASSIGN(ProximityAuthMessengerImplTest);
};
TEST_F(ProximityAuthMessengerImplTest,
SupportsSignIn_ProtocolVersionThreeZero) {
CreateMessenger(false /* is_multi_device_api_enabled */);
messenger_->GetFakeSecureContext()->set_protocol_version(
cryptauth::SecureContext::PROTOCOL_VERSION_THREE_ZERO); cryptauth::SecureContext::PROTOCOL_VERSION_THREE_ZERO);
EXPECT_FALSE(messenger.SupportsSignIn()); EXPECT_FALSE(messenger_->SupportsSignIn());
} }
TEST(ProximityAuthMessengerImplTest, SupportsSignIn_ProtocolVersionThreeOne) { TEST_F(ProximityAuthMessengerImplTest, SupportsSignIn_ProtocolVersionThreeOne) {
TestMessenger messenger; CreateMessenger(false /* is_multi_device_api_enabled */);
messenger.GetFakeSecureContext()->set_protocol_version(
messenger_->GetFakeSecureContext()->set_protocol_version(
cryptauth::SecureContext::PROTOCOL_VERSION_THREE_ONE); cryptauth::SecureContext::PROTOCOL_VERSION_THREE_ONE);
EXPECT_TRUE(messenger.SupportsSignIn()); EXPECT_TRUE(messenger_->SupportsSignIn());
}
TEST_F(ProximityAuthMessengerImplTest, SupportsSignIn_MultiDeviceApiEnabled) {
CreateMessenger(true /* is_multi_device_api_enabled */);
EXPECT_TRUE(messenger_->SupportsSignIn());
} }
TEST(ProximityAuthMessengerImplTest, TEST_F(ProximityAuthMessengerImplTest,
OnConnectionStatusChanged_ConnectionDisconnects) { OnConnectionStatusChanged_ConnectionDisconnects) {
TestMessenger messenger; CreateMessenger(false /* is_multi_device_api_enabled */);
MockMessengerObserver observer(&messenger);
EXPECT_CALL(observer, OnDisconnected()); EXPECT_CALL(*observer_, OnDisconnected());
messenger.GetFakeConnection()->Disconnect(); messenger_->GetFakeConnection()->Disconnect();
} }
TEST(ProximityAuthMessengerImplTest, DispatchUnlockEvent_SendsExpectedMessage) { TEST_F(ProximityAuthMessengerImplTest,
TestMessenger messenger; DispatchUnlockEvent_SendsExpectedMessage) {
messenger.DispatchUnlockEvent(); CreateMessenger(false /* is_multi_device_api_enabled */);
messenger_->DispatchUnlockEvent();
cryptauth::WireMessage* message = cryptauth::WireMessage* message =
messenger.GetFakeConnection()->current_message(); messenger_->GetFakeConnection()->current_message();
ASSERT_TRUE(message); ASSERT_TRUE(message);
EXPECT_EQ( EXPECT_EQ(
"{" "{"
...@@ -124,39 +180,56 @@ TEST(ProximityAuthMessengerImplTest, DispatchUnlockEvent_SendsExpectedMessage) { ...@@ -124,39 +180,56 @@ TEST(ProximityAuthMessengerImplTest, DispatchUnlockEvent_SendsExpectedMessage) {
EXPECT_EQ("easy_unlock", message->feature()); EXPECT_EQ("easy_unlock", message->feature());
} }
TEST(ProximityAuthMessengerImplTest, DispatchUnlockEvent_SendMessageFails) { TEST_F(ProximityAuthMessengerImplTest,
TestMessenger messenger; DispatchUnlockEvent_SendsExpectedMessage_MultiDeviceApiEnabled) {
MockMessengerObserver observer(&messenger); CreateMessenger(true /* is_multi_device_api_enabled */);
messenger.DispatchUnlockEvent();
EXPECT_CALL(observer, OnUnlockEventSent(false)); messenger_->DispatchUnlockEvent();
messenger.GetFakeConnection()->FinishSendingMessageWithSuccess(false);
EXPECT_EQ(
"{"
"\"name\":\"easy_unlock\","
"\"type\":\"event\""
"}",
GetLastSentMessage());
} }
TEST(ProximityAuthMessengerImplTest, DispatchUnlockEvent_SendMessageSucceeds) { TEST_F(ProximityAuthMessengerImplTest, DispatchUnlockEvent_SendMessageFails) {
TestMessenger messenger; CreateMessenger(false /* is_multi_device_api_enabled */);
MockMessengerObserver observer(&messenger);
messenger.DispatchUnlockEvent(); messenger_->DispatchUnlockEvent();
EXPECT_CALL(observer, OnUnlockEventSent(true)); EXPECT_CALL(*observer_, OnUnlockEventSent(false));
messenger.GetFakeConnection()->FinishSendingMessageWithSuccess(true); messenger_->GetFakeConnection()->FinishSendingMessageWithSuccess(false);
} }
TEST(ProximityAuthMessengerImplTest, TEST_F(ProximityAuthMessengerImplTest,
DispatchUnlockEvent_SendMessageSucceeds) {
CreateMessenger(false /* is_multi_device_api_enabled */);
messenger_->DispatchUnlockEvent();
EXPECT_CALL(*observer_, OnUnlockEventSent(true));
messenger_->GetFakeConnection()->FinishSendingMessageWithSuccess(true);
}
TEST_F(ProximityAuthMessengerImplTest,
RequestDecryption_SignInUnsupported_DoesntSendMessage) { RequestDecryption_SignInUnsupported_DoesntSendMessage) {
TestMessenger messenger; CreateMessenger(false /* is_multi_device_api_enabled */);
messenger.GetFakeSecureContext()->set_protocol_version(
messenger_->GetFakeSecureContext()->set_protocol_version(
cryptauth::SecureContext::PROTOCOL_VERSION_THREE_ZERO); cryptauth::SecureContext::PROTOCOL_VERSION_THREE_ZERO);
messenger.RequestDecryption(kChallenge); messenger_->RequestDecryption(kChallenge);
EXPECT_FALSE(messenger.GetFakeConnection()->current_message()); EXPECT_FALSE(messenger_->GetFakeConnection()->current_message());
} }
TEST(ProximityAuthMessengerImplTest, RequestDecryption_SendsExpectedMessage) { TEST_F(ProximityAuthMessengerImplTest, RequestDecryption_SendsExpectedMessage) {
TestMessenger messenger; CreateMessenger(false /* is_multi_device_api_enabled */);
messenger.RequestDecryption(kChallenge);
messenger_->RequestDecryption(kChallenge);
cryptauth::WireMessage* message = cryptauth::WireMessage* message =
messenger.GetFakeConnection()->current_message(); messenger_->GetFakeConnection()->current_message();
ASSERT_TRUE(message); ASSERT_TRUE(message);
EXPECT_EQ( EXPECT_EQ(
"{" "{"
...@@ -166,13 +239,28 @@ TEST(ProximityAuthMessengerImplTest, RequestDecryption_SendsExpectedMessage) { ...@@ -166,13 +239,28 @@ TEST(ProximityAuthMessengerImplTest, RequestDecryption_SendsExpectedMessage) {
message->payload()); message->payload());
} }
TEST(ProximityAuthMessengerImplTest, TEST_F(ProximityAuthMessengerImplTest,
RequestDecryption_SendsExpectedMessage_MultiDeviceApiEnabled) {
CreateMessenger(true /* is_multi_device_api_enabled */);
messenger_->RequestDecryption(kChallenge);
EXPECT_EQ(
"{"
"\"encrypted_data\":\"YSBtb3N0IGRpZmZpY3VsdCBjaGFsbGVuZ2U=\","
"\"type\":\"decrypt_request\""
"}",
GetLastSentMessage());
}
TEST_F(ProximityAuthMessengerImplTest,
RequestDecryption_SendsExpectedMessage_UsingBase64UrlEncoding) { RequestDecryption_SendsExpectedMessage_UsingBase64UrlEncoding) {
TestMessenger messenger; CreateMessenger(false /* is_multi_device_api_enabled */);
messenger.RequestDecryption("\xFF\xE6");
messenger_->RequestDecryption("\xFF\xE6");
cryptauth::WireMessage* message = cryptauth::WireMessage* message =
messenger.GetFakeConnection()->current_message(); messenger_->GetFakeConnection()->current_message();
ASSERT_TRUE(message); ASSERT_TRUE(message);
EXPECT_EQ( EXPECT_EQ(
"{" "{"
...@@ -182,47 +270,73 @@ TEST(ProximityAuthMessengerImplTest, ...@@ -182,47 +270,73 @@ TEST(ProximityAuthMessengerImplTest,
message->payload()); message->payload());
} }
TEST(ProximityAuthMessengerImplTest, RequestDecryption_SendMessageFails) { TEST_F(
TestMessenger messenger; ProximityAuthMessengerImplTest,
MockMessengerObserver observer(&messenger); RequestDecryption_SendsExpectedMessage_UsingBase64UrlEncoding_MultiDeviceApiEnabled) {
messenger.RequestDecryption(kChallenge); CreateMessenger(true /* is_multi_device_api_enabled */);
EXPECT_CALL(observer, OnDecryptResponseProxy(std::string())); messenger_->RequestDecryption("\xFF\xE6");
messenger.GetFakeConnection()->FinishSendingMessageWithSuccess(false);
EXPECT_EQ(
"{"
"\"encrypted_data\":\"_-Y=\","
"\"type\":\"decrypt_request\""
"}",
GetLastSentMessage());
} }
TEST(ProximityAuthMessengerImplTest, TEST_F(ProximityAuthMessengerImplTest, RequestDecryption_SendMessageFails) {
CreateMessenger(false /* is_multi_device_api_enabled */);
messenger_->RequestDecryption(kChallenge);
EXPECT_CALL(*observer_, OnDecryptResponseProxy(std::string()));
messenger_->GetFakeConnection()->FinishSendingMessageWithSuccess(false);
}
TEST_F(ProximityAuthMessengerImplTest,
RequestDecryption_SendSucceeds_WaitsForReply) { RequestDecryption_SendSucceeds_WaitsForReply) {
TestMessenger messenger; CreateMessenger(false /* is_multi_device_api_enabled */);
MockMessengerObserver observer(&messenger);
messenger.RequestDecryption(kChallenge); messenger_->RequestDecryption(kChallenge);
EXPECT_CALL(observer, OnDecryptResponseProxy(_)).Times(0); EXPECT_CALL(*observer_, OnDecryptResponseProxy(_)).Times(0);
messenger.GetFakeConnection()->FinishSendingMessageWithSuccess(true); messenger_->GetFakeConnection()->FinishSendingMessageWithSuccess(true);
} }
TEST(ProximityAuthMessengerImplTest, TEST_F(ProximityAuthMessengerImplTest,
RequestDecryption_SendSucceeds_NotifiesObserversOnReply_NoData) { RequestDecryption_SendSucceeds_NotifiesObserversOnReply_NoData) {
TestMessenger messenger; CreateMessenger(false /* is_multi_device_api_enabled */);
MockMessengerObserver observer(&messenger);
messenger.RequestDecryption(kChallenge); messenger_->RequestDecryption(kChallenge);
messenger.GetFakeConnection()->FinishSendingMessageWithSuccess(true); messenger_->GetFakeConnection()->FinishSendingMessageWithSuccess(true);
EXPECT_CALL(observer, OnDecryptResponseProxy(std::string())); EXPECT_CALL(*observer_, OnDecryptResponseProxy(std::string()));
messenger.GetFakeConnection()->ReceiveMessage( messenger_->GetFakeConnection()->ReceiveMessage(
std::string(kTestFeature), std::string(kTestFeature),
"{\"type\":\"decrypt_response\"}, but encoded"); "{\"type\":\"decrypt_response\"}, but encoded");
} }
TEST(ProximityAuthMessengerImplTest, TEST_F(
ProximityAuthMessengerImplTest,
RequestDecryption_SendSucceeds_NotifiesObserversOnReply_NoData_MultiDeviceApiEnabled) {
CreateMessenger(true /* is_multi_device_api_enabled */);
messenger_->RequestDecryption(kChallenge);
EXPECT_CALL(*observer_, OnDecryptResponseProxy(std::string()));
fake_channel_->NotifyMessageReceived("{\"type\":\"decrypt_response\"}");
}
TEST_F(ProximityAuthMessengerImplTest,
RequestDecryption_SendSucceeds_NotifiesObserversOnReply_InvalidData) { RequestDecryption_SendSucceeds_NotifiesObserversOnReply_InvalidData) {
TestMessenger messenger; CreateMessenger(false /* is_multi_device_api_enabled */);
MockMessengerObserver observer(&messenger);
messenger.RequestDecryption(kChallenge); messenger_->RequestDecryption(kChallenge);
messenger.GetFakeConnection()->FinishSendingMessageWithSuccess(true); messenger_->GetFakeConnection()->FinishSendingMessageWithSuccess(true);
EXPECT_CALL(observer, OnDecryptResponseProxy(std::string())); EXPECT_CALL(*observer_, OnDecryptResponseProxy(std::string()));
messenger.GetFakeConnection()->ReceiveMessage( messenger_->GetFakeConnection()->ReceiveMessage(
std::string(kTestFeature), std::string(kTestFeature),
"{" "{"
"\"type\":\"decrypt_response\"," "\"type\":\"decrypt_response\","
...@@ -230,15 +344,30 @@ TEST(ProximityAuthMessengerImplTest, ...@@ -230,15 +344,30 @@ TEST(ProximityAuthMessengerImplTest,
"}, but encoded"); "}, but encoded");
} }
TEST(ProximityAuthMessengerImplTest, TEST_F(
ProximityAuthMessengerImplTest,
RequestDecryption_SendSucceeds_NotifiesObserversOnReply_InvalidData_MultiDeviceApiEnabled) {
CreateMessenger(true /* is_multi_device_api_enabled */);
messenger_->RequestDecryption(kChallenge);
EXPECT_CALL(*observer_, OnDecryptResponseProxy(std::string()));
fake_channel_->NotifyMessageReceived(
"{"
"\"type\":\"decrypt_response\","
"\"data\":\"not a base64-encoded string\""
"}");
}
TEST_F(ProximityAuthMessengerImplTest,
RequestDecryption_SendSucceeds_NotifiesObserversOnReply_ValidData) { RequestDecryption_SendSucceeds_NotifiesObserversOnReply_ValidData) {
TestMessenger messenger; CreateMessenger(false /* is_multi_device_api_enabled */);
MockMessengerObserver observer(&messenger);
messenger.RequestDecryption(kChallenge);
messenger.GetFakeConnection()->FinishSendingMessageWithSuccess(true);
EXPECT_CALL(observer, OnDecryptResponseProxy("a winner is you")); messenger_->RequestDecryption(kChallenge);
messenger.GetFakeConnection()->ReceiveMessage( messenger_->GetFakeConnection()->FinishSendingMessageWithSuccess(true);
EXPECT_CALL(*observer_, OnDecryptResponseProxy("a winner is you"));
messenger_->GetFakeConnection()->ReceiveMessage(
std::string(kTestFeature), std::string(kTestFeature),
"{" "{"
"\"type\":\"decrypt_response\"," "\"type\":\"decrypt_response\","
...@@ -246,16 +375,31 @@ TEST(ProximityAuthMessengerImplTest, ...@@ -246,16 +375,31 @@ TEST(ProximityAuthMessengerImplTest,
"}, but encoded"); "}, but encoded");
} }
TEST_F(
ProximityAuthMessengerImplTest,
RequestDecryption_SendSucceeds_NotifiesObserversOnReply_ValidData_MultiDeviceApiEnabled) {
CreateMessenger(true /* is_multi_device_api_enabled */);
messenger_->RequestDecryption(kChallenge);
EXPECT_CALL(*observer_, OnDecryptResponseProxy("a winner is you"));
fake_channel_->NotifyMessageReceived(
"{"
"\"type\":\"decrypt_response\","
"\"data\":\"YSB3aW5uZXIgaXMgeW91\"" // "a winner is you", base64-encoded
"}");
}
// Verify that the messenger correctly parses base64url encoded data. // Verify that the messenger correctly parses base64url encoded data.
TEST(ProximityAuthMessengerImplTest, TEST_F(ProximityAuthMessengerImplTest,
RequestDecryption_SendSucceeds_ParsesBase64UrlEncodingInReply) { RequestDecryption_SendSucceeds_ParsesBase64UrlEncodingInReply) {
TestMessenger messenger; CreateMessenger(false /* is_multi_device_api_enabled */);
MockMessengerObserver observer(&messenger);
messenger.RequestDecryption(kChallenge);
messenger.GetFakeConnection()->FinishSendingMessageWithSuccess(true);
EXPECT_CALL(observer, OnDecryptResponseProxy("\xFF\xE6")); messenger_->RequestDecryption(kChallenge);
messenger.GetFakeConnection()->ReceiveMessage( messenger_->GetFakeConnection()->FinishSendingMessageWithSuccess(true);
EXPECT_CALL(*observer_, OnDecryptResponseProxy("\xFF\xE6"));
messenger_->GetFakeConnection()->ReceiveMessage(
std::string(kTestFeature), std::string(kTestFeature),
"{" "{"
"\"type\":\"decrypt_response\"," "\"type\":\"decrypt_response\","
...@@ -263,79 +407,126 @@ TEST(ProximityAuthMessengerImplTest, ...@@ -263,79 +407,126 @@ TEST(ProximityAuthMessengerImplTest,
"}, but encoded"); "}, but encoded");
} }
TEST(ProximityAuthMessengerImplTest, TEST_F(
ProximityAuthMessengerImplTest,
RequestDecryption_SendSucceeds_ParsesBase64UrlEncodingInReply_MultiDeviceApiEnabled) {
CreateMessenger(true /* is_multi_device_api_enabled */);
messenger_->RequestDecryption(kChallenge);
EXPECT_CALL(*observer_, OnDecryptResponseProxy("\xFF\xE6"));
fake_channel_->NotifyMessageReceived(
"{"
"\"type\":\"decrypt_response\","
"\"data\":\"_-Y=\"" // "\0xFF\0xE6", base64url-encoded.
"}");
}
TEST_F(ProximityAuthMessengerImplTest,
RequestUnlock_SignInUnsupported_DoesntSendMessage) { RequestUnlock_SignInUnsupported_DoesntSendMessage) {
TestMessenger messenger; CreateMessenger(false /* is_multi_device_api_enabled */);
messenger.GetFakeSecureContext()->set_protocol_version(
messenger_->GetFakeSecureContext()->set_protocol_version(
cryptauth::SecureContext::PROTOCOL_VERSION_THREE_ZERO); cryptauth::SecureContext::PROTOCOL_VERSION_THREE_ZERO);
messenger.RequestUnlock(); messenger_->RequestUnlock();
EXPECT_FALSE(messenger.GetFakeConnection()->current_message()); EXPECT_FALSE(messenger_->GetFakeConnection()->current_message());
} }
TEST(ProximityAuthMessengerImplTest, RequestUnlock_SendsExpectedMessage) { TEST_F(ProximityAuthMessengerImplTest, RequestUnlock_SendsExpectedMessage) {
TestMessenger messenger; CreateMessenger(false /* is_multi_device_api_enabled */);
messenger.RequestUnlock();
messenger_->RequestUnlock();
cryptauth::WireMessage* message = cryptauth::WireMessage* message =
messenger.GetFakeConnection()->current_message(); messenger_->GetFakeConnection()->current_message();
ASSERT_TRUE(message); ASSERT_TRUE(message);
EXPECT_EQ("{\"type\":\"unlock_request\"}, but encoded", message->payload()); EXPECT_EQ("{\"type\":\"unlock_request\"}, but encoded", message->payload());
} }
TEST(ProximityAuthMessengerImplTest, RequestUnlock_SendMessageFails) { TEST_F(ProximityAuthMessengerImplTest,
TestMessenger messenger; RequestUnlock_SendsExpectedMessage_MultiDeviceApiEnabled) {
MockMessengerObserver observer(&messenger); CreateMessenger(true /* is_multi_device_api_enabled */);
messenger.RequestUnlock();
EXPECT_CALL(observer, OnUnlockResponse(false)); messenger_->RequestUnlock();
messenger.GetFakeConnection()->FinishSendingMessageWithSuccess(false);
EXPECT_EQ("{\"type\":\"unlock_request\"}", GetLastSentMessage());
} }
TEST(ProximityAuthMessengerImplTest, RequestUnlock_SendSucceeds_WaitsForReply) { TEST_F(ProximityAuthMessengerImplTest, RequestUnlock_SendMessageFails) {
TestMessenger messenger; CreateMessenger(false /* is_multi_device_api_enabled */);
MockMessengerObserver observer(&messenger);
messenger.RequestUnlock(); messenger_->RequestUnlock();
EXPECT_CALL(observer, OnUnlockResponse(_)).Times(0); EXPECT_CALL(*observer_, OnUnlockResponse(false));
messenger.GetFakeConnection()->FinishSendingMessageWithSuccess(true); messenger_->GetFakeConnection()->FinishSendingMessageWithSuccess(false);
} }
TEST(ProximityAuthMessengerImplTest, TEST_F(ProximityAuthMessengerImplTest,
RequestUnlock_SendSucceeds_WaitsForReply) {
CreateMessenger(false /* is_multi_device_api_enabled */);
messenger_->RequestUnlock();
EXPECT_CALL(*observer_, OnUnlockResponse(_)).Times(0);
messenger_->GetFakeConnection()->FinishSendingMessageWithSuccess(true);
}
TEST_F(ProximityAuthMessengerImplTest,
RequestUnlock_SendSucceeds_NotifiesObserversOnReply) { RequestUnlock_SendSucceeds_NotifiesObserversOnReply) {
TestMessenger messenger; CreateMessenger(false /* is_multi_device_api_enabled */);
MockMessengerObserver observer(&messenger);
messenger.RequestUnlock();
messenger.GetFakeConnection()->FinishSendingMessageWithSuccess(true);
EXPECT_CALL(observer, OnUnlockResponse(true)); messenger_->RequestUnlock();
messenger.GetFakeConnection()->ReceiveMessage( messenger_->GetFakeConnection()->FinishSendingMessageWithSuccess(true);
EXPECT_CALL(*observer_, OnUnlockResponse(true));
messenger_->GetFakeConnection()->ReceiveMessage(
std::string(kTestFeature), "{\"type\":\"unlock_response\"}, but encoded"); std::string(kTestFeature), "{\"type\":\"unlock_response\"}, but encoded");
} }
TEST(ProximityAuthMessengerImplTest, TEST_F(
ProximityAuthMessengerImplTest,
RequestUnlock_SendSucceeds_NotifiesObserversOnReply_MultiDeviceApiEnabled) {
CreateMessenger(true /* is_multi_device_api_enabled */);
messenger_->RequestUnlock();
EXPECT_CALL(*observer_, OnUnlockResponse(true));
fake_channel_->NotifyMessageReceived("{\"type\":\"unlock_response\"}");
}
TEST_F(ProximityAuthMessengerImplTest,
OnMessageReceived_RemoteStatusUpdate_Invalid) { OnMessageReceived_RemoteStatusUpdate_Invalid) {
TestMessenger messenger; CreateMessenger(false /* is_multi_device_api_enabled */);
MockMessengerObserver observer(&messenger);
// Receive a status update message that's missing all the data.
EXPECT_CALL(*observer_, OnRemoteStatusUpdate(_)).Times(0);
messenger_->GetFakeConnection()->ReceiveMessage(
std::string(kTestFeature), "{\"type\":\"status_update\"}, but encoded");
}
// ryan
TEST_F(ProximityAuthMessengerImplTest,
OnMessageReceived_RemoteStatusUpdate_Invalid_MultiDeviceApiEnabled) {
CreateMessenger(true /* is_multi_device_api_enabled */);
// Receive a status update message that's missing all the data. // Receive a status update message that's missing all the data.
EXPECT_CALL(observer, OnRemoteStatusUpdate(_)).Times(0); EXPECT_CALL(*observer_, OnRemoteStatusUpdate(_)).Times(0);
messenger.GetFakeConnection()->ReceiveMessage( messenger_->GetFakeConnection()->ReceiveMessage(
std::string(kTestFeature), "{\"type\":\"status_update\"}, but encoded"); std::string(kTestFeature), "{\"type\":\"status_update\"}, but encoded");
} }
TEST(ProximityAuthMessengerImplTest, TEST_F(ProximityAuthMessengerImplTest,
OnMessageReceived_RemoteStatusUpdate_Valid) { OnMessageReceived_RemoteStatusUpdate_Valid) {
TestMessenger messenger; CreateMessenger(false /* is_multi_device_api_enabled */);
MockMessengerObserver observer(&messenger);
EXPECT_CALL(observer, EXPECT_CALL(*observer_,
OnRemoteStatusUpdate( OnRemoteStatusUpdate(
AllOf(Field(&RemoteStatusUpdate::user_presence, USER_PRESENT), AllOf(Field(&RemoteStatusUpdate::user_presence, USER_PRESENT),
Field(&RemoteStatusUpdate::secure_screen_lock_state, Field(&RemoteStatusUpdate::secure_screen_lock_state,
SECURE_SCREEN_LOCK_ENABLED), SECURE_SCREEN_LOCK_ENABLED),
Field(&RemoteStatusUpdate::trust_agent_state, Field(&RemoteStatusUpdate::trust_agent_state,
TRUST_AGENT_UNSUPPORTED)))); TRUST_AGENT_UNSUPPORTED))));
messenger.GetFakeConnection()->ReceiveMessage( messenger_->GetFakeConnection()->ReceiveMessage(
std::string(kTestFeature), std::string(kTestFeature),
"{" "{"
"\"type\":\"status_update\"," "\"type\":\"status_update\","
...@@ -345,61 +536,132 @@ TEST(ProximityAuthMessengerImplTest, ...@@ -345,61 +536,132 @@ TEST(ProximityAuthMessengerImplTest,
"}, but encoded"); "}, but encoded");
} }
TEST(ProximityAuthMessengerImplTest, OnMessageReceived_InvalidJSON) { TEST_F(ProximityAuthMessengerImplTest,
TestMessenger messenger; OnMessageReceived_RemoteStatusUpdate_Valid_MultiDeviceApiEnabled) {
StrictMock<MockMessengerObserver> observer(&messenger); CreateMessenger(true /* is_multi_device_api_enabled */);
messenger.RequestUnlock();
messenger.GetFakeConnection()->FinishSendingMessageWithSuccess(true); EXPECT_CALL(*observer_,
OnRemoteStatusUpdate(
AllOf(Field(&RemoteStatusUpdate::user_presence, USER_PRESENT),
Field(&RemoteStatusUpdate::secure_screen_lock_state,
SECURE_SCREEN_LOCK_ENABLED),
Field(&RemoteStatusUpdate::trust_agent_state,
TRUST_AGENT_UNSUPPORTED))));
fake_channel_->NotifyMessageReceived(
"{"
"\"type\":\"status_update\","
"\"user_presence\":\"present\","
"\"secure_screen_lock\":\"enabled\","
"\"trust_agent\":\"unsupported\""
"}");
}
TEST_F(ProximityAuthMessengerImplTest, OnMessageReceived_InvalidJSON) {
CreateMessenger(false /* is_multi_device_api_enabled */);
StrictMock<MockMessengerObserver> observer(messenger_.get());
messenger_->RequestUnlock();
messenger_->GetFakeConnection()->FinishSendingMessageWithSuccess(true);
// The StrictMock will verify that no observer methods are called. // The StrictMock will verify that no observer methods are called.
messenger.GetFakeConnection()->ReceiveMessage(std::string(kTestFeature), messenger_->GetFakeConnection()->ReceiveMessage(std::string(kTestFeature),
"Not JSON, but encoded"); "Not JSON, but encoded");
} }
TEST(ProximityAuthMessengerImplTest, OnMessageReceived_MissingTypeField) { TEST_F(ProximityAuthMessengerImplTest,
TestMessenger messenger; OnMessageReceived_InvalidJSON_MultiDeviceApiEnabled) {
StrictMock<MockMessengerObserver> observer(&messenger); CreateMessenger(true /* is_multi_device_api_enabled */);
messenger.RequestUnlock();
messenger.GetFakeConnection()->FinishSendingMessageWithSuccess(true); StrictMock<MockMessengerObserver> observer(messenger_.get());
messenger_->RequestUnlock();
// The StrictMock will verify that no observer methods are called.
fake_channel_->NotifyMessageReceived("Not JSON");
}
TEST_F(ProximityAuthMessengerImplTest, OnMessageReceived_MissingTypeField) {
CreateMessenger(false /* is_multi_device_api_enabled */);
StrictMock<MockMessengerObserver> observer(messenger_.get());
messenger_->RequestUnlock();
messenger_->GetFakeConnection()->FinishSendingMessageWithSuccess(true);
// The StrictMock will verify that no observer methods are called. // The StrictMock will verify that no observer methods are called.
messenger.GetFakeConnection()->ReceiveMessage( messenger_->GetFakeConnection()->ReceiveMessage(
std::string(kTestFeature), std::string(kTestFeature),
"{\"some key that's not 'type'\":\"some value\"}, but encoded"); "{\"some key that's not 'type'\":\"some value\"}, but encoded");
} }
TEST(ProximityAuthMessengerImplTest, OnMessageReceived_UnexpectedReply) { TEST_F(ProximityAuthMessengerImplTest,
TestMessenger messenger; OnMessageReceived_MissingTypeField_MultiDeviceApiEnabled) {
StrictMock<MockMessengerObserver> observer(&messenger); CreateMessenger(true /* is_multi_device_api_enabled */);
StrictMock<MockMessengerObserver> observer(messenger_.get());
messenger_->RequestUnlock();
// The StrictMock will verify that no observer methods are called. // The StrictMock will verify that no observer methods are called.
messenger.GetFakeConnection()->ReceiveMessage( fake_channel_->NotifyMessageReceived(
"{\"some key that's not 'type'\":\"some value\"}");
}
TEST_F(ProximityAuthMessengerImplTest, OnMessageReceived_UnexpectedReply) {
CreateMessenger(false /* is_multi_device_api_enabled */);
StrictMock<MockMessengerObserver> observer(messenger_.get());
// The StrictMock will verify that no observer methods are called.
messenger_->GetFakeConnection()->ReceiveMessage(
std::string(kTestFeature), "{\"type\":\"unlock_response\"}, but encoded"); std::string(kTestFeature), "{\"type\":\"unlock_response\"}, but encoded");
} }
TEST(ProximityAuthMessengerImplTest, TEST_F(ProximityAuthMessengerImplTest,
OnMessageReceived_UnexpectedReply_MultiDeviceApiEnabled) {
CreateMessenger(true /* is_multi_device_api_enabled */);
StrictMock<MockMessengerObserver> observer(messenger_.get());
// The StrictMock will verify that no observer methods are called.
fake_channel_->NotifyMessageReceived("{\"type\":\"unlock_response\"}");
}
TEST_F(ProximityAuthMessengerImplTest,
OnMessageReceived_MismatchedReply_UnlockInReplyToDecrypt) { OnMessageReceived_MismatchedReply_UnlockInReplyToDecrypt) {
TestMessenger messenger; CreateMessenger(false /* is_multi_device_api_enabled */);
StrictMock<MockMessengerObserver> observer(&messenger);
messenger.RequestDecryption(kChallenge); StrictMock<MockMessengerObserver> observer(messenger_.get());
messenger.GetFakeConnection()->FinishSendingMessageWithSuccess(true);
messenger_->RequestDecryption(kChallenge);
messenger_->GetFakeConnection()->FinishSendingMessageWithSuccess(true);
// The StrictMock will verify that no observer methods are called. // The StrictMock will verify that no observer methods are called.
messenger.GetFakeConnection()->ReceiveMessage( messenger_->GetFakeConnection()->ReceiveMessage(
std::string(kTestFeature), "{\"type\":\"unlock_response\"}, but encoded"); std::string(kTestFeature), "{\"type\":\"unlock_response\"}, but encoded");
} }
TEST(ProximityAuthMessengerImplTest, TEST_F(
ProximityAuthMessengerImplTest,
OnMessageReceived_MismatchedReply_UnlockInReplyToDecrypt_MultiDeviceApiEnabled) {
CreateMessenger(true /* is_multi_device_api_enabled */);
StrictMock<MockMessengerObserver> observer(messenger_.get());
messenger_->RequestDecryption(kChallenge);
// The StrictMock will verify that no observer methods are called.
fake_channel_->NotifyMessageReceived("{\"type\":\"unlock_response\"}");
}
TEST_F(ProximityAuthMessengerImplTest,
OnMessageReceived_MismatchedReply_DecryptInReplyToUnlock) { OnMessageReceived_MismatchedReply_DecryptInReplyToUnlock) {
TestMessenger messenger; CreateMessenger(false /* is_multi_device_api_enabled */);
StrictMock<MockMessengerObserver> observer(&messenger);
messenger.RequestUnlock(); StrictMock<MockMessengerObserver> observer(messenger_.get());
messenger.GetFakeConnection()->FinishSendingMessageWithSuccess(true);
messenger_->RequestUnlock();
messenger_->GetFakeConnection()->FinishSendingMessageWithSuccess(true);
// The StrictMock will verify that no observer methods are called. // The StrictMock will verify that no observer methods are called.
messenger.GetFakeConnection()->ReceiveMessage( messenger_->GetFakeConnection()->ReceiveMessage(
std::string(kTestFeature), std::string(kTestFeature),
"{" "{"
"\"type\":\"decrypt_response\"," "\"type\":\"decrypt_response\","
...@@ -407,37 +669,52 @@ TEST(ProximityAuthMessengerImplTest, ...@@ -407,37 +669,52 @@ TEST(ProximityAuthMessengerImplTest,
"}, but encoded"); "}, but encoded");
} }
TEST(ProximityAuthMessengerImplTest, BuffersMessages_WhileSending) { TEST_F(
TestMessenger messenger; ProximityAuthMessengerImplTest,
MockMessengerObserver observer(&messenger); OnMessageReceived_MismatchedReply_DecryptInReplyToUnlock_MultiDeviceApiEnabled) {
CreateMessenger(true /* is_multi_device_api_enabled */);
StrictMock<MockMessengerObserver> observer(messenger_.get());
messenger_->RequestUnlock();
// The StrictMock will verify that no observer methods are called.
fake_channel_->NotifyMessageReceived(
"{"
"\"type\":\"decrypt_response\","
"\"data\":\"YSB3aW5uZXIgaXMgeW91\""
"}");
}
TEST_F(ProximityAuthMessengerImplTest, BuffersMessages_WhileSending) {
CreateMessenger(false /* is_multi_device_api_enabled */);
// Initiate a decryption request, and then initiate an unlock request before // Initiate a decryption request, and then initiate an unlock request before
// the decryption request is even finished sending. // the decryption request is even finished sending.
messenger.RequestDecryption(kChallenge); messenger_->RequestDecryption(kChallenge);
messenger.RequestUnlock(); messenger_->RequestUnlock();
EXPECT_CALL(observer, OnDecryptResponseProxy(std::string())); EXPECT_CALL(*observer_, OnDecryptResponseProxy(std::string()));
messenger.GetFakeConnection()->FinishSendingMessageWithSuccess(false); messenger_->GetFakeConnection()->FinishSendingMessageWithSuccess(false);
EXPECT_CALL(observer, OnUnlockResponse(false)); EXPECT_CALL(*observer_, OnUnlockResponse(false));
messenger.GetFakeConnection()->FinishSendingMessageWithSuccess(false); messenger_->GetFakeConnection()->FinishSendingMessageWithSuccess(false);
} }
TEST(ProximityAuthMessengerImplTest, BuffersMessages_WhileAwaitingReply) { TEST_F(ProximityAuthMessengerImplTest, BuffersMessages_WhileAwaitingReply) {
TestMessenger messenger; CreateMessenger(false /* is_multi_device_api_enabled */);
MockMessengerObserver observer(&messenger);
// Initiate a decryption request, and allow the message to be sent. // Initiate a decryption request, and allow the message to be sent.
messenger.RequestDecryption(kChallenge); messenger_->RequestDecryption(kChallenge);
messenger.GetFakeConnection()->FinishSendingMessageWithSuccess(true); messenger_->GetFakeConnection()->FinishSendingMessageWithSuccess(true);
// At this point, the messenger is awaiting a reply to the decryption message. // At this point, the messenger is awaiting a reply to the decryption message.
// While it's waiting, initiate an unlock request. // While it's waiting, initiate an unlock request.
messenger.RequestUnlock(); messenger_->RequestUnlock();
// Now simulate a response arriving for the original decryption request. // Now simulate a response arriving for the original decryption request.
EXPECT_CALL(observer, OnDecryptResponseProxy("a winner is you")); EXPECT_CALL(*observer_, OnDecryptResponseProxy("a winner is you"));
messenger.GetFakeConnection()->ReceiveMessage( messenger_->GetFakeConnection()->ReceiveMessage(
std::string(kTestFeature), std::string(kTestFeature),
"{" "{"
"\"type\":\"decrypt_response\"," "\"type\":\"decrypt_response\","
...@@ -446,8 +723,33 @@ TEST(ProximityAuthMessengerImplTest, BuffersMessages_WhileAwaitingReply) { ...@@ -446,8 +723,33 @@ TEST(ProximityAuthMessengerImplTest, BuffersMessages_WhileAwaitingReply) {
// The unlock request should have remained buffered, and should only now be // The unlock request should have remained buffered, and should only now be
// sent. // sent.
EXPECT_CALL(observer, OnUnlockResponse(false)); EXPECT_CALL(*observer_, OnUnlockResponse(false));
messenger.GetFakeConnection()->FinishSendingMessageWithSuccess(false); messenger_->GetFakeConnection()->FinishSendingMessageWithSuccess(false);
}
TEST_F(ProximityAuthMessengerImplTest, BuffersMessages_MultiDeviceApiEnabled) {
CreateMessenger(true /* is_multi_device_api_enabled */);
// Initiate a decryption request, and allow the message to be sent.
messenger_->RequestDecryption(kChallenge);
// At this point, the messenger is awaiting a reply to the decryption message.
// While it's waiting, initiate an unlock request.
messenger_->RequestUnlock();
// Now simulate a response arriving for the original decryption request.
EXPECT_CALL(*observer_, OnDecryptResponseProxy("a winner is you"));
fake_channel_->NotifyMessageReceived(
"{"
"\"type\":\"decrypt_response\","
"\"data\":\"YSB3aW5uZXIgaXMgeW91\""
"}");
// The unlock request should have remained buffered, and should only now be
// sent.
EXPECT_CALL(*observer_, OnUnlockResponse(true));
GetLastSentMessage();
fake_channel_->NotifyMessageReceived("{\"type\":\"unlock_response\"}");
} }
} // namespace proximity_auth } // namespace proximity_auth
...@@ -148,9 +148,12 @@ void RemoteDeviceLifeCycleImpl::OnAuthenticationResult( ...@@ -148,9 +148,12 @@ void RemoteDeviceLifeCycleImpl::OnAuthenticationResult(
void RemoteDeviceLifeCycleImpl::CreateMessenger() { void RemoteDeviceLifeCycleImpl::CreateMessenger() {
DCHECK(state_ == RemoteDeviceLifeCycle::State::AUTHENTICATING); DCHECK(state_ == RemoteDeviceLifeCycle::State::AUTHENTICATING);
DCHECK(secure_context_);
messenger_.reset( // TODO(crbug.com/752273): Inject a real ClientChannel.
new MessengerImpl(std::move(connection_), std::move(secure_context_))); messenger_.reset(new MessengerImpl(std::move(connection_),
std::move(secure_context_),
nullptr /* channel */));
messenger_->AddObserver(this); messenger_->AddObserver(this);
TransitionToState(RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED); TransitionToState(RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED);
......
...@@ -69,6 +69,7 @@ class MockMessenger : public Messenger { ...@@ -69,6 +69,7 @@ class MockMessenger : public Messenger {
MOCK_METHOD0(RequestUnlock, void()); MOCK_METHOD0(RequestUnlock, void());
MOCK_CONST_METHOD0(GetSecureContext, cryptauth::SecureContext*()); MOCK_CONST_METHOD0(GetSecureContext, cryptauth::SecureContext*());
MOCK_CONST_METHOD0(GetConnection, cryptauth::Connection*()); MOCK_CONST_METHOD0(GetConnection, cryptauth::Connection*());
MOCK_CONST_METHOD0(GetChannel, chromeos::secure_channel::ClientChannel*());
private: private:
DISALLOW_COPY_AND_ASSIGN(MockMessenger); DISALLOW_COPY_AND_ASSIGN(MockMessenger);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment