| Index: chrome/browser/chromeos/login/signin/device_id_browsertest.cc
|
| diff --git a/chrome/browser/chromeos/login/signin/device_id_browsertest.cc b/chrome/browser/chromeos/login/signin/device_id_browsertest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..b3ea8d0408d665c6dd689399ce9627cc4cfde6ed
|
| --- /dev/null
|
| +++ b/chrome/browser/chromeos/login/signin/device_id_browsertest.cc
|
| @@ -0,0 +1,279 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "base/command_line.h"
|
| +#include "base/files/file_path.h"
|
| +#include "base/json/json_reader.h"
|
| +#include "base/json/json_writer.h"
|
| +#include "base/message_loop/message_loop.h"
|
| +#include "base/prefs/pref_service.h"
|
| +#include "base/run_loop.h"
|
| +#include "base/strings/stringprintf.h"
|
| +#include "chrome/browser/chromeos/login/test/oobe_base_test.h"
|
| +#include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
|
| +#include "chrome/browser/chromeos/login/ui/oobe_display.h"
|
| +#include "chrome/browser/chromeos/profiles/profile_helper.h"
|
| +#include "chrome/browser/signin/chrome_signin_client_factory.h"
|
| +#include "chrome/common/chrome_switches.h"
|
| +#include "chrome/test/base/in_process_browser_test.h"
|
| +#include "chromeos/chromeos_switches.h"
|
| +#include "components/signin/core/common/signin_pref_names.h"
|
| +#include "components/user_manager/remove_user_delegate.h"
|
| +#include "components/user_manager/user_manager.h"
|
| +
|
| +namespace {
|
| +
|
| +char kRefreshToken1[] = "refresh_token_1";
|
| +char kRefreshToken2[] = "refresh_token_2";
|
| +const base::FilePath::CharType kRefreshTokenToDeviceIdMapFile[] =
|
| + FILE_PATH_LITERAL("refrest_token_to_device_id.json");
|
| +
|
| +char kSecondUserEmail[] = "second_user@gmail.com";
|
| +char kSecondUserPassword[] = "password";
|
| +char kSecondUserRefreshToken1[] = "refresh_token_second_user_1";
|
| +char kSecondUserRefreshToken2[] = "refresh_token_second_user_2";
|
| +
|
| +} // namespace
|
| +
|
| +namespace chromeos {
|
| +
|
| +class DeviceIDTest : public OobeBaseTest,
|
| + public user_manager::RemoveUserDelegate {
|
| + public:
|
| + void SetUpCommandLine(base::CommandLine* command_line) override {
|
| + OobeBaseTest::SetUpCommandLine(command_line);
|
| + command_line->AppendSwitch(switches::kOobeSkipPostLogin);
|
| + }
|
| +
|
| + void SetUpOnMainThread() override {
|
| + OobeBaseTest::SetUpOnMainThread();
|
| + LoadRefreshTokenToDeviceIdMap();
|
| + }
|
| +
|
| + void TearDownOnMainThread() override {
|
| + SaveRefreshTokenToDeviceIdMap();
|
| + OobeBaseTest::TearDownOnMainThread();
|
| + }
|
| +
|
| + std::string GetDeviceId(const std::string& user_id) {
|
| + return user_manager::UserManager::Get()->GetKnownUserDeviceId(user_id);
|
| + }
|
| +
|
| + std::string GetDeviceIdFromSigninClient(const std::string& user_id) {
|
| + return ChromeSigninClientFactory::GetForProfile(
|
| + ProfileHelper::Get()->GetProfileByUser(
|
| + user_manager::UserManager::Get()->FindUser(user_id)))
|
| + ->GetSigninScopedDeviceId();
|
| + }
|
| +
|
| + std::string GetDeviceIdFromGAIA(const std::string& refresh_token) {
|
| + return fake_gaia_->GetDeviceIdByRefreshToken(refresh_token);
|
| + }
|
| +
|
| + // Checks that user's device ID retrieved from UserManager and SigninClient
|
| + // are the same.
|
| + // If |refresh_token| is not empty, checks that device ID associated with the
|
| + // |refresh_token| in GAIA is the same as ID saved on device.
|
| + void CheckDeviceIDIsConsistent(const std::string& user_id,
|
| + const std::string& refresh_token) {
|
| + const std::string device_id_in_signin_client =
|
| + GetDeviceIdFromSigninClient(user_id);
|
| + const std::string device_id_in_local_state = GetDeviceId(user_id);
|
| +
|
| + EXPECT_FALSE(device_id_in_signin_client.empty());
|
| + EXPECT_EQ(device_id_in_signin_client, device_id_in_local_state);
|
| +
|
| + if (!refresh_token.empty()) {
|
| + const std::string device_id_in_gaia = GetDeviceIdFromGAIA(refresh_token);
|
| + EXPECT_EQ(device_id_in_signin_client, device_id_in_gaia);
|
| + }
|
| + }
|
| +
|
| + void WaitForSessionStart() {
|
| + content::WindowedNotificationObserver(
|
| + chrome::NOTIFICATION_SESSION_STARTED,
|
| + content::NotificationService::AllSources()).Wait();
|
| + }
|
| +
|
| + void SignInOnline(const std::string& user_id,
|
| + const std::string& password,
|
| + const std::string& refresh_token) {
|
| + WaitForGaiaPageLoad();
|
| +
|
| + FakeGaia::MergeSessionParams params;
|
| + params.email = user_id;
|
| + params.refresh_token = refresh_token;
|
| + fake_gaia_->UpdateMergeSessionParams(params);
|
| +
|
| + GetLoginDisplay()->ShowSigninScreenForCreds(user_id, password);
|
| + WaitForSessionStart();
|
| + }
|
| +
|
| + void SignInOffline(const std::string& user_id, const std::string& password) {
|
| + WaitForSigninScreen();
|
| +
|
| + JS().Execute(
|
| + base::StringPrintf("chrome.send('authenticateUser', ['%s', '%s'])",
|
| + user_id.c_str(), password.c_str()));
|
| + WaitForSessionStart();
|
| + }
|
| +
|
| + void RemoveUser(const std::string& user_id) {
|
| + user_manager::UserManager::Get()->RemoveUser(user_id, this);
|
| + user_removal_loop_.Run();
|
| + }
|
| +
|
| + private:
|
| + // user_manager::RemoveUserDelegate:
|
| + void OnBeforeUserRemoved(const std::string& username) override {}
|
| +
|
| + void OnUserRemoved(const std::string& username) override {
|
| + user_removal_loop_.Quit();
|
| + }
|
| +
|
| + base::FilePath GetRefreshTokenToDeviceIdMapFilePath() const {
|
| + return base::CommandLine::ForCurrentProcess()
|
| + ->GetSwitchValuePath(::switches::kUserDataDir)
|
| + .Append(kRefreshTokenToDeviceIdMapFile);
|
| + }
|
| +
|
| + void LoadRefreshTokenToDeviceIdMap() {
|
| + std::string file_contents;
|
| + if (!base::ReadFileToString(GetRefreshTokenToDeviceIdMapFilePath(),
|
| + &file_contents))
|
| + return;
|
| + scoped_ptr<base::Value> value(base::JSONReader::Read(file_contents));
|
| + base::DictionaryValue* dictionary;
|
| + EXPECT_TRUE(value->GetAsDictionary(&dictionary));
|
| + FakeGaia::RefreshTokenToDeviceIdMap map;
|
| + for (base::DictionaryValue::Iterator it(*dictionary); !it.IsAtEnd();
|
| + it.Advance()) {
|
| + std::string device_id;
|
| + EXPECT_TRUE(it.value().GetAsString(&device_id));
|
| + map[it.key()] = device_id;
|
| + }
|
| + fake_gaia_->SetRefreshTokenToDeviceIdMap(map);
|
| + }
|
| +
|
| + void SaveRefreshTokenToDeviceIdMap() {
|
| + base::DictionaryValue dictionary;
|
| + for (const auto& kv : fake_gaia_->refresh_token_to_device_id_map())
|
| + dictionary.SetStringWithoutPathExpansion(kv.first, kv.second);
|
| + std::string json;
|
| + EXPECT_TRUE(base::JSONWriter::Write(dictionary, &json));
|
| + EXPECT_TRUE(base::WriteFile(GetRefreshTokenToDeviceIdMapFilePath(),
|
| + json.c_str(), json.length()));
|
| + }
|
| +
|
| + base::RunLoop user_removal_loop_;
|
| +};
|
| +
|
| +// Add the first user and check that device ID is consistent.
|
| +IN_PROC_BROWSER_TEST_F(DeviceIDTest, PRE_PRE_PRE_PRE_PRE_NewUsers) {
|
| + SignInOnline(kFakeUserEmail, kFakeUserPassword, kRefreshToken1);
|
| + CheckDeviceIDIsConsistent(kFakeUserEmail, kRefreshToken1);
|
| +}
|
| +
|
| +// Authenticate the first user through GAIA and verify that device ID remains
|
| +// the same.
|
| +IN_PROC_BROWSER_TEST_F(DeviceIDTest, PRE_PRE_PRE_PRE_NewUsers) {
|
| + const std::string device_id = GetDeviceId(kFakeUserEmail);
|
| + EXPECT_FALSE(device_id.empty());
|
| + EXPECT_EQ(device_id, GetDeviceIdFromGAIA(kRefreshToken1));
|
| +
|
| + SignInOnline(kFakeUserEmail, kFakeUserPassword, kRefreshToken2);
|
| + CheckDeviceIDIsConsistent(kFakeUserEmail, kRefreshToken2);
|
| +
|
| + CHECK_EQ(device_id, GetDeviceId(kFakeUserEmail));
|
| +}
|
| +
|
| +// Authenticate the first user offline and verify that device ID remains
|
| +// the same.
|
| +IN_PROC_BROWSER_TEST_F(DeviceIDTest, PRE_PRE_PRE_NewUsers) {
|
| + const std::string device_id = GetDeviceId(kFakeUserEmail);
|
| + EXPECT_FALSE(device_id.empty());
|
| +
|
| + SignInOffline(kFakeUserEmail, kFakeUserPassword);
|
| + CheckDeviceIDIsConsistent(kFakeUserEmail, kRefreshToken2);
|
| +
|
| + // Verify that device ID remained the same after offline auth.
|
| + CHECK_EQ(device_id, GetDeviceId(kFakeUserEmail));
|
| +}
|
| +
|
| +// Add the second user.
|
| +IN_PROC_BROWSER_TEST_F(DeviceIDTest, PRE_PRE_NewUsers) {
|
| + WaitForSigninScreen();
|
| + JS().Execute("chrome.send('showAddUser')");
|
| + SignInOnline(kSecondUserEmail, kSecondUserPassword, kSecondUserRefreshToken1);
|
| + CheckDeviceIDIsConsistent(kSecondUserEmail, kSecondUserRefreshToken1);
|
| +}
|
| +
|
| +// Remove the second user.
|
| +IN_PROC_BROWSER_TEST_F(DeviceIDTest, PRE_NewUsers) {
|
| + WaitForSigninScreen();
|
| + RemoveUser(kSecondUserEmail);
|
| +}
|
| +
|
| +// Add the second user back. Verify that device ID has been changed.
|
| +IN_PROC_BROWSER_TEST_F(DeviceIDTest, NewUsers) {
|
| + EXPECT_TRUE(GetDeviceId(kSecondUserEmail).empty());
|
| + SignInOnline(kSecondUserEmail, kSecondUserPassword, kSecondUserRefreshToken2);
|
| + CheckDeviceIDIsConsistent(kSecondUserEmail, kSecondUserRefreshToken2);
|
| + EXPECT_NE(GetDeviceIdFromGAIA(kSecondUserRefreshToken1),
|
| + GetDeviceId(kSecondUserEmail));
|
| +}
|
| +
|
| +// Set up a user that has a device ID stored in preference only.
|
| +IN_PROC_BROWSER_TEST_F(DeviceIDTest, PRE_Migration) {
|
| + SignInOnline(kFakeUserEmail, kFakeUserPassword, kRefreshToken1);
|
| +
|
| + // Simulate user that has device ID saved only in preferences (pre-M44).
|
| + PrefService* prefs =
|
| + ProfileHelper::Get()
|
| + ->GetProfileByUser(user_manager::UserManager::Get()->GetActiveUser())
|
| + ->GetPrefs();
|
| + prefs->SetString(prefs::kGoogleServicesSigninScopedDeviceId,
|
| + GetDeviceId(kFakeUserEmail));
|
| +
|
| + // Can't use SetKnownUserDeviceId here, because it forbids changing a device
|
| + // ID.
|
| + user_manager::UserManager::Get()->SetKnownUserStringPref(
|
| + kFakeUserEmail, "device_id", std::string());
|
| +}
|
| +
|
| +// Tests that after the first sign in the device ID has been moved to the Local
|
| +// state.
|
| +IN_PROC_BROWSER_TEST_F(DeviceIDTest, Migration) {
|
| + EXPECT_TRUE(GetDeviceId(kFakeUserEmail).empty());
|
| + SignInOffline(kFakeUserEmail, kFakeUserPassword);
|
| + CheckDeviceIDIsConsistent(kFakeUserEmail, kRefreshToken1);
|
| +}
|
| +
|
| +// Set up a user that doesn't have a device ID.
|
| +IN_PROC_BROWSER_TEST_F(DeviceIDTest, PRE_LegacyUsers) {
|
| + SignInOnline(kFakeUserEmail, kFakeUserPassword, kRefreshToken1);
|
| +
|
| + PrefService* prefs =
|
| + ProfileHelper::Get()
|
| + ->GetProfileByUser(user_manager::UserManager::Get()->GetActiveUser())
|
| + ->GetPrefs();
|
| + EXPECT_TRUE(
|
| + prefs->GetString(prefs::kGoogleServicesSigninScopedDeviceId).empty());
|
| +
|
| + // Can't use SetKnownUserDeviceId here, because it forbids changing a device
|
| + // ID.
|
| + user_manager::UserManager::Get()->SetKnownUserStringPref(
|
| + kFakeUserEmail, "device_id", std::string());
|
| +}
|
| +
|
| +// Tests that device ID has been generated after the first sign in.
|
| +IN_PROC_BROWSER_TEST_F(DeviceIDTest, LegacyUsers) {
|
| + EXPECT_TRUE(GetDeviceId(kFakeUserEmail).empty());
|
| + SignInOffline(kFakeUserEmail, kFakeUserPassword);
|
| + // Last param |auth_code| is empty, because we don't pass a device ID to GAIA
|
| + // in this case.
|
| + CheckDeviceIDIsConsistent(kFakeUserEmail, std::string());
|
| +}
|
| +
|
| +} // namespace chromeos
|
|
|