Index: remoting/protocol/third_party_authenticator_unittest.cc |
diff --git a/remoting/protocol/third_party_authenticator_unittest.cc b/remoting/protocol/third_party_authenticator_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..437e4071e1a41205741cd62b5374c3a4e73d5bb7 |
--- /dev/null |
+++ b/remoting/protocol/third_party_authenticator_unittest.cc |
@@ -0,0 +1,200 @@ |
+// 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/third_party_authenticator.h" |
+ |
+#include "base/bind.h" |
+#include "net/base/net_errors.h" |
+#include "remoting/protocol/authenticator_test_base.h" |
+#include "remoting/protocol/channel_authenticator.h" |
+#include "remoting/protocol/connection_tester.h" |
+#include "remoting/protocol/fake_authenticator.h" |
+#include "remoting/protocol/key_pair.h" |
+#include "testing/gmock/include/gmock/gmock.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+#include "third_party/libjingle/source/talk/xmllite/xmlelement.h" |
+ |
+using testing::_; |
+using testing::DeleteArg; |
+using testing::SaveArg; |
+ |
+namespace remoting { |
+namespace protocol { |
+ |
+namespace { |
+ |
+const int kMessageSize = 100; |
+const int kMessages = 1; |
+ |
+const char kTokenIssueUrl[] = "https://example.com/Issue"; |
+const char kTokenVerificationUrl[] = "https://example.com/Verify"; |
+const char kTokenScope[] = "host:a@b.com/1 client:a@b.com/2"; |
+const char kToken[] = "abc123456xyz789"; |
+const char kSharedSecret[] = "1234-1234-5678"; |
+const char kSharedSecretBad[] = "0000-0000-0001"; |
+ |
+} // namespace |
+ |
+class ThirdPartyAuthenticatorTest : public AuthenticatorTestBase { |
+ class FakeTokenFetcher |
+ : public protocol::ThirdPartyAuthenticator::TokenFetcher { |
+ public: |
+ virtual void FetchThirdPartyToken( |
+ const std::string& token_url, |
+ const std::string& host_public_key, |
+ const std::string& scope, |
+ const base::Callback<void( |
+ const std::string& token, |
+ const std::string& shared_secret)>&on_token_fetched) { |
+ on_token_fetched_ = on_token_fetched; |
+ } |
+ |
+ void OnTokenFetched(const std::string& token, |
+ const std::string& shared_secret) { |
+ on_token_fetched_.Run(token, shared_secret); |
+ on_token_fetched_.Reset(); |
+ } |
+ |
+ base::Callback<void(const std::string& token, |
+ const std::string& shared_secret)> on_token_fetched_; |
+ }; |
+ |
+ class FakeTokenValidator |
+ : public protocol::ThirdPartyAuthenticator::TokenValidator { |
+ public: |
+ virtual void ValidateThirdPartyToken( |
+ const std::string& token_validation_url, |
+ const std::string& token, |
+ const std::string& host_public_key, |
+ const std::string& token_signature, |
+ const std::string& scope, |
+ const base::Callback<void( |
+ const std::string& shared_secret)>& on_token_validated) { |
+ on_token_validated_ = on_token_validated; |
+ } |
+ |
+ void OnTokenValidated(const std::string& shared_secret) { |
+ on_token_validated_.Run(shared_secret); |
+ on_token_validated_.Reset(); |
+ } |
+ virtual ~FakeTokenValidator() {} |
+ base::Callback<void(const std::string& shared_secret)> on_token_validated_; |
+ }; |
+ |
+ public: |
+ ThirdPartyAuthenticatorTest() { |
+ } |
+ virtual ~ThirdPartyAuthenticatorTest() { |
+ } |
+ |
+ protected: |
+ void InitAuthenticators() { |
+ scoped_ptr<protocol::ThirdPartyAuthenticator::TokenValidator> |
+ token_validator(new FakeTokenValidator()); |
+ token_validator_ = static_cast<FakeTokenValidator*>(token_validator.get()); |
+ host_ = ThirdPartyAuthenticator::CreateForHost( |
+ host_cert_, key_pair_->Copy(), |
+ kTokenIssueUrl, kTokenVerificationUrl, kTokenScope, |
+ token_validator.Pass(), Authenticator::WAITING_MESSAGE); |
+ client_ = ThirdPartyAuthenticator::CreateForClient( |
+ host_public_key_, &token_fetcher_, Authenticator::MESSAGE_READY); |
+ } |
+ |
+ FakeTokenFetcher token_fetcher_; |
+ FakeTokenValidator* token_validator_; |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(ThirdPartyAuthenticatorTest); |
+}; |
+ |
+TEST_F(ThirdPartyAuthenticatorTest, SuccessfulShortAuth) { |
+ ASSERT_NO_FATAL_FAILURE(InitAuthenticators()); |
+ ASSERT_NO_FATAL_FAILURE(RunAuthExchange()); |
+ ASSERT_EQ(Authenticator::WAITING_EXTERNAL, client_->state()); |
+ ASSERT_NO_FATAL_FAILURE(token_fetcher_.OnTokenFetched(kToken, kSharedSecret)); |
+ ASSERT_EQ(Authenticator::WAITING_EXTERNAL, host_->state()); |
+ ASSERT_NO_FATAL_FAILURE( |
+ token_validator_->OnTokenValidated(kSharedSecret)); |
+ // Both sides have finished. |
+ ASSERT_EQ(Authenticator::ACCEPTED, host_->state()); |
+ ASSERT_EQ(Authenticator::ACCEPTED, client_->state()); |
+ |
+ // An authenticated channel can be created after the authentication. |
+ client_auth_ = client_->CreateChannelAuthenticator(); |
+ host_auth_ = host_->CreateChannelAuthenticator(); |
+ RunChannelAuth(false); |
+ |
+ StreamConnectionTester tester(host_socket_.get(), client_socket_.get(), |
+ kMessageSize, kMessages); |
+ |
+ tester.Start(); |
+ message_loop_.Run(); |
+ tester.CheckResults(); |
+} |
+ |
+TEST_F(ThirdPartyAuthenticatorTest, ClientNoSecret) { |
+ ASSERT_NO_FATAL_FAILURE(InitAuthenticators()); |
+ ASSERT_NO_FATAL_FAILURE(RunAuthExchange()); |
+ ASSERT_EQ(Authenticator::WAITING_EXTERNAL, client_->state()); |
+ ASSERT_NO_FATAL_FAILURE(token_fetcher_.OnTokenFetched(kToken, "")); |
+ // The end result is that the client rejected the connection, since it |
+ // couldn't fetch the secret. |
+ ASSERT_EQ(Authenticator::REJECTED, client_->state()); |
+} |
+ |
+TEST_F(ThirdPartyAuthenticatorTest, InvalidToken) { |
+ ASSERT_NO_FATAL_FAILURE(InitAuthenticators()); |
+ ASSERT_NO_FATAL_FAILURE(RunAuthExchange()); |
+ ASSERT_EQ(Authenticator::WAITING_EXTERNAL, client_->state()); |
+ ASSERT_NO_FATAL_FAILURE(token_fetcher_.OnTokenFetched(kToken, kSharedSecret)); |
+ ASSERT_EQ(Authenticator::WAITING_EXTERNAL, host_->state()); |
+ ASSERT_NO_FATAL_FAILURE(token_validator_->OnTokenValidated("")); |
+ |
+ // The end result is that the host rejected the token. |
+ ASSERT_EQ(Authenticator::REJECTED, host_->state()); |
+} |
+ |
+TEST_F(ThirdPartyAuthenticatorTest, CannotFetchToken) { |
+ ASSERT_NO_FATAL_FAILURE(InitAuthenticators()); |
+ ASSERT_NO_FATAL_FAILURE(RunAuthExchange()); |
+ ASSERT_EQ(Authenticator::WAITING_EXTERNAL, client_->state()); |
+ ASSERT_NO_FATAL_FAILURE(token_fetcher_.OnTokenFetched("", "")); |
+ |
+ // The end result is that the client rejected the connection, since it |
+ // couldn't fetch the token. |
+ ASSERT_EQ(Authenticator::REJECTED, client_->state()); |
+} |
+ |
+// Test that negotiation stops when the fake authentication is rejected. |
+TEST_F(ThirdPartyAuthenticatorTest, HostBadSecret) { |
+ ASSERT_NO_FATAL_FAILURE(InitAuthenticators()); |
+ ASSERT_NO_FATAL_FAILURE(RunAuthExchange()); |
+ |
+ ASSERT_EQ(Authenticator::WAITING_EXTERNAL, client_->state()); |
+ ASSERT_NO_FATAL_FAILURE(token_fetcher_.OnTokenFetched(kToken, kSharedSecret)); |
+ ASSERT_EQ(Authenticator::WAITING_EXTERNAL, host_->state()); |
+ ASSERT_NO_FATAL_FAILURE( |
+ token_validator_->OnTokenValidated(kSharedSecretBad)); |
+ |
+ // The end result is that the host rejected the fake authentication. |
+ ASSERT_EQ(Authenticator::REJECTED, client_->state()); |
+} |
+ |
+TEST_F(ThirdPartyAuthenticatorTest, ClientBadSecret) { |
+ ASSERT_NO_FATAL_FAILURE(InitAuthenticators()); |
+ ASSERT_NO_FATAL_FAILURE(RunAuthExchange()); |
+ |
+ ASSERT_EQ(Authenticator::WAITING_EXTERNAL, client_->state()); |
+ ASSERT_NO_FATAL_FAILURE( |
+ token_fetcher_.OnTokenFetched(kToken, kSharedSecretBad)); |
+ ASSERT_EQ(Authenticator::WAITING_EXTERNAL, host_->state()); |
+ ASSERT_NO_FATAL_FAILURE( |
+ token_validator_->OnTokenValidated(kSharedSecret)); |
+ |
+ // The end result is that the host rejected the fake authentication. |
+ ASSERT_EQ(Authenticator::REJECTED, client_->state()); |
+} |
+ |
+} // namespace protocol |
+} // namespace remoting |