1 // Copyright 2016 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 #include <memory>
6 #include <string>
7
8 #include "base/bind.h"
9 #include "base/callback.h"
10 #include "base/command_line.h"
11 #include "base/macros.h"
12 #include "base/run_loop.h"
13 #include "base/task/post_task.h"
14 #include "base/test/bind.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/browser_process_platform_part.h"
17 #include "chrome/browser/chromeos/arc/auth/arc_auth_service.h"
18 #include "chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.h"
19 #include "chrome/browser/chromeos/arc/session/arc_session_manager.h"
20 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
21 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
22 #include "chrome/test/base/in_process_browser_test.h"
23 #include "components/arc/arc_util.h"
24 #include "components/policy/core/common/cloud/device_management_service.h"
25 #include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
26 #include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
27 #include "components/policy/core/common/policy_switches.h"
28 #include "components/user_manager/scoped_user_manager.h"
29 #include "content/public/browser/browser_task_traits.h"
30 #include "content/public/browser/browser_thread.h"
31 #include "content/public/test/browser_test.h"
32 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
33 #include "services/network/test/test_url_loader_factory.h"
34 #include "services/network/test/test_utils.h"
35 #include "testing/gtest/include/gtest/gtest.h"
36
37 namespace arc {
38 namespace {
39
40 constexpr char kFakeUserName[] = "test@example.com";
41 constexpr char kFakeAuthCode[] = "fake-auth-code";
42
ResponseJob(const network::ResourceRequest & request,network::TestURLLoaderFactory * factory)43 void ResponseJob(const network::ResourceRequest& request,
44 network::TestURLLoaderFactory* factory) {
45 std::string request_body = network::GetUploadData(request);
46 enterprise_management::DeviceManagementRequest parsed_request;
47 EXPECT_TRUE(
48 parsed_request.ParseFromArray(request_body.c_str(), request_body.size()));
49 // Check if auth code is requested.
50 EXPECT_TRUE(parsed_request.has_service_api_access_request());
51
52 enterprise_management::DeviceManagementResponse response;
53 response.mutable_service_api_access_response()->set_auth_code(kFakeAuthCode);
54
55 std::string response_data;
56 EXPECT_TRUE(response.SerializeToString(&response_data));
57
58 factory->AddResponse(request.url.spec(), response_data);
59 }
60
61 } // namespace
62
63 class ArcRobotAuthCodeFetcherBrowserTest : public InProcessBrowserTest {
64 protected:
65 // Test configuration for whether to set up the CloudPolicyClient connection.
66 // By default, the test sets up the connection.
67 enum class CloudPolicyClientSetup {
68 kConnect = 0,
69 kSkip = 1,
70 };
71
ArcRobotAuthCodeFetcherBrowserTest(CloudPolicyClientSetup cloud_policy_client_setup=CloudPolicyClientSetup::kConnect)72 explicit ArcRobotAuthCodeFetcherBrowserTest(
73 CloudPolicyClientSetup cloud_policy_client_setup =
74 CloudPolicyClientSetup::kConnect)
75 : cloud_policy_client_setup_(cloud_policy_client_setup) {}
76
77 ~ArcRobotAuthCodeFetcherBrowserTest() override = default;
78
SetUpCommandLine(base::CommandLine * command_line)79 void SetUpCommandLine(base::CommandLine* command_line) override {
80 command_line->AppendSwitchASCII(policy::switches::kDeviceManagementUrl,
81 "http://localhost");
82 arc::SetArcAvailableCommandLineForTesting(command_line);
83 }
84
SetUpOnMainThread()85 void SetUpOnMainThread() override {
86 user_manager_enabler_ = std::make_unique<user_manager::ScopedUserManager>(
87 std::make_unique<chromeos::FakeChromeUserManager>());
88
89 const AccountId account_id(AccountId::FromUserEmail(kFakeUserName));
90 GetFakeUserManager()->AddArcKioskAppUser(account_id);
91 GetFakeUserManager()->LoginUser(account_id);
92
93 if (cloud_policy_client_setup_ == CloudPolicyClientSetup::kSkip)
94 return;
95
96 policy::BrowserPolicyConnectorChromeOS* const connector =
97 g_browser_process->platform_part()->browser_policy_connector_chromeos();
98 policy::DeviceCloudPolicyManagerChromeOS* const cloud_policy_manager =
99 connector->GetDeviceCloudPolicyManager();
100
101 cloud_policy_manager->StartConnection(
102 std::make_unique<policy::MockCloudPolicyClient>(),
103 connector->GetInstallAttributes());
104
105 policy::MockCloudPolicyClient* const cloud_policy_client =
106 static_cast<policy::MockCloudPolicyClient*>(
107 cloud_policy_manager->core()->client());
108 cloud_policy_client->SetDMToken("fake-dm-token");
109 cloud_policy_client->client_id_ = "client-id";
110 }
111
TearDownOnMainThread()112 void TearDownOnMainThread() override { user_manager_enabler_.reset(); }
113
GetFakeUserManager() const114 chromeos::FakeChromeUserManager* GetFakeUserManager() const {
115 return static_cast<chromeos::FakeChromeUserManager*>(
116 user_manager::UserManager::Get());
117 }
118
FetchAuthCode(ArcRobotAuthCodeFetcher * fetcher,bool * output_fetch_success,std::string * output_auth_code)119 void FetchAuthCode(ArcRobotAuthCodeFetcher* fetcher,
120 bool* output_fetch_success,
121 std::string* output_auth_code) {
122 base::RunLoop run_loop;
123 fetcher->SetURLLoaderFactoryForTesting(
124 test_url_loader_factory_.GetSafeWeakWrapper());
125 fetcher->Fetch(base::BindOnce(
126 [](bool* output_fetch_success, std::string* output_auth_code,
127 base::RunLoop* run_loop, bool fetch_success,
128 const std::string& auth_code) {
129 *output_fetch_success = fetch_success;
130 *output_auth_code = auth_code;
131 run_loop->Quit();
132 },
133 output_fetch_success, output_auth_code, &run_loop));
134 // Because the Fetch() operation needs to interact with other threads,
135 // RunUntilIdle() won't work here. Instead, use Run() and Quit() explicitly
136 // in the callback.
137 run_loop.Run();
138 }
139
test_url_loader_factory()140 network::TestURLLoaderFactory* test_url_loader_factory() {
141 return &test_url_loader_factory_;
142 }
143
144 private:
145 // Whether to connect the CloudPolicyClient.
146 CloudPolicyClientSetup cloud_policy_client_setup_;
147
148 network::TestURLLoaderFactory test_url_loader_factory_;
149 std::unique_ptr<user_manager::ScopedUserManager> user_manager_enabler_;
150
151 DISALLOW_COPY_AND_ASSIGN(ArcRobotAuthCodeFetcherBrowserTest);
152 };
153
IN_PROC_BROWSER_TEST_F(ArcRobotAuthCodeFetcherBrowserTest,RequestAccountInfoSuccess)154 IN_PROC_BROWSER_TEST_F(ArcRobotAuthCodeFetcherBrowserTest,
155 RequestAccountInfoSuccess) {
156 test_url_loader_factory()->SetInterceptor(
157 base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
158 ResponseJob(request, test_url_loader_factory());
159 }));
160
161 std::string auth_code;
162 bool fetch_success = false;
163
164 auto robot_fetcher = std::make_unique<ArcRobotAuthCodeFetcher>();
165 FetchAuthCode(robot_fetcher.get(), &fetch_success, &auth_code);
166
167 EXPECT_TRUE(fetch_success);
168 EXPECT_EQ(kFakeAuthCode, auth_code);
169 }
170
IN_PROC_BROWSER_TEST_F(ArcRobotAuthCodeFetcherBrowserTest,RequestAccountInfoError)171 IN_PROC_BROWSER_TEST_F(ArcRobotAuthCodeFetcherBrowserTest,
172 RequestAccountInfoError) {
173 test_url_loader_factory()->SetInterceptor(
174 base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
175 test_url_loader_factory()->AddResponse(
176 request.url.spec(), std::string(), net::HTTP_BAD_REQUEST);
177 }));
178
179 // We expect auth_code is empty in this case. So initialize with non-empty
180 // value.
181 std::string auth_code = "NOT-YET-FETCHED";
182 bool fetch_success = true;
183
184 auto robot_fetcher = std::make_unique<ArcRobotAuthCodeFetcher>();
185 FetchAuthCode(robot_fetcher.get(), &fetch_success, &auth_code);
186
187 EXPECT_FALSE(fetch_success);
188 // Use EXPECT_EQ for better logging in case of failure.
189 EXPECT_EQ(std::string(), auth_code);
190 }
191
192 class ArcRobotAuthCodeFetcherOfflineBrowserTest
193 : public ArcRobotAuthCodeFetcherBrowserTest {
194 protected:
ArcRobotAuthCodeFetcherOfflineBrowserTest()195 ArcRobotAuthCodeFetcherOfflineBrowserTest()
196 : ArcRobotAuthCodeFetcherBrowserTest(CloudPolicyClientSetup::kSkip) {}
197
198 ~ArcRobotAuthCodeFetcherOfflineBrowserTest() override = default;
199
200 private:
201 DISALLOW_COPY_AND_ASSIGN(ArcRobotAuthCodeFetcherOfflineBrowserTest);
202 };
203
204 // Tests that the fetch fails when CloudPolicyClient has not been set up yet.
IN_PROC_BROWSER_TEST_F(ArcRobotAuthCodeFetcherOfflineBrowserTest,RequestAccountInfo)205 IN_PROC_BROWSER_TEST_F(ArcRobotAuthCodeFetcherOfflineBrowserTest,
206 RequestAccountInfo) {
207 // We expect auth_code is empty in this case. So initialize with non-empty
208 // value.
209 std::string auth_code = "NOT-YET-FETCHED";
210 bool fetch_success = true;
211
212 auto robot_fetcher = std::make_unique<ArcRobotAuthCodeFetcher>();
213 FetchAuthCode(robot_fetcher.get(), &fetch_success, &auth_code);
214
215 EXPECT_FALSE(fetch_success);
216 // Use EXPECT_EQ for better logging in case of failure.
217 EXPECT_EQ(std::string(), auth_code);
218 }
219
220 } // namespace arc
221