| // 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. |
| // |
| // A set of unit tests for TokenValidatorFactoryImpl |
| |
| #include "remoting/host/token_validator_factory_impl.h" |
| |
| #include <memory> |
| #include <string> |
| |
| #include "base/bind.h" |
| #include "base/json/json_writer.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/run_loop.h" |
| #include "base/values.h" |
| #include "net/base/net_errors.h" |
| #include "net/http/http_status_code.h" |
| #include "net/test/url_request/url_request_failed_job.h" |
| #include "net/url_request/url_request_job_factory.h" |
| #include "net/url_request/url_request_job_factory_impl.h" |
| #include "net/url_request/url_request_status.h" |
| #include "net/url_request/url_request_test_job.h" |
| #include "net/url_request/url_request_test_util.h" |
| #include "remoting/base/rsa_key_pair.h" |
| #include "remoting/base/test_rsa_key_pair.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "url/gurl.h" |
| |
| namespace { |
| |
| const char kTokenUrl[] = "https://example.com/token"; |
| const char kTokenValidationUrl[] = "https://example.com/validate"; |
| const char kTokenValidationCertIssuer[] = ""; |
| const char kLocalJid[] = "user@example.com/local"; |
| const char kRemoteJid[] = "user@example.com/remote"; |
| const char kToken[] = "xyz123456"; |
| const char kSharedSecret[] = "abcdefgh"; |
| |
| // Bad scope: no nonce element. |
| const char kBadScope[] = |
| "client:user@example.com/local host:user@example.com/remote"; |
| |
| class FakeProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler { |
| public: |
| FakeProtocolHandler(const std::string& headers, const std::string& response) |
| : headers_(headers), |
| response_(response) { |
| } |
| |
| ~FakeProtocolHandler() override = default; |
| |
| net::URLRequestJob* MaybeCreateJob( |
| net::URLRequest* request, |
| net::NetworkDelegate* network_delegate) const override { |
| return new net::URLRequestTestJob( |
| request, network_delegate, headers_, response_, true); |
| } |
| |
| private: |
| std::string headers_; |
| std::string response_; |
| }; |
| |
| // Creates URLRequestJobs that fail at the specified phase. |
| class FakeFailingProtocolHandler |
| : public net::URLRequestJobFactory::ProtocolHandler { |
| public: |
| FakeFailingProtocolHandler( |
| net::URLRequestFailedJob::FailurePhase failure_phase, |
| net::Error net_error) |
| : failure_phase_(failure_phase), net_error_(net_error) {} |
| |
| ~FakeFailingProtocolHandler() override = default; |
| |
| net::URLRequestJob* MaybeCreateJob( |
| net::URLRequest* request, |
| net::NetworkDelegate* network_delegate) const override { |
| return new net::URLRequestFailedJob(request, network_delegate, |
| failure_phase_, net_error_); |
| } |
| |
| private: |
| const net::URLRequestFailedJob::FailurePhase failure_phase_; |
| const net::Error net_error_; |
| }; |
| |
| class SetResponseURLRequestContext: public net::TestURLRequestContext { |
| public: |
| void SetResponse(const std::string& headers, const std::string& response) { |
| std::unique_ptr<net::URLRequestJobFactoryImpl> factory = |
| std::make_unique<net::URLRequestJobFactoryImpl>(); |
| factory->SetProtocolHandler( |
| "https", std::make_unique<FakeProtocolHandler>(headers, response)); |
| context_storage_.set_job_factory(std::move(factory)); |
| } |
| |
| void SetErrorResponse(net::URLRequestFailedJob::FailurePhase failure_phase, |
| net::Error net_error) { |
| std::unique_ptr<net::URLRequestJobFactoryImpl> factory = |
| std::make_unique<net::URLRequestJobFactoryImpl>(); |
| factory->SetProtocolHandler( |
| "https", |
| std::make_unique<FakeFailingProtocolHandler>(failure_phase, net_error)); |
| context_storage_.set_job_factory(std::move(factory)); |
| } |
| }; |
| |
| } // namespace |
| |
| namespace remoting { |
| |
| class TokenValidatorFactoryImplTest : public testing::Test { |
| public: |
| TokenValidatorFactoryImplTest() : message_loop_(base::MessageLoop::TYPE_IO) {} |
| |
| void SuccessCallback(const std::string& shared_secret) { |
| EXPECT_FALSE(shared_secret.empty()); |
| run_loop_.QuitWhenIdle(); |
| } |
| |
| void FailureCallback(const std::string& shared_secret) { |
| EXPECT_TRUE(shared_secret.empty()); |
| run_loop_.QuitWhenIdle(); |
| } |
| |
| void DeleteOnFailureCallback(const std::string& shared_secret) { |
| EXPECT_TRUE(shared_secret.empty()); |
| token_validator_.reset(); |
| run_loop_.QuitWhenIdle(); |
| } |
| |
| protected: |
| void SetUp() override { |
| key_pair_ = RsaKeyPair::FromString(kTestRsaKeyPair); |
| request_context_getter_ = new net::TestURLRequestContextGetter( |
| message_loop_.task_runner(), |
| std::make_unique<SetResponseURLRequestContext>()); |
| ThirdPartyAuthConfig config; |
| config.token_url = GURL(kTokenUrl); |
| config.token_validation_url = GURL(kTokenValidationUrl); |
| config.token_validation_cert_issuer = kTokenValidationCertIssuer; |
| token_validator_factory_ = new TokenValidatorFactoryImpl( |
| config, key_pair_, request_context_getter_); |
| } |
| |
| static std::string CreateResponse(const std::string& scope) { |
| base::DictionaryValue response_dict; |
| response_dict.SetString("access_token", kSharedSecret); |
| response_dict.SetString("token_type", "shared_secret"); |
| response_dict.SetString("scope", scope); |
| std::string response; |
| base::JSONWriter::Write(response_dict, &response); |
| return response; |
| } |
| |
| static std::string CreateErrorResponse(const std::string& error) { |
| base::DictionaryValue response_dict; |
| response_dict.SetString("error", error); |
| std::string response; |
| base::JSONWriter::Write(response_dict, &response); |
| return response; |
| } |
| |
| |
| void SetResponse(const std::string& headers, const std::string& response) { |
| SetResponseURLRequestContext* context = |
| static_cast<SetResponseURLRequestContext*>( |
| request_context_getter_->GetURLRequestContext()); |
| context->SetResponse(headers, response); |
| } |
| |
| void SetErrorResponse(net::URLRequestFailedJob::FailurePhase failure_phase, |
| net::Error net_error) { |
| SetResponseURLRequestContext* context = |
| static_cast<SetResponseURLRequestContext*>( |
| request_context_getter_->GetURLRequestContext()); |
| context->SetErrorResponse(failure_phase, net_error); |
| } |
| |
| base::MessageLoop message_loop_; |
| base::RunLoop run_loop_; |
| scoped_refptr<RsaKeyPair> key_pair_; |
| scoped_refptr<net::URLRequestContextGetter> request_context_getter_; |
| scoped_refptr<TokenValidatorFactoryImpl> token_validator_factory_; |
| std::unique_ptr<protocol::TokenValidator> token_validator_; |
| }; |
| |
| TEST_F(TokenValidatorFactoryImplTest, Success) { |
| token_validator_ = token_validator_factory_->CreateTokenValidator( |
| kLocalJid, kRemoteJid); |
| |
| SetResponse(net::URLRequestTestJob::test_headers(), |
| CreateResponse(token_validator_->token_scope())); |
| |
| token_validator_->ValidateThirdPartyToken( |
| kToken, base::Bind(&TokenValidatorFactoryImplTest::SuccessCallback, |
| base::Unretained(this))); |
| run_loop_.Run(); |
| } |
| |
| TEST_F(TokenValidatorFactoryImplTest, BadToken) { |
| token_validator_ = token_validator_factory_->CreateTokenValidator( |
| kLocalJid, kRemoteJid); |
| |
| SetResponse(net::URLRequestTestJob::test_error_headers(), std::string()); |
| |
| token_validator_->ValidateThirdPartyToken( |
| kToken, base::Bind(&TokenValidatorFactoryImplTest::FailureCallback, |
| base::Unretained(this))); |
| run_loop_.Run(); |
| } |
| |
| TEST_F(TokenValidatorFactoryImplTest, BadScope) { |
| token_validator_ = token_validator_factory_->CreateTokenValidator( |
| kLocalJid, kRemoteJid); |
| |
| SetResponse(net::URLRequestTestJob::test_headers(), |
| CreateResponse(kBadScope)); |
| |
| token_validator_->ValidateThirdPartyToken( |
| kToken, base::Bind(&TokenValidatorFactoryImplTest::FailureCallback, |
| base::Unretained(this))); |
| run_loop_.Run(); |
| } |
| |
| TEST_F(TokenValidatorFactoryImplTest, DeleteOnFailure) { |
| token_validator_ = token_validator_factory_->CreateTokenValidator( |
| kLocalJid, kRemoteJid); |
| |
| SetResponse(net::URLRequestTestJob::test_error_headers(), std::string()); |
| |
| token_validator_->ValidateThirdPartyToken( |
| kToken, base::Bind( |
| &TokenValidatorFactoryImplTest::DeleteOnFailureCallback, |
| base::Unretained(this))); |
| run_loop_.Run(); |
| } |
| |
| TEST_F(TokenValidatorFactoryImplTest, DeleteOnStartError) { |
| token_validator_ = |
| token_validator_factory_->CreateTokenValidator(kLocalJid, kRemoteJid); |
| |
| SetErrorResponse(net::URLRequestFailedJob::START, net::ERR_FAILED); |
| |
| token_validator_->ValidateThirdPartyToken( |
| kToken, |
| base::Bind(&TokenValidatorFactoryImplTest::DeleteOnFailureCallback, |
| base::Unretained(this))); |
| run_loop_.Run(); |
| } |
| |
| TEST_F(TokenValidatorFactoryImplTest, DeleteOnSyncReadError) { |
| token_validator_ = |
| token_validator_factory_->CreateTokenValidator(kLocalJid, kRemoteJid); |
| |
| SetErrorResponse(net::URLRequestFailedJob::READ_SYNC, net::ERR_FAILED); |
| |
| token_validator_->ValidateThirdPartyToken( |
| kToken, |
| base::Bind(&TokenValidatorFactoryImplTest::DeleteOnFailureCallback, |
| base::Unretained(this))); |
| run_loop_.Run(); |
| } |
| |
| TEST_F(TokenValidatorFactoryImplTest, DeleteOnAsyncReadError) { |
| token_validator_ = |
| token_validator_factory_->CreateTokenValidator(kLocalJid, kRemoteJid); |
| |
| SetErrorResponse(net::URLRequestFailedJob::READ_ASYNC, net::ERR_FAILED); |
| |
| token_validator_->ValidateThirdPartyToken( |
| kToken, |
| base::Bind(&TokenValidatorFactoryImplTest::DeleteOnFailureCallback, |
| base::Unretained(this))); |
| run_loop_.Run(); |
| } |
| |
| } // namespace remoting |