blob: 93ae50fc7d7cd3a2e30d1c2fdbf97b8c4b126615 [file] [log] [blame]
Andreea Costinase45d54b2020-03-10 09:21:14 +01001// Copyright 2020 The Chromium OS 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#include "system-proxy/proxy_connect_job.h"
6
7#include <netinet/in.h>
8#include <sys/socket.h>
9#include <sys/types.h>
10
11#include <gmock/gmock.h>
12#include <gtest/gtest.h>
13#include <utility>
14
Andreea Costinase45d54b2020-03-10 09:21:14 +010015#include <base/bind.h>
16#include <base/bind_helpers.h>
17#include <base/callback_helpers.h>
18#include <base/files/file_util.h>
19#include <base/files/scoped_file.h>
Qijiang Fan34014672020-07-20 16:05:38 +090020#include <base/task/single_thread_task_executor.h>
Andreea Costinas08a5d182020-04-29 22:12:47 +020021#include <base/test/test_mock_time_task_runner.h>
Andreea Costinase45d54b2020-03-10 09:21:14 +010022#include <brillo/message_loops/base_message_loop.h>
Garrick Evanscd8c2972020-04-14 14:35:52 +090023#include <chromeos/patchpanel/socket.h>
24#include <chromeos/patchpanel/socket_forwarder.h>
Andreea Costinase45d54b2020-03-10 09:21:14 +010025
26#include "bindings/worker_common.pb.h"
27#include "system-proxy/protobuf_util.h"
Andreea Costinas054fbb52020-06-12 20:46:22 +020028#include "system-proxy/test_http_server.h"
Andreea Costinase45d54b2020-03-10 09:21:14 +010029
30namespace {
Andreea Costinas054fbb52020-06-12 20:46:22 +020031
Andreea Costinasbb2aa022020-06-13 00:03:23 +020032constexpr char kCredentials[] = "username:pwd";
Andreea Costinas054fbb52020-06-12 20:46:22 +020033constexpr char kValidConnectRequest[] =
34 "CONNECT www.example.server.com:443 HTTP/1.1\r\n\r\n";
Andreea Costinase45d54b2020-03-10 09:21:14 +010035} // namespace
36
37namespace system_proxy {
38
39using ::testing::_;
40using ::testing::Return;
41
Andreea Costinas8c436b02020-09-18 14:46:54 +020042class FakeSocketForwarder : public patchpanel::SocketForwarder {
43 public:
44 FakeSocketForwarder(const std::string& name,
45 std::unique_ptr<patchpanel::Socket> sock0,
46 std::unique_ptr<patchpanel::Socket> sock1)
47 : patchpanel::SocketForwarder(name, std::move(sock0), std::move(sock1)) {}
48
49 void Run() override { /* do nothing */
50 }
51};
52
53class FakeProxyConnectJob : public ProxyConnectJob {
54 public:
55 FakeProxyConnectJob(std::unique_ptr<patchpanel::Socket> socket,
56 const std::string& credentials,
57 ResolveProxyCallback resolve_proxy_callback,
58 AuthenticationRequiredCallback auth_required_callback,
59 OnConnectionSetupFinishedCallback setup_finished_callback)
60 : ProxyConnectJob(std::move(socket),
61 credentials,
62 std::move(resolve_proxy_callback),
63 auth_required_callback,
64 std::move(setup_finished_callback)) {}
65
66 std::unique_ptr<patchpanel::SocketForwarder> CreateSocketForwarder(
67 std::unique_ptr<patchpanel::Socket> peer0,
68 std::unique_ptr<patchpanel::Socket> peer1) {
69 return std::make_unique<FakeSocketForwarder>(
70 "test-forwarder", std::move(peer0), std::move(peer1));
71 }
72};
73
Andreea Costinase45d54b2020-03-10 09:21:14 +010074class ProxyConnectJobTest : public ::testing::Test {
75 public:
Andreea Costinasbb2aa022020-06-13 00:03:23 +020076 struct HttpAuthEntry {
77 HttpAuthEntry(const std::string& origin,
78 const std::string& scheme,
79 const std::string& realm,
80 const std::string& credentials)
81 : origin(origin),
82 scheme(scheme),
83 realm(realm),
84 credentials(credentials) {}
85 std::string origin;
86 std::string scheme;
87 std::string realm;
88 std::string credentials;
89 };
Andreea Costinase45d54b2020-03-10 09:21:14 +010090 ProxyConnectJobTest() = default;
91 ProxyConnectJobTest(const ProxyConnectJobTest&) = delete;
92 ProxyConnectJobTest& operator=(const ProxyConnectJobTest&) = delete;
93 ~ProxyConnectJobTest() = default;
94
95 void SetUp() override {
96 int fds[2];
97 ASSERT_NE(-1,
98 socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
99 0 /* protocol */, fds));
100 cros_client_socket_ =
Garrick Evans3388a032020-03-24 11:25:55 +0900101 std::make_unique<patchpanel::Socket>(base::ScopedFD(fds[1]));
Andreea Costinase45d54b2020-03-10 09:21:14 +0100102
Andreea Costinas8c436b02020-09-18 14:46:54 +0200103 connect_job_ = std::make_unique<FakeProxyConnectJob>(
Garrick Evans3388a032020-03-24 11:25:55 +0900104 std::make_unique<patchpanel::Socket>(base::ScopedFD(fds[0])), "",
Andreea Costinase45d54b2020-03-10 09:21:14 +0100105 base::BindOnce(&ProxyConnectJobTest::ResolveProxy,
106 base::Unretained(this)),
Andreea Costinased9e6122020-08-12 12:06:19 +0200107 base::BindRepeating(&ProxyConnectJobTest::OnAuthCredentialsRequired,
108 base::Unretained(this)),
Andreea Costinase45d54b2020-03-10 09:21:14 +0100109 base::BindOnce(&ProxyConnectJobTest::OnConnectionSetupFinished,
110 base::Unretained(this)));
Andreea Costinase45d54b2020-03-10 09:21:14 +0100111 }
112
113 protected:
Andreea Costinasa8bc59c2020-09-18 13:49:13 +0200114 virtual void OnConnectionSetupFinished(
115 std::unique_ptr<patchpanel::SocketForwarder> fwd,
116 ProxyConnectJob* connect_job) {}
117 virtual void ResolveProxy(
Andreea Costinase45d54b2020-03-10 09:21:14 +0100118 const std::string& target_url,
119 base::OnceCallback<void(const std::list<std::string>&)> callback) {
Andreea Costinasa8bc59c2020-09-18 13:49:13 +0200120 std::move(callback).Run({});
Andreea Costinase45d54b2020-03-10 09:21:14 +0100121 }
Andreea Costinasa8bc59c2020-09-18 13:49:13 +0200122 virtual void OnAuthCredentialsRequired(
Andreea Costinasbb2aa022020-06-13 00:03:23 +0200123 const std::string& proxy_url,
124 const std::string& scheme,
125 const std::string& realm,
Andreea Costinased9e6122020-08-12 12:06:19 +0200126 const std::string& bad_credentials,
127 base::RepeatingCallback<void(const std::string&)> callback) {
Andreea Costinasa8bc59c2020-09-18 13:49:13 +0200128 std::move(callback).Run(/* credentials = */ "");
Andreea Costinasbb2aa022020-06-13 00:03:23 +0200129 }
130
Andreea Costinase45d54b2020-03-10 09:21:14 +0100131 std::unique_ptr<ProxyConnectJob> connect_job_;
Qijiang Fan34014672020-07-20 16:05:38 +0900132 base::SingleThreadTaskExecutor task_executor_{base::MessagePumpType::IO};
133 std::unique_ptr<brillo::BaseMessageLoop> brillo_loop_{
134 std::make_unique<brillo::BaseMessageLoop>(task_executor_.task_runner())};
Garrick Evans3388a032020-03-24 11:25:55 +0900135 std::unique_ptr<patchpanel::Socket> cros_client_socket_;
Andreea Costinas08a5d182020-04-29 22:12:47 +0200136
Andreea Costinas08a5d182020-04-29 22:12:47 +0200137 FRIEND_TEST(ProxyConnectJobTest, ClientConnectTimeoutJobCanceled);
Andreea Costinase45d54b2020-03-10 09:21:14 +0100138};
139
Andreea Costinase45d54b2020-03-10 09:21:14 +0100140TEST_F(ProxyConnectJobTest, BadHttpRequestWrongMethod) {
Andreea Costinas08a5d182020-04-29 22:12:47 +0200141 connect_job_->Start();
Andreea Costinase45d54b2020-03-10 09:21:14 +0100142 char badConnRequest[] = "GET www.example.server.com:443 HTTP/1.1\r\n\r\n";
143 cros_client_socket_->SendTo(badConnRequest, std::strlen(badConnRequest));
Qijiang Fan34014672020-07-20 16:05:38 +0900144 brillo_loop_->RunOnce(false);
Andreea Costinase45d54b2020-03-10 09:21:14 +0100145
146 EXPECT_EQ("", connect_job_->target_url_);
147 EXPECT_EQ(0, connect_job_->proxy_servers_.size());
148 const std::string expected_http_response =
149 "HTTP/1.1 400 Bad Request - Origin: local proxy\r\n\r\n";
150 std::vector<char> buf(expected_http_response.size());
151 ASSERT_TRUE(
152 base::ReadFromFD(cros_client_socket_->fd(), buf.data(), buf.size()));
153 std::string actual_response(buf.data(), buf.size());
154 EXPECT_EQ(expected_http_response, actual_response);
155}
156
157TEST_F(ProxyConnectJobTest, BadHttpRequestNoEmptyLine) {
Andreea Costinas08a5d182020-04-29 22:12:47 +0200158 connect_job_->Start();
Andreea Costinase45d54b2020-03-10 09:21:14 +0100159 // No empty line after http message.
160 char badConnRequest[] = "CONNECT www.example.server.com:443 HTTP/1.1\r\n";
161 cros_client_socket_->SendTo(badConnRequest, std::strlen(badConnRequest));
Qijiang Fan34014672020-07-20 16:05:38 +0900162 brillo_loop_->RunOnce(false);
Andreea Costinase45d54b2020-03-10 09:21:14 +0100163
164 EXPECT_EQ("", connect_job_->target_url_);
165 EXPECT_EQ(0, connect_job_->proxy_servers_.size());
166 const std::string expected_http_response =
167 "HTTP/1.1 400 Bad Request - Origin: local proxy\r\n\r\n";
168 std::vector<char> buf(expected_http_response.size());
169 ASSERT_TRUE(
170 base::ReadFromFD(cros_client_socket_->fd(), buf.data(), buf.size()));
171 std::string actual_response(buf.data(), buf.size());
172 EXPECT_EQ(expected_http_response, actual_response);
173}
174
Andreea Costinas08a5d182020-04-29 22:12:47 +0200175TEST_F(ProxyConnectJobTest, WaitClientConnectTimeout) {
176 // Add a TaskRunner where we can control time.
177 scoped_refptr<base::TestMockTimeTaskRunner> task_runner{
178 new base::TestMockTimeTaskRunner()};
Qijiang Fan34014672020-07-20 16:05:38 +0900179 brillo_loop_ = nullptr;
180 brillo_loop_ = std::make_unique<brillo::BaseMessageLoop>(task_runner);
Andreea Costinas08a5d182020-04-29 22:12:47 +0200181 base::TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner.get());
182
183 connect_job_->Start();
184
185 EXPECT_EQ(1, task_runner->GetPendingTaskCount());
186 // Move the time ahead so that the client connection timeout callback is
187 // triggered.
188 task_runner->FastForwardBy(task_runner->NextPendingTaskDelay());
189
190 const std::string expected_http_response =
191 "HTTP/1.1 408 Request Timeout - Origin: local proxy\r\n\r\n";
192 std::vector<char> buf(expected_http_response.size());
193 ASSERT_TRUE(
194 base::ReadFromFD(cros_client_socket_->fd(), buf.data(), buf.size()));
195 std::string actual_response(buf.data(), buf.size());
196
197 EXPECT_EQ(expected_http_response, actual_response);
198}
199
200// Check that the client connect timeout callback is not fired if the owning
201// proxy connect job is destroyed.
202TEST_F(ProxyConnectJobTest, ClientConnectTimeoutJobCanceled) {
203 // Add a TaskRunner where we can control time.
204 scoped_refptr<base::TestMockTimeTaskRunner> task_runner{
205 new base::TestMockTimeTaskRunner()};
Qijiang Fan34014672020-07-20 16:05:38 +0900206 brillo_loop_ = nullptr;
207 brillo_loop_ = std::make_unique<brillo::BaseMessageLoop>(task_runner);
Andreea Costinas08a5d182020-04-29 22:12:47 +0200208 base::TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner.get());
209
210 // Create a proxy connect job and start the client connect timeout counter.
211 {
212 int fds[2];
213 ASSERT_NE(-1,
214 socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
215 0 /* protocol */, fds));
216 auto client_socket =
217 std::make_unique<patchpanel::Socket>(base::ScopedFD(fds[1]));
218
219 auto connect_job = std::make_unique<ProxyConnectJob>(
220 std::make_unique<patchpanel::Socket>(base::ScopedFD(fds[0])), "",
221 base::BindOnce(&ProxyConnectJobTest::ResolveProxy,
222 base::Unretained(this)),
Andreea Costinased9e6122020-08-12 12:06:19 +0200223 base::BindRepeating(&ProxyConnectJobTest::OnAuthCredentialsRequired,
224 base::Unretained(this)),
Andreea Costinas08a5d182020-04-29 22:12:47 +0200225 base::BindOnce(&ProxyConnectJobTest::OnConnectionSetupFinished,
226 base::Unretained(this)));
227 // Post the timeout task.
228 connect_job->Start();
229 EXPECT_TRUE(task_runner->HasPendingTask());
230 }
231 // Check that the task was canceled.
232 EXPECT_FALSE(task_runner->HasPendingTask());
233}
234
Andreea Costinasa8bc59c2020-09-18 13:49:13 +0200235class HttpServerProxyConnectJobTest : public ProxyConnectJobTest {
236 public:
237 HttpServerProxyConnectJobTest() = default;
238 HttpServerProxyConnectJobTest(const HttpServerProxyConnectJobTest&) = delete;
239 HttpServerProxyConnectJobTest& operator=(
240 const HttpServerProxyConnectJobTest&) = delete;
241 ~HttpServerProxyConnectJobTest() = default;
Andreea Costinasbb2aa022020-06-13 00:03:23 +0200242
Andreea Costinasa8bc59c2020-09-18 13:49:13 +0200243 protected:
244 HttpTestServer http_test_server_;
245
246 std::vector<HttpAuthEntry> http_auth_cache_;
247 bool auth_requested_ = false;
248
249 void AddHttpAuthEntry(const std::string& origin,
250 const std::string& scheme,
251 const std::string& realm,
252 const std::string& credentials) {
253 http_auth_cache_.push_back(
254 HttpAuthEntry(origin, scheme, realm, credentials));
255 }
256
257 bool AuthRequested() { return auth_requested_; }
258
259 void AddServerReply(HttpTestServer::HttpConnectReply reply) {
260 http_test_server_.AddHttpConnectReply(reply);
261 }
262
263 void ResolveProxy(const std::string& target_url,
264 base::OnceCallback<void(const std::list<std::string>&)>
265 callback) override {
266 // Return the URL of the test proxy.
267 std::move(callback).Run({http_test_server_.GetUrl()});
268 }
269
270 void OnAuthCredentialsRequired(
271 const std::string& proxy_url,
272 const std::string& scheme,
273 const std::string& realm,
274 const std::string& bad_credentials,
275 base::RepeatingCallback<void(const std::string&)> callback) override {
276 auth_requested_ = true;
277 for (const auto& auth_entry : http_auth_cache_) {
278 if (auth_entry.origin == proxy_url && auth_entry.realm == realm &&
279 auth_entry.scheme == scheme) {
280 std::move(callback).Run(auth_entry.credentials);
281 return;
282 }
283 }
284 if (invoke_authentication_callback_) {
285 std::move(callback).Run(/* credentials = */ "");
286 }
287 }
288 void OnConnectionSetupFinished(
289 std::unique_ptr<patchpanel::SocketForwarder> fwd,
290 ProxyConnectJob* connect_job) override {
291 ASSERT_EQ(connect_job, connect_job_.get());
292 if (fwd) {
293 forwarder_created_ = true;
294
295 brillo_loop_->RunOnce(false);
296
297 fwd.reset();
298 }
299 }
300
301 bool forwarder_created_ = false;
302 // Used to simulate time-outs while waiting for credentials from the Browser.
303 bool invoke_authentication_callback_ = true;
304};
305
306TEST_F(HttpServerProxyConnectJobTest, SuccessfulConnection) {
307 AddServerReply(HttpTestServer::HttpConnectReply::kOk);
308 http_test_server_.Start();
309
310 connect_job_->Start();
311 cros_client_socket_->SendTo(kValidConnectRequest,
312 std::strlen(kValidConnectRequest));
313 brillo_loop_->RunOnce(false);
314 EXPECT_EQ("www.example.server.com:443", connect_job_->target_url_);
315 EXPECT_EQ(1, connect_job_->proxy_servers_.size());
316 EXPECT_EQ(http_test_server_.GetUrl(), connect_job_->proxy_servers_.front());
317 EXPECT_TRUE(forwarder_created_);
318}
319
320TEST_F(HttpServerProxyConnectJobTest, TunnelFailedBadGatewayFromRemote) {
321 AddServerReply(HttpTestServer::HttpConnectReply::kBadGateway);
322 http_test_server_.Start();
323
324 connect_job_->Start();
325 cros_client_socket_->SendTo(kValidConnectRequest,
326 std::strlen(kValidConnectRequest));
327 brillo_loop_->RunOnce(false);
328 EXPECT_FALSE(forwarder_created_);
329
330 std::string expected_server_reply =
331 "HTTP/1.1 502 Error creating tunnel - Origin: local proxy\r\n\r\n";
332 std::vector<char> buf(expected_server_reply.size());
333
334 ASSERT_TRUE(cros_client_socket_->RecvFrom(buf.data(), buf.size()));
335 std::string actual_server_reply(buf.data(), buf.size());
336 EXPECT_EQ(expected_server_reply, actual_server_reply);
337}
338
339TEST_F(HttpServerProxyConnectJobTest, SuccessfulConnectionAltEnding) {
340 AddServerReply(HttpTestServer::HttpConnectReply::kOk);
341 http_test_server_.Start();
342
343 connect_job_->Start();
344 char validConnRequest[] = "CONNECT www.example.server.com:443 HTTP/1.1\r\n\n";
345 cros_client_socket_->SendTo(validConnRequest, std::strlen(validConnRequest));
346 brillo_loop_->RunOnce(false);
347
348 EXPECT_EQ("www.example.server.com:443", connect_job_->target_url_);
349 EXPECT_EQ(1, connect_job_->proxy_servers_.size());
350 EXPECT_EQ(http_test_server_.GetUrl(), connect_job_->proxy_servers_.front());
351 EXPECT_TRUE(forwarder_created_);
352 ASSERT_FALSE(AuthRequested());
353}
354
355// Test that the the CONNECT request is sent again after acquiring credentials.
356TEST_F(HttpServerProxyConnectJobTest, ResendWithCredentials) {
357 AddServerReply(HttpTestServer::HttpConnectReply::kAuthRequiredBasic);
358 AddServerReply(HttpTestServer::HttpConnectReply::kOk);
359 http_test_server_.Start();
360
361 AddHttpAuthEntry(http_test_server_.GetUrl(), "Basic", "\"My Proxy\"",
362 kCredentials);
Andreea Costinasbb2aa022020-06-13 00:03:23 +0200363 connect_job_->Start();
364
365 cros_client_socket_->SendTo(kValidConnectRequest,
366 std::strlen(kValidConnectRequest));
Qijiang Fan34014672020-07-20 16:05:38 +0900367 brillo_loop_->RunOnce(false);
Andreea Costinasbb2aa022020-06-13 00:03:23 +0200368
369 ASSERT_TRUE(AuthRequested());
370 EXPECT_TRUE(forwarder_created_);
371 EXPECT_EQ(kCredentials, connect_job_->credentials_);
372 EXPECT_EQ(200, connect_job_->http_response_code_);
373}
374
375// Test that the proxy auth required status is forwarded to the client if
376// credentials are missing.
Andreea Costinasa8bc59c2020-09-18 13:49:13 +0200377TEST_F(HttpServerProxyConnectJobTest, NoCredentials) {
378 AddServerReply(HttpTestServer::HttpConnectReply::kAuthRequiredBasic);
379 http_test_server_.Start();
Andreea Costinasbb2aa022020-06-13 00:03:23 +0200380 connect_job_->Start();
381
382 cros_client_socket_->SendTo(kValidConnectRequest,
383 std::strlen(kValidConnectRequest));
Qijiang Fan34014672020-07-20 16:05:38 +0900384 brillo_loop_->RunOnce(false);
Andreea Costinasbb2aa022020-06-13 00:03:23 +0200385
386 ASSERT_TRUE(AuthRequested());
387 EXPECT_EQ("", connect_job_->credentials_);
388 EXPECT_EQ(407, connect_job_->http_response_code_);
389}
390
391// Test that the proxy auth required status is forwarded to the client if the
392// server chose Kerberos as an authentication method.
Andreea Costinasa8bc59c2020-09-18 13:49:13 +0200393TEST_F(HttpServerProxyConnectJobTest, KerberosAuth) {
394 AddServerReply(HttpTestServer::HttpConnectReply::kAuthRequiredKerberos);
395 http_test_server_.Start();
Andreea Costinasbb2aa022020-06-13 00:03:23 +0200396
397 connect_job_->Start();
398
399 cros_client_socket_->SendTo(kValidConnectRequest,
400 std::strlen(kValidConnectRequest));
Qijiang Fan34014672020-07-20 16:05:38 +0900401 brillo_loop_->RunOnce(false);
Andreea Costinasbb2aa022020-06-13 00:03:23 +0200402
403 ASSERT_FALSE(AuthRequested());
404 EXPECT_EQ("", connect_job_->credentials_);
405 EXPECT_EQ(407, connect_job_->http_response_code_);
406}
407
Andreea Costinased9e6122020-08-12 12:06:19 +0200408// Test that the connection times out while waiting for credentials from the
409// Browser.
Andreea Costinasa8bc59c2020-09-18 13:49:13 +0200410TEST_F(HttpServerProxyConnectJobTest, AuthenticationTimeout) {
Andreea Costinased9e6122020-08-12 12:06:19 +0200411 // Add a TaskRunner where we can control time.
412 scoped_refptr<base::TestMockTimeTaskRunner> task_runner{
413 new base::TestMockTimeTaskRunner()};
414 brillo_loop_ = nullptr;
415 brillo_loop_ = std::make_unique<brillo::BaseMessageLoop>(task_runner);
416 base::TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner.get());
417
418 invoke_authentication_callback_ = false;
419
Andreea Costinasa8bc59c2020-09-18 13:49:13 +0200420 AddServerReply(HttpTestServer::HttpConnectReply::kAuthRequiredBasic);
421 http_test_server_.Start();
Andreea Costinased9e6122020-08-12 12:06:19 +0200422
423 connect_job_->Start();
424
425 cros_client_socket_->SendTo(kValidConnectRequest,
426 std::strlen(kValidConnectRequest));
427 task_runner->RunUntilIdle();
428 // We need to manually invoke the method which reads from the client socket
429 // because |task_runner| will not execute the FileDescriptorWatcher's tasks.
430 connect_job_->OnClientReadReady();
431
432 // Check that an authentication request was sent.
433 ASSERT_TRUE(AuthRequested());
434 EXPECT_EQ(1, task_runner->GetPendingTaskCount());
435 // Move the time ahead so that the client connection timeout callback is
436 // triggered.
437 task_runner->FastForwardBy(task_runner->NextPendingTaskDelay());
438
439 const std::string expected_http_response =
440 "HTTP/1.1 407 Credentials required - Origin: local proxy\r\n\r\n";
441 std::vector<char> buf(expected_http_response.size());
442 ASSERT_TRUE(
443 base::ReadFromFD(cros_client_socket_->fd(), buf.data(), buf.size()));
444 std::string actual_response(buf.data(), buf.size());
445
446 // Check that the auth failure was forwarded to the client.
447 EXPECT_EQ(expected_http_response, actual_response);
448}
449
450// Verifies that the receiving the same bad credentials twice will send an auth
451// failure to the Chrome OS local client.
Andreea Costinasa8bc59c2020-09-18 13:49:13 +0200452TEST_F(HttpServerProxyConnectJobTest, CancelIfBadCredentials) {
453 AddServerReply(HttpTestServer::HttpConnectReply::kAuthRequiredBasic);
454 AddServerReply(HttpTestServer::HttpConnectReply::kAuthRequiredBasic);
455 http_test_server_.Start();
456
457 AddHttpAuthEntry(http_test_server_.GetUrl(), "Basic", "\"My Proxy\"",
458 kCredentials);
Andreea Costinased9e6122020-08-12 12:06:19 +0200459
460 connect_job_->Start();
461
462 cros_client_socket_->SendTo(kValidConnectRequest,
463 std::strlen(kValidConnectRequest));
464 brillo_loop_->RunOnce(false);
465
466 ASSERT_TRUE(AuthRequested());
467
468 const std::string expected_http_response =
469 "HTTP/1.1 407 Credentials required - Origin: local proxy\r\n\r\n";
470 std::vector<char> buf(expected_http_response.size());
471 ASSERT_TRUE(
472 base::ReadFromFD(cros_client_socket_->fd(), buf.data(), buf.size()));
473 std::string actual_response(buf.data(), buf.size());
474
475 EXPECT_EQ(expected_http_response, actual_response);
476}
477
Andreea Costinase45d54b2020-03-10 09:21:14 +0100478} // namespace system_proxy