1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
|
// Copyright 2013 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 "chrome/browser/net/nss_context.h"
#include <memory>
#include "base/bind.h"
#include "base/run_loop.h"
#include "base/task/post_task.h"
#include "chrome/browser/chromeos/login/login_manager_test.h"
#include "chrome/browser/chromeos/login/startup_utils.h"
#include "chrome/browser/chromeos/login/ui/user_adding_screen.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "net/cert/nss_cert_database.h"
namespace {
constexpr char kTestUser1[] = "test-user1@gmail.com";
constexpr char kTestUser1GaiaId[] = "1111111111";
constexpr char kTestUser2[] = "test-user2@gmail.com";
constexpr char kTestUser2GaiaId[] = "2222222222";
void NotCalledDbCallback(net::NSSCertDatabase* db) { ASSERT_TRUE(false); }
// DBTester handles retrieving the NSSCertDatabase for a given profile, and
// doing some simple sanity checks.
// Browser test cases run on the UI thread, while the nss_context access needs
// to happen on the IO thread. The DBTester class encapsulates the thread
// posting and waiting on the UI thread so that the test case body can be
// written linearly.
class DBTester {
public:
explicit DBTester(Profile* profile) : profile_(profile), db_(NULL) {}
// Initial retrieval of cert database. It may be asynchronous or synchronous.
// Returns true if the database was retrieved successfully.
bool DoGetDBTests() {
base::RunLoop run_loop;
base::PostTaskWithTraits(
FROM_HERE, {content::BrowserThread::IO},
base::Bind(&DBTester::GetDBAndDoTestsOnIOThread, base::Unretained(this),
profile_->GetResourceContext(), run_loop.QuitClosure()));
run_loop.Run();
return !!db_;
}
// Test retrieving the database again, should be called after DoGetDBTests.
void DoGetDBAgainTests() {
base::RunLoop run_loop;
base::PostTaskWithTraits(
FROM_HERE, {content::BrowserThread::IO},
base::Bind(&DBTester::DoGetDBAgainTestsOnIOThread,
base::Unretained(this), profile_->GetResourceContext(),
run_loop.QuitClosure()));
run_loop.Run();
}
void DoNotEqualsTests(DBTester* other_tester) {
// The DB and its NSS slots should be different for each profile.
EXPECT_NE(db_, other_tester->db_);
EXPECT_NE(db_->GetPublicSlot().get(),
other_tester->db_->GetPublicSlot().get());
}
private:
void GetDBAndDoTestsOnIOThread(content::ResourceContext* context,
const base::Closure& done_callback) {
net::NSSCertDatabase* db = GetNSSCertDatabaseForResourceContext(
context,
base::Bind(&DBTester::DoTestsOnIOThread,
base::Unretained(this),
done_callback));
if (db) {
DVLOG(1) << "got db synchronously";
DoTestsOnIOThread(done_callback, db);
} else {
DVLOG(1) << "getting db asynchronously...";
}
}
void DoTestsOnIOThread(const base::Closure& done_callback,
net::NSSCertDatabase* db) {
db_ = db;
EXPECT_TRUE(db);
if (db) {
EXPECT_TRUE(db->GetPublicSlot().get());
// Public and private slot are the same in tests.
EXPECT_EQ(db->GetPublicSlot().get(), db->GetPrivateSlot().get());
}
base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
done_callback);
}
void DoGetDBAgainTestsOnIOThread(content::ResourceContext* context,
const base::Closure& done_callback) {
net::NSSCertDatabase* db = GetNSSCertDatabaseForResourceContext(
context, base::Bind(&NotCalledDbCallback));
// Should always be synchronous now.
EXPECT_TRUE(db);
// Should return the same db as before.
EXPECT_EQ(db_, db);
base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
done_callback);
}
Profile* profile_;
net::NSSCertDatabase* db_;
};
class UserAddingFinishObserver : public chromeos::UserAddingScreen::Observer {
public:
UserAddingFinishObserver() {
chromeos::UserAddingScreen::Get()->AddObserver(this);
}
~UserAddingFinishObserver() override {
chromeos::UserAddingScreen::Get()->RemoveObserver(this);
}
void WaitUntilUserAddingFinishedOrCancelled() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (finished_)
return;
run_loop_.reset(new base::RunLoop());
run_loop_->Run();
}
// chromeos::UserAddingScreen::Observer:
void OnUserAddingFinished() override {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
finished_ = true;
if (run_loop_)
run_loop_->Quit();
}
void OnUserAddingStarted() override {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
finished_ = false;
}
private:
bool finished_ = false;
std::unique_ptr<base::RunLoop> run_loop_;
DISALLOW_COPY_AND_ASSIGN(UserAddingFinishObserver);
};
} // namespace
class NSSContextChromeOSBrowserTest : public chromeos::LoginManagerTest {
public:
NSSContextChromeOSBrowserTest()
: LoginManagerTest(true /* should_launch_browser */,
true /* should_initialize_webui */) {}
~NSSContextChromeOSBrowserTest() override {}
};
IN_PROC_BROWSER_TEST_F(NSSContextChromeOSBrowserTest, PRE_TwoUsers) {
// Initialization for ChromeOS multi-profile test infrastructure.
RegisterUser(AccountId::FromUserEmailGaiaId(kTestUser1, kTestUser1GaiaId));
RegisterUser(AccountId::FromUserEmailGaiaId(kTestUser2, kTestUser2GaiaId));
chromeos::StartupUtils::MarkOobeCompleted();
}
IN_PROC_BROWSER_TEST_F(NSSContextChromeOSBrowserTest, TwoUsers) {
user_manager::UserManager* user_manager = user_manager::UserManager::Get();
// Log in first user and get their DB.
const AccountId account_id1(
AccountId::FromUserEmailGaiaId(kTestUser1, kTestUser1GaiaId));
LoginUser(account_id1);
Profile* profile1 = chromeos::ProfileHelper::Get()->GetProfileByUserUnsafe(
user_manager->FindUser(account_id1));
ASSERT_TRUE(profile1);
DBTester tester1(profile1);
ASSERT_TRUE(tester1.DoGetDBTests());
// Log in second user and get their DB.
UserAddingFinishObserver observer;
chromeos::UserAddingScreen::Get()->Start();
base::RunLoop().RunUntilIdle();
const AccountId account_id2(
AccountId::FromUserEmailGaiaId(kTestUser2, kTestUser2GaiaId));
AddUser(account_id2);
observer.WaitUntilUserAddingFinishedOrCancelled();
Profile* profile2 = chromeos::ProfileHelper::Get()->GetProfileByUserUnsafe(
user_manager->FindUser(account_id2));
ASSERT_TRUE(profile2);
DBTester tester2(profile2);
ASSERT_TRUE(tester2.DoGetDBTests());
// Get both DBs again to check that the same object is returned.
tester1.DoGetDBAgainTests();
tester2.DoGetDBAgainTests();
// Check that each user has a separate DB and NSS slots.
tester1.DoNotEqualsTests(&tester2);
}
|