device_local_account_browsertest.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
1// Copyright (c) 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#include <map>
6#include <string>
7
8#include "base/basictypes.h"
9#include "base/bind.h"
10#include "base/command_line.h"
11#include "base/file_util.h"
12#include "base/files/file_path.h"
13#include "base/files/scoped_temp_dir.h"
14#include "base/message_loop.h"
15#include "base/path_service.h"
16#include "base/run_loop.h"
17#include "base/stl_util.h"
18#include "base/strings/string_util.h"
19#include "base/strings/utf_string_conversions.h"
20#include "chrome/browser/browser_process.h"
21#include "chrome/browser/chromeos/login/existing_user_controller.h"
22#include "chrome/browser/chromeos/login/login_display_host.h"
23#include "chrome/browser/chromeos/login/login_display_host_impl.h"
24#include "chrome/browser/chromeos/login/user.h"
25#include "chrome/browser/chromeos/login/user_manager.h"
26#include "chrome/browser/chromeos/policy/device_local_account.h"
27#include "chrome/browser/chromeos/policy/device_policy_builder.h"
28#include "chrome/browser/chromeos/policy/enterprise_install_attributes.h"
29#include "chrome/browser/lifetime/application_lifetime.h"
30#include "chrome/browser/policy/cloud/cloud_policy_constants.h"
31#include "chrome/browser/policy/cloud/policy_builder.h"
32#include "chrome/browser/policy/policy_service.h"
33#include "chrome/browser/policy/proto/chromeos/chrome_device_policy.pb.h"
34#include "chrome/browser/policy/proto/chromeos/install_attributes.pb.h"
35#include "chrome/browser/policy/test/local_policy_test_server.h"
36#include "chrome/browser/prefs/session_startup_pref.h"
37#include "chrome/browser/ui/browser.h"
38#include "chrome/browser/ui/browser_finder.h"
39#include "chrome/browser/ui/host_desktop.h"
40#include "chrome/browser/ui/tabs/tab_strip_model.h"
41#include "chrome/common/chrome_notification_types.h"
42#include "chrome/common/chrome_switches.h"
43#include "chrome/test/base/in_process_browser_test.h"
44#include "chromeos/chromeos_paths.h"
45#include "chromeos/chromeos_switches.h"
46#include "chromeos/dbus/cryptohome_client.h"
47#include "chromeos/dbus/dbus_method_call_status.h"
48#include "chromeos/dbus/dbus_thread_manager.h"
49#include "chromeos/dbus/fake_cryptohome_client.h"
50#include "chromeos/dbus/fake_session_manager_client.h"
51#include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
52#include "chromeos/dbus/session_manager_client.h"
53#include "content/public/browser/web_contents.h"
54#include "content/public/test/test_utils.h"
55#include "testing/gmock/include/gmock/gmock.h"
56#include "third_party/cros_system_api/dbus/service_constants.h"
57
58namespace em = enterprise_management;
59
60using testing::Return;
61
62namespace policy {
63
64namespace {
65
66const char kAccountId1[] = "dla1@example.com";
67const char kAccountId2[] = "dla2@example.com";
68const char kDisplayName1[] = "display name for account 1";
69const char kDisplayName2[] = "display name for account 2";
70const char* kStartupURLs[] = {
71  "chrome://policy",
72  "chrome://about",
73};
74
75}  // namespace
76
77class DeviceLocalAccountTest : public InProcessBrowserTest {
78 protected:
79  DeviceLocalAccountTest()
80      : user_id_1_(GenerateDeviceLocalAccountUserId(
81            kAccountId1, DeviceLocalAccount::TYPE_PUBLIC_SESSION)),
82        user_id_2_(GenerateDeviceLocalAccountUserId(
83            kAccountId2, DeviceLocalAccount::TYPE_PUBLIC_SESSION)) {}
84
85  virtual ~DeviceLocalAccountTest() {}
86
87  virtual void SetUp() OVERRIDE {
88    // Configure and start the test server.
89    scoped_ptr<crypto::RSAPrivateKey> signing_key(
90        PolicyBuilder::CreateTestSigningKey());
91    ASSERT_TRUE(test_server_.SetSigningKey(signing_key.get()));
92    signing_key.reset();
93    test_server_.RegisterClient(PolicyBuilder::kFakeToken,
94                                PolicyBuilder::kFakeDeviceId);
95    ASSERT_TRUE(test_server_.Start());
96
97    InProcessBrowserTest::SetUp();
98  }
99
100  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
101    command_line->AppendSwitch(chromeos::switches::kLoginManager);
102    command_line->AppendSwitch(chromeos::switches::kForceLoginManagerInTests);
103    command_line->AppendSwitchASCII(
104        switches::kDeviceManagementUrl, test_server_.GetServiceURL().spec());
105    command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user");
106  }
107
108  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
109    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
110
111    // Clear command-line arguments (but keep command-line switches) so the
112    // startup pages policy takes effect.
113    CommandLine* command_line = CommandLine::ForCurrentProcess();
114    CommandLine::StringVector argv(command_line->argv());
115    argv.erase(argv.begin() + argv.size() - command_line->GetArgs().size(),
116               argv.end());
117    command_line->InitFromArgv(argv);
118
119    // Mark the device enterprise-enrolled.
120    SetUpInstallAttributes();
121
122    // Redirect session_manager DBus calls to FakeSessionManagerClient.
123    chromeos::MockDBusThreadManagerWithoutGMock* dbus_thread_manager =
124        new chromeos::MockDBusThreadManagerWithoutGMock();
125    session_manager_client_ =
126        dbus_thread_manager->fake_session_manager_client();
127    chromeos::DBusThreadManager::InitializeForTesting(dbus_thread_manager);
128
129    SetUpPolicy();
130  }
131
132  virtual void CleanUpOnMainThread() OVERRIDE {
133    // This shuts down the login UI.
134    base::MessageLoop::current()->PostTask(FROM_HERE,
135                                           base::Bind(&chrome::AttemptExit));
136    base::RunLoop().RunUntilIdle();
137  }
138
139  void SetUpInstallAttributes() {
140    cryptohome::SerializedInstallAttributes install_attrs_proto;
141    cryptohome::SerializedInstallAttributes::Attribute* attribute = NULL;
142
143    attribute = install_attrs_proto.add_attributes();
144    attribute->set_name(EnterpriseInstallAttributes::kAttrEnterpriseOwned);
145    attribute->set_value("true");
146
147    attribute = install_attrs_proto.add_attributes();
148    attribute->set_name(EnterpriseInstallAttributes::kAttrEnterpriseUser);
149    attribute->set_value(PolicyBuilder::kFakeUsername);
150
151    base::FilePath install_attrs_file =
152        temp_dir_.path().AppendASCII("install_attributes.pb");
153    const std::string install_attrs_blob(
154        install_attrs_proto.SerializeAsString());
155    ASSERT_EQ(static_cast<int>(install_attrs_blob.size()),
156              file_util::WriteFile(install_attrs_file,
157                                   install_attrs_blob.c_str(),
158                                   install_attrs_blob.size()));
159    ASSERT_TRUE(PathService::Override(chromeos::FILE_INSTALL_ATTRIBUTES,
160                                      install_attrs_file));
161  }
162
163  void SetUpPolicy() {
164    // Configure two device-local accounts in device settings.
165    DevicePolicyBuilder device_policy;
166    device_policy.policy_data().set_public_key_version(1);
167    em::ChromeDeviceSettingsProto& proto(device_policy.payload());
168    proto.mutable_show_user_names()->set_show_user_names(true);
169    em::DeviceLocalAccountInfoProto* account1 =
170        proto.mutable_device_local_accounts()->add_account();
171    account1->set_account_id(kAccountId1);
172    account1->set_type(
173        em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION);
174    em::DeviceLocalAccountInfoProto* account2 =
175        proto.mutable_device_local_accounts()->add_account();
176    account2->set_account_id(kAccountId2);
177    account2->set_type(
178        em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION);
179    device_policy.Build();
180    session_manager_client_->set_device_policy(device_policy.GetBlob());
181    test_server_.UpdatePolicy(dm_protocol::kChromeDevicePolicyType,
182                              std::string(), proto.SerializeAsString());
183
184    // Install the owner key.
185    base::FilePath owner_key_file = temp_dir_.path().AppendASCII("owner.key");
186    std::vector<uint8> owner_key_bits;
187    ASSERT_TRUE(device_policy.signing_key()->ExportPublicKey(&owner_key_bits));
188    ASSERT_EQ(
189        static_cast<int>(owner_key_bits.size()),
190        file_util::WriteFile(
191            owner_key_file,
192            reinterpret_cast<const char*>(vector_as_array(&owner_key_bits)),
193            owner_key_bits.size()));
194    ASSERT_TRUE(
195        PathService::Override(chromeos::FILE_OWNER_KEY, owner_key_file));
196
197    // Configure device-local account policy for the first device-local account.
198    UserPolicyBuilder device_local_account_policy;
199    device_local_account_policy.policy_data().set_policy_type(
200        dm_protocol::kChromePublicAccountPolicyType);
201    device_local_account_policy.policy_data().set_username(kAccountId1);
202    device_local_account_policy.policy_data().set_settings_entity_id(
203        kAccountId1);
204    device_local_account_policy.policy_data().set_public_key_version(1);
205    device_local_account_policy.payload().mutable_restoreonstartup()->set_value(
206        SessionStartupPref::kPrefValueURLs);
207    em::StringListPolicyProto* startup_urls_proto =
208        device_local_account_policy.payload().mutable_restoreonstartupurls();
209    for (size_t i = 0; i < arraysize(kStartupURLs); ++i)
210      startup_urls_proto->mutable_value()->add_entries(kStartupURLs[i]);
211    device_local_account_policy.payload().mutable_userdisplayname()->set_value(
212        kDisplayName1);
213    device_local_account_policy.Build();
214    session_manager_client_->set_device_local_account_policy(
215        kAccountId1, device_local_account_policy.GetBlob());
216    test_server_.UpdatePolicy(
217        dm_protocol::kChromePublicAccountPolicyType, kAccountId1,
218        device_local_account_policy.payload().SerializeAsString());
219
220    // Make policy for the second account available from the server.
221    device_local_account_policy.payload().mutable_userdisplayname()->set_value(
222        kDisplayName2);
223    test_server_.UpdatePolicy(
224        dm_protocol::kChromePublicAccountPolicyType, kAccountId2,
225        device_local_account_policy.payload().SerializeAsString());
226
227    // Don't install policy for |kAccountId2| yet so initial download gets
228    // test coverage.
229    ASSERT_TRUE(session_manager_client_->device_local_account_policy(
230        kAccountId2).empty());
231  }
232
233  void CheckPublicSessionPresent(const std::string& id) {
234    const chromeos::User* user = chromeos::UserManager::Get()->FindUser(id);
235    ASSERT_TRUE(user);
236    EXPECT_EQ(id, user->email());
237    EXPECT_EQ(chromeos::User::USER_TYPE_PUBLIC_ACCOUNT, user->GetType());
238  }
239
240  const std::string user_id_1_;
241  const std::string user_id_2_;
242
243  LocalPolicyTestServer test_server_;
244  base::ScopedTempDir temp_dir_;
245
246  chromeos::FakeSessionManagerClient* session_manager_client_;
247};
248
249static bool IsKnownUser(const std::string& account_id) {
250  return chromeos::UserManager::Get()->IsKnownUser(account_id);
251}
252
253IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, LoginScreen) {
254  content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
255                                        base::Bind(&IsKnownUser, user_id_1_))
256      .Wait();
257  content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
258                                        base::Bind(&IsKnownUser, user_id_2_))
259      .Wait();
260
261  CheckPublicSessionPresent(user_id_1_);
262  CheckPublicSessionPresent(user_id_2_);
263}
264
265static bool DisplayNameMatches(const std::string& account_id,
266                        const std::string& display_name) {
267  const chromeos::User* user =
268      chromeos::UserManager::Get()->FindUser(account_id);
269  if (!user || user->display_name().empty())
270    return false;
271  EXPECT_EQ(UTF8ToUTF16(display_name), user->display_name());
272  return true;
273}
274
275IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, DisplayName) {
276  content::WindowedNotificationObserver(
277      chrome::NOTIFICATION_USER_LIST_CHANGED,
278      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName1)).Wait();
279}
280
281IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, PolicyDownload) {
282  // Policy for kAccountId2 is not installed in session_manager_client, make
283  // sure it gets fetched from the server. Note that the test setup doesn't set
284  // up policy for kAccountId2, so the presence of the display name can be used
285  // as signal to indicate successful policy download.
286  content::WindowedNotificationObserver(
287      chrome::NOTIFICATION_USER_LIST_CHANGED,
288      base::Bind(&DisplayNameMatches, user_id_2_, kDisplayName2)).Wait();
289
290  // Sanity check: The policy should be present now.
291  ASSERT_FALSE(session_manager_client_->device_local_account_policy(
292      kAccountId2).empty());
293}
294
295static bool IsNotKnownUser(const std::string& account_id) {
296  return !IsKnownUser(account_id);
297}
298
299IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, DevicePolicyChange) {
300  // Wait until the login screen is up.
301  content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
302                                        base::Bind(&IsKnownUser, user_id_1_))
303      .Wait();
304  content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
305                                        base::Bind(&IsKnownUser, user_id_2_))
306      .Wait();
307
308  // Update policy to remove kAccountId2.
309  em::ChromeDeviceSettingsProto policy;
310  policy.mutable_show_user_names()->set_show_user_names(true);
311  em::DeviceLocalAccountInfoProto* account1 =
312      policy.mutable_device_local_accounts()->add_account();
313  account1->set_account_id(kAccountId1);
314  account1->set_type(
315      em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION);
316
317  test_server_.UpdatePolicy(dm_protocol::kChromeDevicePolicyType, std::string(),
318                            policy.SerializeAsString());
319  g_browser_process->policy_service()->RefreshPolicies(base::Closure());
320
321  // Make sure the second device-local account disappears.
322  content::WindowedNotificationObserver(
323      chrome::NOTIFICATION_USER_LIST_CHANGED,
324      base::Bind(&IsNotKnownUser, user_id_2_)).Wait();
325}
326
327static bool IsSessionStarted() {
328  return chromeos::UserManager::Get()->IsSessionStarted();
329}
330
331IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, StartSession) {
332  // This observes the display name becoming available as this indicates
333  // device-local account policy is fully loaded, which is a prerequisite for
334  // successful login.
335  content::WindowedNotificationObserver(
336      chrome::NOTIFICATION_USER_LIST_CHANGED,
337      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName1)).Wait();
338
339  chromeos::LoginDisplayHost* host =
340      chromeos::LoginDisplayHostImpl::default_host();
341  ASSERT_TRUE(host);
342  host->StartSignInScreen();
343  chromeos::ExistingUserController* controller =
344      chromeos::ExistingUserController::current_controller();
345  ASSERT_TRUE(controller);
346  controller->LoginAsPublicAccount(user_id_1_);
347
348  // Wait for the session to start.
349  content::WindowedNotificationObserver(chrome::NOTIFICATION_SESSION_STARTED,
350                                        base::Bind(IsSessionStarted)).Wait();
351
352  // Check that the startup pages specified in policy were opened.
353  EXPECT_EQ(1U, chrome::GetTotalBrowserCount());
354  Browser* browser =
355      chrome::FindLastActiveWithHostDesktopType(chrome::HOST_DESKTOP_TYPE_ASH);
356  ASSERT_TRUE(browser);
357
358  TabStripModel* tabs = browser->tab_strip_model();
359  ASSERT_TRUE(tabs);
360  int expected_tab_count = static_cast<int>(arraysize(kStartupURLs));
361  EXPECT_EQ(expected_tab_count, tabs->count());
362  for (int i = 0; i < expected_tab_count && i < tabs->count(); ++i)
363    EXPECT_EQ(GURL(kStartupURLs[i]), tabs->GetWebContentsAt(i)->GetURL());
364}
365
366}  // namespace policy
367