123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- // 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 <memory>
- #include <utility>
- #include "base/bind.h"
- #include "base/memory/ptr_util.h"
- #include "base/run_loop.h"
- #include "net/base/net_errors.h"
- #include "remoting/base/rsa_key_pair.h"
- #include "remoting/protocol/authenticator.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/third_party_authenticator_base.h"
- #include "remoting/protocol/third_party_client_authenticator.h"
- #include "remoting/protocol/third_party_host_authenticator.h"
- #include "remoting/protocol/token_validator.h"
- #include "remoting/protocol/v2_authenticator.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
- using testing::_;
- using testing::DeleteArg;
- using testing::SaveArg;
- namespace {
- const int kMessageSize = 100;
- const int kMessages = 1;
- const char kTokenUrl[] = "https://example.com/Issue";
- 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
- namespace remoting {
- namespace protocol {
- class ThirdPartyAuthenticatorTest : public AuthenticatorTestBase {
- class FakeTokenFetcher {
- public:
- void FetchThirdPartyToken(
- const std::string& token_url,
- const std::string& scope,
- const ThirdPartyTokenFetchedCallback& token_fetched_callback) {
- ASSERT_EQ(token_url, kTokenUrl);
- ASSERT_EQ(scope, kTokenScope);
- ASSERT_FALSE(token_fetched_callback.is_null());
- on_token_fetched_ = token_fetched_callback;
- }
- void OnTokenFetched(const std::string& token,
- const std::string& shared_secret) {
- ASSERT_FALSE(on_token_fetched_.is_null());
- if (!shared_secret.empty()) {
- std::move(on_token_fetched_).Run(token, shared_secret);
- } else {
- std::move(on_token_fetched_)
- .Run(token, Authenticator::RejectionReason::INVALID_CREDENTIALS);
- }
- }
- private:
- ThirdPartyTokenFetchedCallback on_token_fetched_;
- };
- class FakeTokenValidator : public TokenValidator {
- public:
- FakeTokenValidator()
- : token_url_(kTokenUrl),
- token_scope_(kTokenScope) {}
- ~FakeTokenValidator() override = default;
- void ValidateThirdPartyToken(
- const std::string& token,
- TokenValidatedCallback token_validated_callback) override {
- ASSERT_FALSE(token_validated_callback.is_null());
- on_token_validated_ = std::move(token_validated_callback);
- }
- void OnTokenValidated(const std::string& shared_secret) {
- ASSERT_FALSE(on_token_validated_.is_null());
- if (!shared_secret.empty()) {
- std::move(on_token_validated_).Run(shared_secret);
- } else {
- std::move(on_token_validated_)
- .Run(Authenticator::RejectionReason::INVALID_CREDENTIALS);
- }
- }
- const GURL& token_url() const override { return token_url_; }
- const std::string& token_scope() const override { return token_scope_; }
- private:
- GURL token_url_;
- std::string token_scope_;
- TokenValidatedCallback on_token_validated_;
- };
- public:
- ThirdPartyAuthenticatorTest() = default;
- ThirdPartyAuthenticatorTest(const ThirdPartyAuthenticatorTest&) = delete;
- ThirdPartyAuthenticatorTest& operator=(const ThirdPartyAuthenticatorTest&) =
- delete;
- ~ThirdPartyAuthenticatorTest() override = default;
- protected:
- void InitAuthenticators() {
- token_validator_ = new FakeTokenValidator();
- host_ = std::make_unique<ThirdPartyHostAuthenticator>(
- base::BindRepeating(&V2Authenticator::CreateForHost, host_cert_,
- key_pair_),
- base::WrapUnique(token_validator_));
- client_ = std::make_unique<ThirdPartyClientAuthenticator>(
- base::BindRepeating(&V2Authenticator::CreateForClient),
- base::BindRepeating(&FakeTokenFetcher::FetchThirdPartyToken,
- base::Unretained(&token_fetcher_)));
- }
- FakeTokenFetcher token_fetcher_;
- FakeTokenValidator* token_validator_;
- };
- TEST_F(ThirdPartyAuthenticatorTest, SuccessfulAuth) {
- ASSERT_NO_FATAL_FAILURE(InitAuthenticators());
- ASSERT_NO_FATAL_FAILURE(RunHostInitiatedAuthExchange());
- ASSERT_EQ(Authenticator::PROCESSING_MESSAGE, client_->state());
- ASSERT_NO_FATAL_FAILURE(token_fetcher_.OnTokenFetched(kToken, kSharedSecret));
- ASSERT_EQ(Authenticator::PROCESSING_MESSAGE, 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);
- base::RunLoop run_loop;
- tester.Start(run_loop.QuitClosure());
- run_loop.Run();
- tester.CheckResults();
- }
- TEST_F(ThirdPartyAuthenticatorTest, ClientNoSecret) {
- ASSERT_NO_FATAL_FAILURE(InitAuthenticators());
- ASSERT_NO_FATAL_FAILURE(RunHostInitiatedAuthExchange());
- ASSERT_EQ(Authenticator::PROCESSING_MESSAGE, client_->state());
- ASSERT_NO_FATAL_FAILURE(token_fetcher_.OnTokenFetched(kToken, std::string()));
- // 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(RunHostInitiatedAuthExchange());
- ASSERT_EQ(Authenticator::PROCESSING_MESSAGE, client_->state());
- ASSERT_NO_FATAL_FAILURE(token_fetcher_.OnTokenFetched(
- kToken, kSharedSecret));
- ASSERT_EQ(Authenticator::PROCESSING_MESSAGE, host_->state());
- ASSERT_NO_FATAL_FAILURE(token_validator_->OnTokenValidated(std::string()));
- // 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(RunHostInitiatedAuthExchange());
- ASSERT_EQ(Authenticator::PROCESSING_MESSAGE, client_->state());
- ASSERT_NO_FATAL_FAILURE(
- token_fetcher_.OnTokenFetched(std::string(), std::string()));
- // 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(RunHostInitiatedAuthExchange());
- ASSERT_EQ(Authenticator::PROCESSING_MESSAGE, client_->state());
- ASSERT_NO_FATAL_FAILURE(token_fetcher_.OnTokenFetched(kToken, kSharedSecret));
- ASSERT_EQ(Authenticator::PROCESSING_MESSAGE, 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(RunHostInitiatedAuthExchange());
- ASSERT_EQ(Authenticator::PROCESSING_MESSAGE, client_->state());
- ASSERT_NO_FATAL_FAILURE(
- token_fetcher_.OnTokenFetched(kToken, kSharedSecretBad));
- ASSERT_EQ(Authenticator::PROCESSING_MESSAGE, 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
|