1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 //
5 // A set of unit tests for TokenValidatorFactoryImpl
6 
7 #include "remoting/host/token_validator_factory_impl.h"
8 
9 #include <memory>
10 #include <string>
11 
12 #include "base/bind.h"
13 #include "base/json/json_writer.h"
14 #include "base/run_loop.h"
15 #include "base/test/task_environment.h"
16 #include "base/values.h"
17 #include "net/base/net_errors.h"
18 #include "net/http/http_status_code.h"
19 #include "net/test/url_request/url_request_failed_job.h"
20 #include "net/url_request/url_request_filter.h"
21 #include "net/url_request/url_request_interceptor.h"
22 #include "net/url_request/url_request_test_job.h"
23 #include "net/url_request/url_request_test_util.h"
24 #include "remoting/base/rsa_key_pair.h"
25 #include "remoting/base/test_rsa_key_pair.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27 #include "url/gurl.h"
28 
29 namespace {
30 
31 const char kTokenUrl[] = "https://example.com/token";
32 const char kTokenValidationUrl[] = "https://example.com/validate";
33 const char kTokenValidationCertIssuer[] = "";
34 const char kLocalJid[] = "user@example.com/local";
35 const char kRemoteJid[] = "user@example.com/remote";
36 const char kToken[] = "xyz123456";
37 const char kSharedSecret[] = "abcdefgh";
38 
39 // Bad scope: no nonce element.
40 const char kBadScope[] =
41     "client:user@example.com/local host:user@example.com/remote";
42 
43 class TestURLRequestInterceptor : public net::URLRequestInterceptor {
44  public:
TestURLRequestInterceptor(const std::string & headers,const std::string & response)45   TestURLRequestInterceptor(const std::string& headers,
46                             const std::string& response)
47       : headers_(headers), response_(response) {}
48 
49   ~TestURLRequestInterceptor() override = default;
50 
MaybeInterceptRequest(net::URLRequest * request) const51   std::unique_ptr<net::URLRequestJob> MaybeInterceptRequest(
52       net::URLRequest* request) const override {
53     return std::make_unique<net::URLRequestTestJob>(request, headers_,
54                                                     response_, true);
55   }
56 
57  private:
58   std::string headers_;
59   std::string response_;
60 };
61 
62 // Creates URLRequestJobs that fail at the specified phase.
63 class TestFailingURLRequestInterceptor : public net::URLRequestInterceptor {
64  public:
TestFailingURLRequestInterceptor(net::URLRequestFailedJob::FailurePhase failure_phase,net::Error net_error)65   TestFailingURLRequestInterceptor(
66       net::URLRequestFailedJob::FailurePhase failure_phase,
67       net::Error net_error)
68       : failure_phase_(failure_phase), net_error_(net_error) {}
69 
70   ~TestFailingURLRequestInterceptor() override = default;
71 
MaybeInterceptRequest(net::URLRequest * request) const72   std::unique_ptr<net::URLRequestJob> MaybeInterceptRequest(
73       net::URLRequest* request) const override {
74     return std::make_unique<net::URLRequestFailedJob>(request, failure_phase_,
75                                                       net_error_);
76   }
77 
78  private:
79   const net::URLRequestFailedJob::FailurePhase failure_phase_;
80   const net::Error net_error_;
81 };
82 
83 }  // namespace
84 
85 namespace remoting {
86 
87 class TokenValidatorFactoryImplTest : public testing::Test {
88  public:
TokenValidatorFactoryImplTest()89   TokenValidatorFactoryImplTest()
90       : task_environment_(
91             base::test::SingleThreadTaskEnvironment::MainThreadType::IO) {}
92 
~TokenValidatorFactoryImplTest()93   ~TokenValidatorFactoryImplTest() override {
94     net::URLRequestFilter::GetInstance()->ClearHandlers();
95   }
96 
SuccessCallback(const std::string & shared_secret)97   void SuccessCallback(const std::string& shared_secret) {
98     EXPECT_FALSE(shared_secret.empty());
99     run_loop_.QuitWhenIdle();
100   }
101 
FailureCallback(const std::string & shared_secret)102   void FailureCallback(const std::string& shared_secret) {
103     EXPECT_TRUE(shared_secret.empty());
104     run_loop_.QuitWhenIdle();
105   }
106 
DeleteOnFailureCallback(const std::string & shared_secret)107   void DeleteOnFailureCallback(const std::string& shared_secret) {
108     EXPECT_TRUE(shared_secret.empty());
109     token_validator_.reset();
110     run_loop_.QuitWhenIdle();
111   }
112 
113  protected:
SetUp()114   void SetUp() override {
115     key_pair_ = RsaKeyPair::FromString(kTestRsaKeyPair);
116     request_context_getter_ = new net::TestURLRequestContextGetter(
117         task_environment_.GetMainThreadTaskRunner());
118     ThirdPartyAuthConfig config;
119     config.token_url = GURL(kTokenUrl);
120     config.token_validation_url = GURL(kTokenValidationUrl);
121     config.token_validation_cert_issuer = kTokenValidationCertIssuer;
122     token_validator_factory_ = new TokenValidatorFactoryImpl(
123         config, key_pair_, request_context_getter_);
124   }
125 
CreateResponse(const std::string & scope)126   static std::string CreateResponse(const std::string& scope) {
127     base::DictionaryValue response_dict;
128     response_dict.SetString("access_token", kSharedSecret);
129     response_dict.SetString("token_type", "shared_secret");
130     response_dict.SetString("scope", scope);
131     std::string response;
132     base::JSONWriter::Write(response_dict, &response);
133     return response;
134   }
135 
CreateErrorResponse(const std::string & error)136   static std::string CreateErrorResponse(const std::string& error) {
137     base::DictionaryValue response_dict;
138     response_dict.SetString("error", error);
139     std::string response;
140     base::JSONWriter::Write(response_dict, &response);
141     return response;
142   }
143 
SetResponse(const std::string & headers,const std::string & response)144   void SetResponse(const std::string& headers, const std::string& response) {
145     net::URLRequestFilter::GetInstance()->AddHostnameInterceptor(
146         "https", "example.com",
147         std::make_unique<TestURLRequestInterceptor>(headers, response));
148   }
149 
SetErrorResponse(net::URLRequestFailedJob::FailurePhase failure_phase,net::Error net_error)150   void SetErrorResponse(net::URLRequestFailedJob::FailurePhase failure_phase,
151                         net::Error net_error) {
152     net::URLRequestFilter::GetInstance()->AddHostnameInterceptor(
153         "https", "example.com",
154         std::make_unique<TestFailingURLRequestInterceptor>(failure_phase,
155                                                            net_error));
156   }
157 
158   base::test::SingleThreadTaskEnvironment task_environment_;
159   base::RunLoop run_loop_;
160   scoped_refptr<RsaKeyPair> key_pair_;
161   scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
162   scoped_refptr<TokenValidatorFactoryImpl> token_validator_factory_;
163   std::unique_ptr<protocol::TokenValidator> token_validator_;
164 };
165 
TEST_F(TokenValidatorFactoryImplTest,Success)166 TEST_F(TokenValidatorFactoryImplTest, Success) {
167   token_validator_ =
168       token_validator_factory_->CreateTokenValidator(kLocalJid, kRemoteJid);
169 
170   SetResponse(net::URLRequestTestJob::test_headers(),
171               CreateResponse(token_validator_->token_scope()));
172 
173   token_validator_->ValidateThirdPartyToken(
174       kToken, base::BindOnce(&TokenValidatorFactoryImplTest::SuccessCallback,
175                              base::Unretained(this)));
176   run_loop_.Run();
177 }
178 
TEST_F(TokenValidatorFactoryImplTest,ValidResponseWithJsonSafetyPrefix_Success)179 TEST_F(TokenValidatorFactoryImplTest,
180        ValidResponseWithJsonSafetyPrefix_Success) {
181   token_validator_ =
182       token_validator_factory_->CreateTokenValidator(kLocalJid, kRemoteJid);
183 
184   SetResponse(net::URLRequestTestJob::test_headers(),
185               ")]}'\n" + CreateResponse(token_validator_->token_scope()));
186 
187   token_validator_->ValidateThirdPartyToken(
188       kToken, base::BindOnce(&TokenValidatorFactoryImplTest::SuccessCallback,
189                              base::Unretained(this)));
190   run_loop_.Run();
191 }
192 
TEST_F(TokenValidatorFactoryImplTest,BadToken)193 TEST_F(TokenValidatorFactoryImplTest, BadToken) {
194   token_validator_ =
195       token_validator_factory_->CreateTokenValidator(kLocalJid, kRemoteJid);
196 
197   SetResponse(net::URLRequestTestJob::test_error_headers(), std::string());
198 
199   token_validator_->ValidateThirdPartyToken(
200       kToken, base::BindOnce(&TokenValidatorFactoryImplTest::FailureCallback,
201                              base::Unretained(this)));
202   run_loop_.Run();
203 }
204 
TEST_F(TokenValidatorFactoryImplTest,BadScope)205 TEST_F(TokenValidatorFactoryImplTest, BadScope) {
206   token_validator_ =
207       token_validator_factory_->CreateTokenValidator(kLocalJid, kRemoteJid);
208 
209   SetResponse(net::URLRequestTestJob::test_headers(),
210               CreateResponse(kBadScope));
211 
212   token_validator_->ValidateThirdPartyToken(
213       kToken, base::BindOnce(&TokenValidatorFactoryImplTest::FailureCallback,
214                              base::Unretained(this)));
215   run_loop_.Run();
216 }
217 
TEST_F(TokenValidatorFactoryImplTest,DeleteOnFailure)218 TEST_F(TokenValidatorFactoryImplTest, DeleteOnFailure) {
219   token_validator_ =
220       token_validator_factory_->CreateTokenValidator(kLocalJid, kRemoteJid);
221 
222   SetResponse(net::URLRequestTestJob::test_error_headers(), std::string());
223 
224   token_validator_->ValidateThirdPartyToken(
225       kToken,
226       base::BindOnce(&TokenValidatorFactoryImplTest::DeleteOnFailureCallback,
227                      base::Unretained(this)));
228   run_loop_.Run();
229 }
230 
TEST_F(TokenValidatorFactoryImplTest,DeleteOnStartError)231 TEST_F(TokenValidatorFactoryImplTest, DeleteOnStartError) {
232   token_validator_ =
233       token_validator_factory_->CreateTokenValidator(kLocalJid, kRemoteJid);
234 
235   SetErrorResponse(net::URLRequestFailedJob::START, net::ERR_FAILED);
236 
237   token_validator_->ValidateThirdPartyToken(
238       kToken,
239       base::BindOnce(&TokenValidatorFactoryImplTest::DeleteOnFailureCallback,
240                      base::Unretained(this)));
241   run_loop_.Run();
242 }
243 
TEST_F(TokenValidatorFactoryImplTest,DeleteOnSyncReadError)244 TEST_F(TokenValidatorFactoryImplTest, DeleteOnSyncReadError) {
245   token_validator_ =
246       token_validator_factory_->CreateTokenValidator(kLocalJid, kRemoteJid);
247 
248   SetErrorResponse(net::URLRequestFailedJob::READ_SYNC, net::ERR_FAILED);
249 
250   token_validator_->ValidateThirdPartyToken(
251       kToken,
252       base::BindOnce(&TokenValidatorFactoryImplTest::DeleteOnFailureCallback,
253                      base::Unretained(this)));
254   run_loop_.Run();
255 }
256 
TEST_F(TokenValidatorFactoryImplTest,DeleteOnAsyncReadError)257 TEST_F(TokenValidatorFactoryImplTest, DeleteOnAsyncReadError) {
258   token_validator_ =
259       token_validator_factory_->CreateTokenValidator(kLocalJid, kRemoteJid);
260 
261   SetErrorResponse(net::URLRequestFailedJob::READ_ASYNC, net::ERR_FAILED);
262 
263   token_validator_->ValidateThirdPartyToken(
264       kToken,
265       base::BindOnce(&TokenValidatorFactoryImplTest::DeleteOnFailureCallback,
266                      base::Unretained(this)));
267   run_loop_.Run();
268 }
269 
270 }  // namespace remoting
271