blob: c358f1f3a14b60340f8fc7361652994901257afb [file] [log] [blame]
Andreea Costinas44cefa22020-03-09 09:07:39 +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/server_proxy.h"
6
7#include <netinet/in.h>
Andreea Costinase45d54b2020-03-10 09:21:14 +01008#include <sys/socket.h>
9#include <sys/types.h>
Andreea Costinas44cefa22020-03-09 09:07:39 +010010
11#include <gmock/gmock.h>
12#include <gtest/gtest.h>
13#include <utility>
14
15#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>
Andreea Costinase45d54b2020-03-10 09:21:14 +010020#include <base/strings/string_util.h>
Qijiang Fan34014672020-07-20 16:05:38 +090021#include <base/task/single_thread_task_executor.h>
Andreea Costinas44cefa22020-03-09 09:07:39 +010022#include <brillo/dbus/async_event_sequencer.h>
Andreea Costinas44cefa22020-03-09 09:07:39 +010023#include <brillo/message_loops/base_message_loop.h>
Garrick Evanscd8c2972020-04-14 14:35:52 +090024#include <chromeos/patchpanel/socket.h>
25#include <chromeos/patchpanel/socket_forwarder.h>
Andreea Costinas44cefa22020-03-09 09:07:39 +010026#include "bindings/worker_common.pb.h"
27#include "system-proxy/protobuf_util.h"
Andreea Costinase45d54b2020-03-10 09:21:14 +010028#include "system-proxy/proxy_connect_job.h"
Andreea Costinas44cefa22020-03-09 09:07:39 +010029
30namespace system_proxy {
31namespace {
Andreea Costinase45d54b2020-03-10 09:21:14 +010032constexpr char kUsername[] = "proxy:user";
33constexpr char kUsernameEncoded[] = "proxy%3Auser";
34constexpr char kPassword[] = "proxy password";
35constexpr char kPasswordEncoded[] = "proxy%20password";
Andreea Costinas44cefa22020-03-09 09:07:39 +010036constexpr int kTestPort = 3128;
Andreea Costinas5862b102020-03-19 14:45:36 +010037constexpr char kFakeProxyAddress[] = "http://127.0.0.1";
Andreea Costinase45d54b2020-03-10 09:21:14 +010038
Andreea Costinas44cefa22020-03-09 09:07:39 +010039} // namespace
40
Andreea Costinase45d54b2020-03-10 09:21:14 +010041using ::testing::_;
Andreea Costinas44cefa22020-03-09 09:07:39 +010042using ::testing::Return;
43
44class MockServerProxy : public ServerProxy {
45 public:
46 explicit MockServerProxy(base::OnceClosure quit_closure)
47 : ServerProxy(std::move(quit_closure)) {}
48 MockServerProxy(const MockServerProxy&) = delete;
49 MockServerProxy& operator=(const MockServerProxy&) = delete;
50 ~MockServerProxy() override = default;
51
52 MOCK_METHOD(int, GetStdinPipe, (), (override));
Andreea Costinas5862b102020-03-19 14:45:36 +010053 MOCK_METHOD(int, GetStdoutPipe, (), (override));
Andreea Costinas44cefa22020-03-09 09:07:39 +010054};
55
Andreea Costinase45d54b2020-03-10 09:21:14 +010056class MockProxyConnectJob : public ProxyConnectJob {
57 public:
Garrick Evans3388a032020-03-24 11:25:55 +090058 MockProxyConnectJob(std::unique_ptr<patchpanel::Socket> socket,
Andreea Costinase45d54b2020-03-10 09:21:14 +010059 const std::string& credentials,
60 ResolveProxyCallback resolve_proxy_callback,
Andreea Costinasbb2aa022020-06-13 00:03:23 +020061 AuthenticationRequiredCallback auth_required_callback,
Andreea Costinase45d54b2020-03-10 09:21:14 +010062 OnConnectionSetupFinishedCallback setup_finished_callback)
63 : ProxyConnectJob(std::move(socket),
64 credentials,
65 std::move(resolve_proxy_callback),
Andreea Costinasbb2aa022020-06-13 00:03:23 +020066 std::move(auth_required_callback),
Andreea Costinase45d54b2020-03-10 09:21:14 +010067 std::move(setup_finished_callback)) {}
68 MockProxyConnectJob(const MockProxyConnectJob&) = delete;
69 MockProxyConnectJob& operator=(const MockProxyConnectJob&) = delete;
70 ~MockProxyConnectJob() override = default;
71
72 MOCK_METHOD(bool, Start, (), (override));
73};
74
Andreea Costinas44cefa22020-03-09 09:07:39 +010075class ServerProxyTest : public ::testing::Test {
76 public:
77 ServerProxyTest() {
78 server_proxy_ =
79 std::make_unique<MockServerProxy>(brillo_loop_.QuitClosure());
80 }
81
82 ServerProxyTest(const ServerProxyTest&) = delete;
83 ServerProxyTest& operator=(const ServerProxyTest&) = delete;
84 ~ServerProxyTest() override {}
85
86 protected:
Andreea Costinas5862b102020-03-19 14:45:36 +010087 // Redirects the standard streams of the worker so that the tests can write
88 // data in the worker's stdin input and read data from the worker's stdout
89 // output.
Andreea Costinas44cefa22020-03-09 09:07:39 +010090 void RedirectStdPipes() {
91 int fds[2];
92 CHECK(base::CreateLocalNonBlockingPipe(fds));
Andreea Costinas5862b102020-03-19 14:45:36 +010093 stdin_read_fd_.reset(fds[0]);
94 stdin_write_fd_.reset(fds[1]);
95 CHECK(base::CreateLocalNonBlockingPipe(fds));
96 stdout_read_fd_.reset(fds[0]);
97 stdout_write_fd_.reset(fds[1]);
Andreea Costinas44cefa22020-03-09 09:07:39 +010098
Andreea Costinas5862b102020-03-19 14:45:36 +010099 ON_CALL(*server_proxy_, GetStdinPipe())
100 .WillByDefault(Return(stdin_read_fd_.get()));
101 // Don't redirect all the calls to |stdout_write_fd_| or the test result
102 // will not be printed in the console. Instead, when wanting to read the
103 // standard output, set the expectation to once return |stdout_write_fd_|.
104 ON_CALL(*server_proxy_, GetStdoutPipe())
105 .WillByDefault(Return(STDOUT_FILENO));
Andreea Costinas44cefa22020-03-09 09:07:39 +0100106 server_proxy_->Init();
107 }
108 // SystemProxyAdaptor instance that creates fake worker processes.
109 std::unique_ptr<MockServerProxy> server_proxy_;
Qijiang Fan34014672020-07-20 16:05:38 +0900110 base::SingleThreadTaskExecutor task_executor_{base::MessagePumpType::IO};
111 brillo::BaseMessageLoop brillo_loop_{task_executor_.task_runner()};
Andreea Costinas5862b102020-03-19 14:45:36 +0100112 base::ScopedFD stdin_read_fd_, stdin_write_fd_, stdout_read_fd_,
113 stdout_write_fd_;
Andreea Costinas44cefa22020-03-09 09:07:39 +0100114};
115
116TEST_F(ServerProxyTest, FetchCredentials) {
Andreea Costinasaae97382020-05-05 13:31:58 +0200117 worker::Credentials credentials;
Andreea Costinase45d54b2020-03-10 09:21:14 +0100118 credentials.set_username(kUsername);
Andreea Costinas44cefa22020-03-09 09:07:39 +0100119 credentials.set_password(kPassword);
Andreea Costinasaae97382020-05-05 13:31:58 +0200120 worker::WorkerConfigs configs;
Andreea Costinas44cefa22020-03-09 09:07:39 +0100121 *configs.mutable_credentials() = credentials;
122 RedirectStdPipes();
123
Andreea Costinas5862b102020-03-19 14:45:36 +0100124 EXPECT_TRUE(WriteProtobuf(stdin_write_fd_.get(), configs));
Andreea Costinas44cefa22020-03-09 09:07:39 +0100125
126 brillo_loop_.RunOnce(false);
127
Andreea Costinase45d54b2020-03-10 09:21:14 +0100128 std::string expected_credentials =
129 base::JoinString({kUsernameEncoded, kPasswordEncoded}, ":");
Andreea Costinasbb2aa022020-06-13 00:03:23 +0200130 EXPECT_EQ(server_proxy_->system_credentials_, expected_credentials);
Andreea Costinas44cefa22020-03-09 09:07:39 +0100131}
132
133TEST_F(ServerProxyTest, FetchListeningAddress) {
Andreea Costinasaae97382020-05-05 13:31:58 +0200134 worker::SocketAddress address;
Andreea Costinas44cefa22020-03-09 09:07:39 +0100135 address.set_addr(INADDR_ANY);
136 address.set_port(kTestPort);
Andreea Costinasaae97382020-05-05 13:31:58 +0200137 worker::WorkerConfigs configs;
Andreea Costinas44cefa22020-03-09 09:07:39 +0100138 *configs.mutable_listening_address() = address;
Andreea Costinas44cefa22020-03-09 09:07:39 +0100139 // Redirect the worker stdin and stdout pipes.
Andreea Costinas5862b102020-03-19 14:45:36 +0100140 RedirectStdPipes();
141 // Send the config to the worker's stdin input.
142 EXPECT_TRUE(WriteProtobuf(stdin_write_fd_.get(), configs));
Andreea Costinas44cefa22020-03-09 09:07:39 +0100143 brillo_loop_.RunOnce(false);
144
145 EXPECT_EQ(server_proxy_->listening_addr_, INADDR_ANY);
146 EXPECT_EQ(server_proxy_->listening_port_, kTestPort);
147}
148
Andreea Costinas5862b102020-03-19 14:45:36 +0100149// Tests that ServerProxy handles the basic flow of a connect request:
150// - server accepts a connection a creates a job for it until the connection is
151// finished;
152// - the connect request from the client socket is read and parsed;
153// - proxy resolution request is correctly handled by the job and ServerProxy;
154// - client is sent an HTTP error code in case of failure;
155// - the failed connection job is removed from the queue.
Andreea Costinase45d54b2020-03-10 09:21:14 +0100156TEST_F(ServerProxyTest, HandleConnectRequest) {
157 server_proxy_->listening_addr_ = htonl(INADDR_LOOPBACK);
158 server_proxy_->listening_port_ = kTestPort;
159 // Redirect the worker stdin and stdout pipes.
160 RedirectStdPipes();
161 server_proxy_->CreateListeningSocket();
Andreea Costinase45d54b2020-03-10 09:21:14 +0100162 CHECK_NE(-1, server_proxy_->listening_fd_->fd());
163 brillo_loop_.RunOnce(false);
164
165 struct sockaddr_in ipv4addr;
166 ipv4addr.sin_family = AF_INET;
167 ipv4addr.sin_port = htons(kTestPort);
168 ipv4addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
169
170 auto client_socket =
Garrick Evans3388a032020-03-24 11:25:55 +0900171 std::make_unique<patchpanel::Socket>(AF_INET, SOCK_STREAM);
Andreea Costinase45d54b2020-03-10 09:21:14 +0100172 EXPECT_TRUE(client_socket->Connect((const struct sockaddr*)&ipv4addr,
173 sizeof(ipv4addr)));
174 brillo_loop_.RunOnce(false);
175
176 EXPECT_EQ(1, server_proxy_->pending_connect_jobs_.size());
Andreea Costinas5862b102020-03-19 14:45:36 +0100177 const std::string_view http_req =
178 "CONNECT www.example.server.com:443 HTTP/1.1\r\n\r\n";
179 client_socket->SendTo(http_req.data(), http_req.size());
180
181 EXPECT_CALL(*server_proxy_, GetStdoutPipe())
182 .WillOnce(Return(stdout_write_fd_.get()));
183 brillo_loop_.RunOnce(false);
Andreea Costinasaae97382020-05-05 13:31:58 +0200184 worker::WorkerRequest request;
Andreea Costinas5862b102020-03-19 14:45:36 +0100185 // Read the request from the worker's stdout output.
186 ASSERT_TRUE(ReadProtobuf(stdout_read_fd_.get(), &request));
187 ASSERT_TRUE(request.has_proxy_resolution_request());
188
Andreea Costinasa89309d2020-05-08 15:51:12 +0200189 EXPECT_EQ("https://www.example.server.com:443",
Andreea Costinas5862b102020-03-19 14:45:36 +0100190 request.proxy_resolution_request().target_url());
191
192 EXPECT_EQ(1, server_proxy_->pending_proxy_resolution_requests_.size());
193
194 // Write reply with a fake proxy to the worker's standard input.
Andreea Costinasaae97382020-05-05 13:31:58 +0200195 worker::ProxyResolutionReply reply;
Andreea Costinas5862b102020-03-19 14:45:36 +0100196 reply.set_target_url(request.proxy_resolution_request().target_url());
197 reply.add_proxy_servers(kFakeProxyAddress);
Andreea Costinasaae97382020-05-05 13:31:58 +0200198 worker::WorkerConfigs configs;
Andreea Costinas5862b102020-03-19 14:45:36 +0100199 *configs.mutable_proxy_resolution_reply() = reply;
200
201 ASSERT_TRUE(WriteProtobuf(stdin_write_fd_.get(), configs));
202 brillo_loop_.RunOnce(false);
203
204 // Verify that the correct HTTP error code is sent to the client. Because
205 // curl_perform will fail, this will be reported as an internal server error.
206 const std::string expected_http_reply =
207 "HTTP/1.1 500 Internal Server Error - Origin: local proxy\r\n\r\n";
208 std::vector<char> buf(expected_http_reply.size());
209 ASSERT_TRUE(base::ReadFromFD(client_socket->fd(), buf.data(), buf.size()));
210 buf.push_back('\0');
211 const std::string actual_http_reply(buf.data());
212 EXPECT_EQ(expected_http_reply, actual_http_reply);
213 EXPECT_EQ(0, server_proxy_->pending_connect_jobs_.size());
Andreea Costinase45d54b2020-03-10 09:21:14 +0100214}
215
216// Tests the |OnConnectionSetupFinished| callback is handled correctly in case
217// of success or error.
218TEST_F(ServerProxyTest, HandlePendingJobs) {
219 int connection_count = 100;
220 int success_count = 51;
221 int failure_count = 49;
222 // Create |connection_count| connections.
223 for (int i = 0; i < connection_count; ++i) {
224 auto client_socket =
Garrick Evans3388a032020-03-24 11:25:55 +0900225 std::make_unique<patchpanel::Socket>(AF_INET, SOCK_STREAM);
Andreea Costinase45d54b2020-03-10 09:21:14 +0100226 auto mock_connect_job = std::make_unique<MockProxyConnectJob>(
227 std::move(client_socket), "" /* credentials */,
228 base::BindOnce([](const std::string& target_url,
229 OnProxyResolvedCallback callback) {}),
Andreea Costinasbb2aa022020-06-13 00:03:23 +0200230 base::BindOnce([](const std::string& proxy_url,
231 const std::string& realm, const std::string& scheme,
232 OnAuthAcquiredCallback callback) {}),
Andreea Costinase45d54b2020-03-10 09:21:14 +0100233 base::BindOnce(&ServerProxy::OnConnectionSetupFinished,
234 base::Unretained(server_proxy_.get())));
235 server_proxy_->pending_connect_jobs_[mock_connect_job.get()] =
236 std::move(mock_connect_job);
237 }
238 // Resolve |failure_count| pending connections with error.
239 for (int i = 0; i < failure_count; ++i) {
240 auto job_iter = server_proxy_->pending_connect_jobs_.begin();
241 std::move(job_iter->second->setup_finished_callback_)
242 .Run(nullptr, job_iter->first);
243 }
244 // Expect failed requests have been cleared from the pending list and no
245 // forwarder.
246 EXPECT_EQ(success_count, server_proxy_->pending_connect_jobs_.size());
247 EXPECT_EQ(0, server_proxy_->forwarders_.size());
248
249 // Resolve |success_count| successful connections.
250 for (int i = 0; i < success_count; ++i) {
Garrick Evans3388a032020-03-24 11:25:55 +0900251 auto fwd = std::make_unique<patchpanel::SocketForwarder>(
Andreea Costinase45d54b2020-03-10 09:21:14 +0100252 "" /* thread name */,
Garrick Evans3388a032020-03-24 11:25:55 +0900253 std::make_unique<patchpanel::Socket>(AF_INET, SOCK_STREAM),
254 std::make_unique<patchpanel::Socket>(AF_INET, SOCK_STREAM));
Andreea Costinase45d54b2020-03-10 09:21:14 +0100255 fwd->Start();
256 auto job_iter = server_proxy_->pending_connect_jobs_.begin();
257 std::move(job_iter->second->setup_finished_callback_)
258 .Run(std::move(fwd), job_iter->first);
259 }
260
261 // Expect the successful requests to have been cleared and |success_count|
262 // active forwarders.
263 EXPECT_EQ(0, server_proxy_->pending_connect_jobs_.size());
264 EXPECT_EQ(success_count, server_proxy_->forwarders_.size());
265}
266
Andreea Costinas833eb7c2020-06-12 11:09:15 +0200267// Test to ensure proxy resolution requests are correctly handled if the
268// associated job is canceled before resolution.
269TEST_F(ServerProxyTest, HandleCanceledJobWhilePendingProxyResolution) {
270 server_proxy_->listening_addr_ = htonl(INADDR_LOOPBACK);
271 server_proxy_->listening_port_ = 3129;
272 // Redirect the worker stdin and stdout pipes.
273 RedirectStdPipes();
274 server_proxy_->CreateListeningSocket();
275 CHECK_NE(-1, server_proxy_->listening_fd_->fd());
276 brillo_loop_.RunOnce(false);
277
278 struct sockaddr_in ipv4addr;
279 ipv4addr.sin_family = AF_INET;
280 ipv4addr.sin_port = htons(3129);
281 ipv4addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
282
283 auto client_socket =
284 std::make_unique<patchpanel::Socket>(AF_INET, SOCK_STREAM);
285 EXPECT_TRUE(client_socket->Connect((const struct sockaddr*)&ipv4addr,
286 sizeof(ipv4addr)));
287 brillo_loop_.RunOnce(false);
288
289 EXPECT_EQ(1, server_proxy_->pending_connect_jobs_.size());
290 const std::string_view http_req =
291 "CONNECT www.example.server.com:443 HTTP/1.1\r\n\r\n";
292 client_socket->SendTo(http_req.data(), http_req.size());
293
294 EXPECT_CALL(*server_proxy_, GetStdoutPipe())
295 .WillOnce(Return(stdout_write_fd_.get()));
296 brillo_loop_.RunOnce(false);
297
298 EXPECT_EQ(1, server_proxy_->pending_connect_jobs_.size());
299 server_proxy_->pending_connect_jobs_.clear();
300
301 EXPECT_EQ(1, server_proxy_->pending_proxy_resolution_requests_.size());
302 server_proxy_->OnProxyResolved("https://www.example.server.com:443", {});
303
304 EXPECT_EQ(0, server_proxy_->pending_proxy_resolution_requests_.size());
305}
306
Andreea Costinasdb2cbee2020-06-15 11:43:44 +0200307// This test verifies that the athentication request is forwarded to the parent
308// process and that the pending authentication requests are resolved when the
309// parent sends the credentials associated with the protection space included in
310// the request.
311TEST_F(ServerProxyTest, HandlePendingAuthRequests) {
312 RedirectStdPipes();
313
314 worker::ProtectionSpace protection_space;
315 protection_space.set_origin(kFakeProxyAddress);
316 protection_space.set_scheme("Basic");
317 protection_space.set_realm("Proxy test realm");
318 std::string actual_credentials = "";
319
320 EXPECT_CALL(*server_proxy_, GetStdoutPipe())
321 .WillOnce(Return(stdout_write_fd_.get()));
322
323 server_proxy_->AuthenticationRequired(
324 protection_space.origin(), protection_space.scheme(),
325 protection_space.realm(),
326 base::Bind(
327 [](std::string* actual_credentials, const std::string& credentials) {
328 *actual_credentials = credentials;
329 },
330 &actual_credentials));
331
332 EXPECT_EQ(1, server_proxy_->pending_auth_required_requests_.size());
333 EXPECT_EQ(protection_space.SerializeAsString(),
334 server_proxy_->pending_auth_required_requests_.begin()->first);
335
336 brillo_loop_.RunOnce(false);
337
338 worker::WorkerRequest request;
339 // Read the request from the worker's stdout output.
340 ASSERT_TRUE(ReadProtobuf(stdout_read_fd_.get(), &request));
341 ASSERT_TRUE(request.has_auth_required_request());
342 ASSERT_TRUE(request.auth_required_request().has_protection_space());
343 EXPECT_EQ(
344 request.auth_required_request().protection_space().SerializeAsString(),
345 protection_space.SerializeAsString());
346
347 // Write reply with a fake credentials to the worker's standard input.
348 worker::Credentials credentials;
349 *credentials.mutable_protection_space() = protection_space;
350 credentials.set_username("test_user");
351 credentials.set_password("test_pwd");
352 worker::WorkerConfigs configs;
353 *configs.mutable_credentials() = credentials;
354
355 ASSERT_TRUE(WriteProtobuf(stdin_write_fd_.get(), configs));
356 brillo_loop_.RunOnce(false);
357 EXPECT_EQ(0, server_proxy_->pending_auth_required_requests_.size());
358 EXPECT_EQ("test_user:test_pwd", actual_credentials);
359}
360
361// This test verifies that pending athentication requests are solved when the
362// parent returns empty credentials for the protection space.
363TEST_F(ServerProxyTest, HandlePendingAuthRequestsNoCredentials) {
364 RedirectStdPipes();
365
366 worker::ProtectionSpace protection_space;
367 protection_space.set_origin(kFakeProxyAddress);
368 protection_space.set_scheme("Basic");
369 protection_space.set_realm("Proxy test realm");
370 std::string actual_credentials = "";
371
372 EXPECT_CALL(*server_proxy_, GetStdoutPipe())
373 .WillOnce(Return(stdout_write_fd_.get()));
374
375 server_proxy_->AuthenticationRequired(
376 protection_space.origin(), protection_space.scheme(),
377 protection_space.realm(),
378 base::Bind(
379 [](std::string* actual_credentials, const std::string& credentials) {
380 *actual_credentials = credentials;
381 },
382 &actual_credentials));
383
384 EXPECT_EQ(1, server_proxy_->pending_auth_required_requests_.size());
385 EXPECT_EQ(protection_space.SerializeAsString(),
386 server_proxy_->pending_auth_required_requests_.begin()->first);
387
388 brillo_loop_.RunOnce(false);
389
390 worker::WorkerRequest request;
391 // Read the request from the worker's stdout output.
392 ASSERT_TRUE(ReadProtobuf(stdout_read_fd_.get(), &request));
393 ASSERT_TRUE(request.has_auth_required_request());
394 ASSERT_TRUE(request.auth_required_request().has_protection_space());
395 EXPECT_EQ(
396 request.auth_required_request().protection_space().SerializeAsString(),
397 protection_space.SerializeAsString());
398
399 // Write reply with a fake credentials to the worker's standard input.
400 worker::Credentials credentials;
401 *credentials.mutable_protection_space() = protection_space;
402 worker::WorkerConfigs configs;
403 *configs.mutable_credentials() = credentials;
404
405 ASSERT_TRUE(WriteProtobuf(stdin_write_fd_.get(), configs));
406 brillo_loop_.RunOnce(false);
407 EXPECT_EQ(0, server_proxy_->pending_auth_required_requests_.size());
408 EXPECT_EQ("", actual_credentials);
409}
410
411// This test verifies that the athentication request is solved with cached
412// credentials.
413TEST_F(ServerProxyTest, HandlePendingAuthRequestsCachedCredentials) {
414 RedirectStdPipes();
415
416 worker::ProtectionSpace protection_space;
417 protection_space.set_origin(kFakeProxyAddress);
418 protection_space.set_scheme("Basic");
419 protection_space.set_realm("Proxy test realm");
420 std::string actual_credentials = "";
421
422 server_proxy_->auth_cache_[protection_space.SerializeAsString()] =
423 "test_user:test_pwd";
424
425 server_proxy_->AuthenticationRequired(
426 protection_space.origin(), protection_space.scheme(),
427 protection_space.realm(),
428 base::Bind(
429 [](std::string* actual_credentials, const std::string& credentials) {
430 *actual_credentials = credentials;
431 },
432 &actual_credentials));
433
434 brillo_loop_.RunOnce(false);
435 EXPECT_EQ(0, server_proxy_->pending_auth_required_requests_.size());
436 EXPECT_EQ("test_user:test_pwd", actual_credentials);
437}
438
Andreea Costinase9c73592020-07-17 15:27:54 +0200439// This test verifies that the stored credentials are removed when receiving a
440// |ClearUserCredentials| request.
441TEST_F(ServerProxyTest, ClearUserCredentials) {
442 worker::ProtectionSpace protection_space;
443 protection_space.set_origin(kFakeProxyAddress);
444 protection_space.set_scheme("Basic");
445 protection_space.set_realm("Proxy test realm");
446 // Add an entry in the cache.
447 server_proxy_->auth_cache_[protection_space.SerializeAsString()] =
448 "test_user:test_pwd";
449
450 worker::ClearUserCredentials clear_user_credentials;
451 worker::WorkerConfigs configs;
452 *configs.mutable_clear_user_credentials() = clear_user_credentials;
453 // Redirect the worker stdin and stdout pipes.
454 RedirectStdPipes();
455 // Send the config to the worker's stdin input.
456 EXPECT_TRUE(WriteProtobuf(stdin_write_fd_.get(), configs));
457 brillo_loop_.RunOnce(false);
458 // Expect that the credentials were cleared.
459 EXPECT_EQ(0, server_proxy_->auth_cache_.size());
460}
461
Andreea Costinas44cefa22020-03-09 09:07:39 +0100462} // namespace system_proxy