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