blob: 5f70aad84825cd87c00d55ca278eb13534c992c9 [file] [log] [blame]
Lutz Justenb7ef5802019-05-14 14:03:20 +02001// Copyright 2019 The Chromium OS 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 "kerberos/account_manager.h"
6
7#include <map>
8#include <memory>
9#include <utility>
10
11#include <base/bind.h>
Qijiang Fan713061e2021-03-08 15:45:12 +090012#include <base/check.h>
Lutz Justene39cbd42019-05-14 14:52:24 +020013#include <base/files/file_path.h>
Lutz Justenb7ef5802019-05-14 14:03:20 +020014#include <base/files/file_util.h>
15#include <base/files/scoped_temp_dir.h>
Lutz Justend925d712019-06-27 17:34:00 +020016#include <base/memory/ref_counted.h>
17#include <base/test/test_mock_time_task_runner.h>
Lutz Justen2d857e12019-07-16 15:58:09 +020018#include <gmock/gmock.h>
Lutz Justenb7ef5802019-05-14 14:03:20 +020019#include <gtest/gtest.h>
Lutz Justen04afd272019-06-14 16:31:26 +020020#include <libpasswordprovider/fake_password_provider.h>
21#include <libpasswordprovider/password_provider_test_utils.h>
Lutz Justenb7ef5802019-05-14 14:03:20 +020022
Lutz Justene39cbd42019-05-14 14:52:24 +020023#include "kerberos/fake_krb5_interface.h"
Lutz Justen2d857e12019-07-16 15:58:09 +020024#include "kerberos/kerberos_metrics.h"
Lutz Justen33601802019-07-03 22:40:57 +020025#include "kerberos/krb5_jail_wrapper.h"
Lutz Justene39cbd42019-05-14 14:52:24 +020026
Lutz Justen2d857e12019-07-16 15:58:09 +020027using testing::_;
28using testing::Mock;
29using testing::NiceMock;
30using testing::Return;
31
Lutz Justend925d712019-06-27 17:34:00 +020032namespace kerberos {
Lutz Justenb7ef5802019-05-14 14:03:20 +020033namespace {
Lutz Justen6f582982019-05-15 10:24:22 +020034
Lutz Justenb7ef5802019-05-14 14:03:20 +020035constexpr char kUser[] = "user@REALM.COM";
Lutz Justen6f582982019-05-15 10:24:22 +020036constexpr char kUser2[] = "user2@REALM2.COM";
Lutz Justen781825e2019-07-13 07:49:44 +020037constexpr char kUser3[] = "user3@REALM3.COM";
Lutz Justen6f582982019-05-15 10:24:22 +020038constexpr char kPassword[] = "i<3k3R8e5Oz";
Lutz Justen04afd272019-06-14 16:31:26 +020039constexpr char kPassword2[] = "ih4zf00d";
Lutz Justen6f582982019-05-15 10:24:22 +020040constexpr char kKrb5Conf[] = R"(
41 [libdefaults]
Felipe Andrade66aaf6b2020-03-24 13:05:57 +010042 forwardable = true)";
43constexpr char kStrongKrb5Conf[] = R"(
44 [libdefaults]
45 forwardable = true
46 default_tkt_enctypes = aes256-cts-hmac-sha1-96
47 default_tgs_enctypes = aes256-cts-hmac-sha1-96
48 permitted_enctypes = aes256-cts-hmac-sha1-96)";
49constexpr char kLegacyKrb5Conf[] = R"(
50 [libdefaults]
51 forwardable = true
52 default_tkt_enctypes = arcfour-hmac
53 default_tgs_enctypes = arcfour-hmac
54 permitted_enctypes = arcfour-hmac)";
Felipe Andrade90cb84e2020-04-07 20:28:33 +020055constexpr char kInvalidKrb5Conf[] = R"(
56 [libdefaults]
57 stonkskew = 123)";
Lutz Justen6f582982019-05-15 10:24:22 +020058
Lutz Justend925d712019-06-27 17:34:00 +020059constexpr Krb5Interface::TgtStatus kValidTgt(3600, 3600);
60constexpr Krb5Interface::TgtStatus kExpiredTgt(0, 0);
61
Lutz Justen04afd272019-06-14 16:31:26 +020062// Convenience defines to make code more readable
63constexpr bool kManaged = true;
64constexpr bool kUnmanaged = false;
65
66constexpr bool kRememberPassword = true;
67constexpr bool kDontRememberPassword = false;
68
69constexpr bool kUseLoginPassword = true;
70constexpr bool kDontUseLoginPassword = false;
71
72constexpr char kEmptyPassword[] = "";
73
Lutz Justen2d857e12019-07-16 15:58:09 +020074class MockMetrics : public KerberosMetrics {
75 public:
76 explicit MockMetrics(const base::FilePath& storage_dir)
77 : KerberosMetrics(storage_dir) {}
Qijiang Fan6bc59e12020-11-11 02:51:06 +090078 MockMetrics(const MockMetrics&) = delete;
79 MockMetrics& operator=(const MockMetrics&) = delete;
80
Lutz Justen2d857e12019-07-16 15:58:09 +020081 ~MockMetrics() override = default;
82
Ben Chan60470012019-09-24 14:01:54 -070083 MOCK_METHOD(bool, ShouldReportDailyUsageStats, (), (override));
84 MOCK_METHOD(void,
85 ReportDailyUsageStats,
86 (int, int, int, int, int),
87 (override));
Felipe Andrade66aaf6b2020-03-24 13:05:57 +010088 MOCK_METHOD(void,
89 ReportKerberosEncryptionTypes,
90 (KerberosEncryptionTypes),
91 (override));
Lutz Justen2d857e12019-07-16 15:58:09 +020092};
93
Lutz Justen6f582982019-05-15 10:24:22 +020094} // namespace
Lutz Justenb7ef5802019-05-14 14:03:20 +020095
Lutz Justenb7ef5802019-05-14 14:03:20 +020096class AccountManagerTest : public ::testing::Test {
97 public:
Lutz Justen6f582982019-05-15 10:24:22 +020098 AccountManagerTest()
99 : kerberos_files_changed_(
100 base::BindRepeating(&AccountManagerTest::OnKerberosFilesChanged,
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200101 base::Unretained(this))),
102 kerberos_ticket_expiring_(
103 base::BindRepeating(&AccountManagerTest::OnKerberosTicketExpiring,
Lutz Justen6f582982019-05-15 10:24:22 +0200104 base::Unretained(this))) {}
Qijiang Fan6bc59e12020-11-11 02:51:06 +0900105 AccountManagerTest(const AccountManagerTest&) = delete;
106 AccountManagerTest& operator=(const AccountManagerTest&) = delete;
107
Lutz Justenb7ef5802019-05-14 14:03:20 +0200108 ~AccountManagerTest() override = default;
109
110 void SetUp() override {
111 ::testing::Test::SetUp();
112
113 // Create temp directory for files written during tests.
114 CHECK(storage_dir_.CreateUniqueTempDir());
Lutz Justen6f582982019-05-15 10:24:22 +0200115 accounts_path_ = storage_dir_.GetPath().Append("accounts");
Lutz Justen33601802019-07-03 22:40:57 +0200116 account_dir_ = storage_dir_.GetPath().Append(
Lutz Justenc5690502019-05-24 17:00:54 +0200117 AccountManager::GetSafeFilenameForTesting(kUser));
Lutz Justen33601802019-07-03 22:40:57 +0200118 krb5cc_path_ = account_dir_.Append("krb5cc");
119 krb5conf_path_ = account_dir_.Append("krb5.conf");
120 password_path_ = account_dir_.Append("password");
Lutz Justenb7ef5802019-05-14 14:03:20 +0200121
Lutz Justen6f582982019-05-15 10:24:22 +0200122 // Create the manager with a fake krb5 interface.
123 auto krb5 = std::make_unique<FakeKrb5Interface>();
Lutz Justen04afd272019-06-14 16:31:26 +0200124 auto password_provider =
125 std::make_unique<password_provider::FakePasswordProvider>();
Lutz Justen2d857e12019-07-16 15:58:09 +0200126 metrics_ = std::make_unique<NiceMock<MockMetrics>>(storage_dir_.GetPath());
Lutz Justen6f582982019-05-15 10:24:22 +0200127 krb5_ = krb5.get();
Lutz Justen04afd272019-06-14 16:31:26 +0200128 password_provider_ = password_provider.get();
Lutz Justenb7ef5802019-05-14 14:03:20 +0200129 manager_ = std::make_unique<AccountManager>(
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200130 storage_dir_.GetPath(), kerberos_files_changed_,
131 kerberos_ticket_expiring_, std::move(krb5),
Lutz Justen2d857e12019-07-16 15:58:09 +0200132 std::move(password_provider), metrics_.get());
Lutz Justenb7ef5802019-05-14 14:03:20 +0200133 }
134
Lutz Justen82d07ce2019-05-16 10:46:14 +0200135 void TearDown() override {
136 // Make sure the file stored on disk contains the same accounts as the
137 // manager instance. This catches cases where AccountManager forgets to save
138 // accounts on some change.
139 if (base::PathExists(accounts_path_)) {
Felipe Andrade89399f02019-11-11 15:52:14 +0100140 std::vector<Account> accounts = manager_->ListAccounts();
Lutz Justen82d07ce2019-05-16 10:46:14 +0200141
Lutz Justen04afd272019-06-14 16:31:26 +0200142 AccountManager other_manager(
143 storage_dir_.GetPath(), kerberos_files_changed_,
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200144 kerberos_ticket_expiring_, std::make_unique<FakeKrb5Interface>(),
Lutz Justen2d857e12019-07-16 15:58:09 +0200145 std::make_unique<password_provider::FakePasswordProvider>(),
146 metrics_.get());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200147 other_manager.LoadAccounts();
Felipe Andrade89399f02019-11-11 15:52:14 +0100148 std::vector<Account> other_accounts = other_manager.ListAccounts();
Lutz Justen82d07ce2019-05-16 10:46:14 +0200149
150 ASSERT_NO_FATAL_FAILURE(ExpectAccountsEqual(accounts, other_accounts));
151 }
152
153 ::testing::Test::TearDown();
154 }
155
Lutz Justen04afd272019-06-14 16:31:26 +0200156 // Add account with default settings.
157 ErrorType AddAccount() { return manager_->AddAccount(kUser, kUnmanaged); }
158
159 // Sets some default Kerberos configuration.
Felipe Andrade66aaf6b2020-03-24 13:05:57 +0100160 ErrorType SetConfig() { return SetConfig(kKrb5Conf); }
161
162 // Sets Kerberos configuration.
163 ErrorType SetConfig(const std::string& config) {
164 return manager_->SetConfig(kUser, config);
165 }
Lutz Justen04afd272019-06-14 16:31:26 +0200166
167 // Acquire Kerberos ticket with default credentials and settings.
168 ErrorType AcquireTgt() {
169 return manager_->AcquireTgt(kUser, kPassword, kDontRememberPassword,
170 kDontUseLoginPassword);
171 }
172
173 void SaveLoginPassword(const char* password) {
174 auto password_ptr = password_provider::test::CreatePassword(password);
175 password_provider_->SavePassword(*password_ptr);
176 }
177
Lutz Justend925d712019-06-27 17:34:00 +0200178 // Fast forwards to the next scheduled task (assumed to be the renewal task)
179 // and verifies expectation that |krb5_->RenewTgt() was called|.
180 void RunScheduledRenewalTask() {
181 int initial_count = krb5_->renew_tgt_call_count();
182 EXPECT_EQ(1, task_runner_->GetPendingTaskCount());
183 task_runner_->FastForwardBy(task_runner_->NextPendingTaskDelay());
184 EXPECT_EQ(initial_count + 1, krb5_->renew_tgt_call_count());
185 }
186
Lutz Justenb7ef5802019-05-14 14:03:20 +0200187 protected:
188 void OnKerberosFilesChanged(const std::string& principal_name) {
189 kerberos_files_changed_count_[principal_name]++;
190 }
191
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200192 void OnKerberosTicketExpiring(const std::string& principal_name) {
193 kerberos_ticket_expiring_count_[principal_name]++;
194 }
195
Lutz Justen82d07ce2019-05-16 10:46:14 +0200196 void ExpectAccountsEqual(const std::vector<Account>& account_list_1,
197 const std::vector<Account>& account_list_2) {
198 ASSERT_EQ(account_list_1.size(), account_list_2.size());
199 for (size_t n = 0; n < account_list_1.size(); ++n) {
200 const Account& account1 = account_list_1[n];
201 const Account& account2 = account_list_2[n];
202
203 EXPECT_EQ(account1.principal_name(), account2.principal_name());
204 EXPECT_EQ(account1.is_managed(), account2.is_managed());
Lutz Justen04afd272019-06-14 16:31:26 +0200205 EXPECT_EQ(account1.use_login_password(), account2.use_login_password());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200206 // TODO(https://crbug.com/952239): Check additional properties.
207 }
208 }
209
Lutz Justenb7ef5802019-05-14 14:03:20 +0200210 std::unique_ptr<AccountManager> manager_;
Lutz Justen6f582982019-05-15 10:24:22 +0200211
Lutz Justen04afd272019-06-14 16:31:26 +0200212 // Fake Kerberos interface used by |manager_|. Not owned.
Lutz Justen6f582982019-05-15 10:24:22 +0200213 FakeKrb5Interface* krb5_;
214
Lutz Justen04afd272019-06-14 16:31:26 +0200215 // Fake password provider to get the login password. Not owned.
216 password_provider::FakePasswordProvider* password_provider_;
217
Lutz Justen2d857e12019-07-16 15:58:09 +0200218 // Mock metrics for testing UMA stat recording.
219 std::unique_ptr<NiceMock<MockMetrics>> metrics_;
220
Lutz Justen6f582982019-05-15 10:24:22 +0200221 // Paths of files stored by |manager_|.
Lutz Justenb7ef5802019-05-14 14:03:20 +0200222 base::ScopedTempDir storage_dir_;
Lutz Justen6f582982019-05-15 10:24:22 +0200223 base::FilePath accounts_path_;
Lutz Justen33601802019-07-03 22:40:57 +0200224 base::FilePath account_dir_;
Lutz Justen6f582982019-05-15 10:24:22 +0200225 base::FilePath krb5conf_path_;
226 base::FilePath krb5cc_path_;
Lutz Justenc5690502019-05-24 17:00:54 +0200227 base::FilePath password_path_;
Lutz Justen6f582982019-05-15 10:24:22 +0200228
229 AccountManager::KerberosFilesChangedCallback kerberos_files_changed_;
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200230 AccountManager::KerberosTicketExpiringCallback kerberos_ticket_expiring_;
231
Lutz Justenb7ef5802019-05-14 14:03:20 +0200232 std::map<std::string, int> kerberos_files_changed_count_;
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200233 std::map<std::string, int> kerberos_ticket_expiring_count_;
Lutz Justenb7ef5802019-05-14 14:03:20 +0200234
Lutz Justend925d712019-06-27 17:34:00 +0200235 scoped_refptr<base::TestMockTimeTaskRunner> task_runner_{
236 new base::TestMockTimeTaskRunner()};
237 base::TestMockTimeTaskRunner::ScopedContext scoped_context_{task_runner_};
Lutz Justenb7ef5802019-05-14 14:03:20 +0200238};
239
Lutz Justen6f582982019-05-15 10:24:22 +0200240// Adding an account succeeds and serializes the file on disk.
Lutz Justenb7ef5802019-05-14 14:03:20 +0200241TEST_F(AccountManagerTest, AddAccountSuccess) {
Lutz Justen6f582982019-05-15 10:24:22 +0200242 EXPECT_FALSE(base::PathExists(accounts_path_));
Lutz Justen04afd272019-06-14 16:31:26 +0200243 EXPECT_EQ(ERROR_NONE, AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200244 EXPECT_TRUE(base::PathExists(accounts_path_));
Lutz Justenb7ef5802019-05-14 14:03:20 +0200245}
246
Lutz Justen6f582982019-05-15 10:24:22 +0200247// AddAccount() fails if the same account is added twice.
Lutz Justenb7ef5802019-05-14 14:03:20 +0200248TEST_F(AccountManagerTest, AddDuplicateAccountFail) {
Lutz Justen04afd272019-06-14 16:31:26 +0200249 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200250
hscham53cf73a2020-11-30 15:58:42 +0900251 EXPECT_TRUE(base::DeleteFile(accounts_path_));
Lutz Justen04afd272019-06-14 16:31:26 +0200252 EXPECT_EQ(ERROR_DUPLICATE_PRINCIPAL_NAME, AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200253 EXPECT_FALSE(base::PathExists(accounts_path_));
Lutz Justenb7ef5802019-05-14 14:03:20 +0200254}
255
Lutz Justen6f582982019-05-15 10:24:22 +0200256// Adding a managed account overwrites an existing unmanaged account.
257TEST_F(AccountManagerTest, ManagedOverridesUnmanaged) {
Lutz Justen04afd272019-06-14 16:31:26 +0200258 ignore_result(manager_->AddAccount(kUser, kUnmanaged));
Lutz Justen6f582982019-05-15 10:24:22 +0200259
Lutz Justen04afd272019-06-14 16:31:26 +0200260 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200261 EXPECT_TRUE(base::PathExists(krb5cc_path_));
262
263 // Overwriting with a managed account should wipe existing files and make the
264 // account managed.
Lutz Justen6f582982019-05-15 10:24:22 +0200265 EXPECT_EQ(ERROR_DUPLICATE_PRINCIPAL_NAME,
Lutz Justen04afd272019-06-14 16:31:26 +0200266 manager_->AddAccount(kUser, kManaged));
Lutz Justen82d07ce2019-05-16 10:46:14 +0200267 EXPECT_FALSE(base::PathExists(krb5cc_path_));
268
Felipe Andrade89399f02019-11-11 15:52:14 +0100269 std::vector<Account> accounts = manager_->ListAccounts();
Lutz Justen6f582982019-05-15 10:24:22 +0200270 ASSERT_EQ(1u, accounts.size());
271 EXPECT_TRUE(accounts[0].is_managed());
272}
273
274// Adding an unmanaged account does not overwrite an existing managed account.
275TEST_F(AccountManagerTest, UnmanagedDoesNotOverrideManaged) {
Lutz Justen04afd272019-06-14 16:31:26 +0200276 ignore_result(manager_->AddAccount(kUser, kManaged));
Lutz Justen6f582982019-05-15 10:24:22 +0200277
278 EXPECT_EQ(ERROR_DUPLICATE_PRINCIPAL_NAME,
Lutz Justen04afd272019-06-14 16:31:26 +0200279 manager_->AddAccount(kUser, kUnmanaged));
Felipe Andrade89399f02019-11-11 15:52:14 +0100280 std::vector<Account> accounts = manager_->ListAccounts();
Lutz Justen6f582982019-05-15 10:24:22 +0200281 ASSERT_EQ(1u, accounts.size());
282 EXPECT_TRUE(accounts[0].is_managed());
283}
284
285// RemoveAccount() succeeds if the account exists and serializes the file on
286// disk.
Lutz Justenb7ef5802019-05-14 14:03:20 +0200287TEST_F(AccountManagerTest, RemoveAccountSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200288 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200289
hscham53cf73a2020-11-30 15:58:42 +0900290 EXPECT_TRUE(base::DeleteFile(accounts_path_));
Lutz Justenb7ef5802019-05-14 14:03:20 +0200291 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
Lutz Justen6f582982019-05-15 10:24:22 +0200292 EXPECT_TRUE(base::PathExists(accounts_path_));
Lutz Justenb7ef5802019-05-14 14:03:20 +0200293}
294
Lutz Justen6f582982019-05-15 10:24:22 +0200295// RemoveAccount() fails if the account does not exist.
Lutz Justenb7ef5802019-05-14 14:03:20 +0200296TEST_F(AccountManagerTest, RemoveUnknownAccountFail) {
297 EXPECT_EQ(ERROR_UNKNOWN_PRINCIPAL_NAME, manager_->RemoveAccount(kUser));
Lutz Justen6f582982019-05-15 10:24:22 +0200298 EXPECT_FALSE(base::PathExists(accounts_path_));
299}
300
301// RemoveAccount() does not trigger KerberosFilesChanged if the credential cache
302// does not exists.
303TEST_F(AccountManagerTest, RemoveAccountTriggersKFCIfCCExists) {
Lutz Justen04afd272019-06-14 16:31:26 +0200304 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200305
306 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
307 EXPECT_EQ(0, kerberos_files_changed_count_[kUser]);
308}
309
310// RemoveAccount() triggers KerberosFilesChanged if the credential cache exists.
311TEST_F(AccountManagerTest, RemoveAccountDoesNotTriggerKFCIfCCDoesNotExist) {
Lutz Justen04afd272019-06-14 16:31:26 +0200312 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200313
Lutz Justen04afd272019-06-14 16:31:26 +0200314 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200315 EXPECT_EQ(1, kerberos_files_changed_count_[kUser]);
316 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
317 EXPECT_EQ(2, kerberos_files_changed_count_[kUser]);
Lutz Justenb7ef5802019-05-14 14:03:20 +0200318}
319
320// Repeatedly calling AddAccount() and RemoveAccount() succeeds.
321TEST_F(AccountManagerTest, RepeatedAddRemoveSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200322 ignore_result(AddAccount());
Lutz Justenb7ef5802019-05-14 14:03:20 +0200323 ignore_result(manager_->RemoveAccount(kUser));
Lutz Justen6f582982019-05-15 10:24:22 +0200324
Lutz Justen04afd272019-06-14 16:31:26 +0200325 EXPECT_EQ(ERROR_NONE, AddAccount());
Lutz Justenb7ef5802019-05-14 14:03:20 +0200326 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
327}
328
Lutz Justen2d420872019-06-25 14:17:21 +0200329// ClearAccounts(CLEAR_ALL) clears all accounts.
330TEST_F(AccountManagerTest, ClearAccountsSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200331 ignore_result(manager_->AddAccount(kUser, kUnmanaged));
332 ignore_result(manager_->AddAccount(kUser2, kManaged));
Lutz Justen82d07ce2019-05-16 10:46:14 +0200333
Lutz Justen781825e2019-07-13 07:49:44 +0200334 EXPECT_EQ(ERROR_NONE, manager_->ClearAccounts(CLEAR_ALL, {}));
Felipe Andrade89399f02019-11-11 15:52:14 +0100335 std::vector<Account> accounts = manager_->ListAccounts();
Lutz Justen82d07ce2019-05-16 10:46:14 +0200336 EXPECT_EQ(0u, accounts.size());
337}
338
Lutz Justen2d420872019-06-25 14:17:21 +0200339// ClearAccounts(CLEAR_ALL) wipes Kerberos configuration and credential cache.
340TEST_F(AccountManagerTest, ClearAccountsRemovesKerberosFiles) {
Lutz Justen04afd272019-06-14 16:31:26 +0200341 ignore_result(AddAccount());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200342
Lutz Justen04afd272019-06-14 16:31:26 +0200343 EXPECT_EQ(ERROR_NONE, SetConfig());
344 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200345 EXPECT_TRUE(base::PathExists(krb5conf_path_));
346 EXPECT_TRUE(base::PathExists(krb5cc_path_));
Lutz Justen781825e2019-07-13 07:49:44 +0200347 EXPECT_EQ(ERROR_NONE, manager_->ClearAccounts(CLEAR_ALL, {}));
Lutz Justen82d07ce2019-05-16 10:46:14 +0200348 EXPECT_FALSE(base::PathExists(krb5conf_path_));
349 EXPECT_FALSE(base::PathExists(krb5cc_path_));
350}
351
Lutz Justen2d420872019-06-25 14:17:21 +0200352// ClearAccounts(CLEAR_ALL) triggers KerberosFilesChanged if the credential
353// cache exists.
354TEST_F(AccountManagerTest, ClearAccountsTriggersKFCIfCCExists) {
Lutz Justen04afd272019-06-14 16:31:26 +0200355 ignore_result(AddAccount());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200356
Lutz Justen04afd272019-06-14 16:31:26 +0200357 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200358 EXPECT_EQ(1, kerberos_files_changed_count_[kUser]);
Lutz Justen781825e2019-07-13 07:49:44 +0200359 EXPECT_EQ(ERROR_NONE, manager_->ClearAccounts(CLEAR_ALL, {}));
Lutz Justen82d07ce2019-05-16 10:46:14 +0200360 EXPECT_EQ(2, kerberos_files_changed_count_[kUser]);
361}
362
Lutz Justen2d420872019-06-25 14:17:21 +0200363// ClearAccounts(CLEAR_ALL) does not trigger KerberosFilesChanged if the
364// credential cache does not exist.
365TEST_F(AccountManagerTest, ClearAccountsDoesNotTriggerKFCIfDoesNotCCExist) {
Lutz Justen04afd272019-06-14 16:31:26 +0200366 ignore_result(AddAccount());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200367
Lutz Justen781825e2019-07-13 07:49:44 +0200368 EXPECT_EQ(ERROR_NONE, manager_->ClearAccounts(CLEAR_ALL, {}));
Lutz Justen82d07ce2019-05-16 10:46:14 +0200369 EXPECT_EQ(0, kerberos_files_changed_count_[kUser]);
370}
371
Lutz Justen2d420872019-06-25 14:17:21 +0200372// ClearAccounts(CLEAR_ONLY_UNMANAGED_ACCOUNTS) clears only unmanaged accounts.
373TEST_F(AccountManagerTest, ClearUnmanagedAccountsSuccess) {
374 ignore_result(manager_->AddAccount(kUser, kUnmanaged));
375 ignore_result(manager_->AddAccount(kUser2, kManaged));
376
Lutz Justen781825e2019-07-13 07:49:44 +0200377 EXPECT_EQ(ERROR_NONE,
378 manager_->ClearAccounts(CLEAR_ONLY_UNMANAGED_ACCOUNTS, {}));
Felipe Andrade89399f02019-11-11 15:52:14 +0100379 std::vector<Account> accounts = manager_->ListAccounts();
Lutz Justen2d420872019-06-25 14:17:21 +0200380 ASSERT_EQ(1u, accounts.size());
381 EXPECT_EQ(kUser2, accounts[0].principal_name());
382}
383
384// ClearAccounts(CLEAR_ONLY_UNMANAGED_REMEMBERED_PASSWORDS) clears only
385// passwords of unmanaged accounts.
386TEST_F(AccountManagerTest, ClearUnmanagedPasswordsSuccess) {
387 // kUser is unmanaged, kUser2 is managed.
388 ignore_result(manager_->AddAccount(kUser, kUnmanaged));
389 ignore_result(manager_->AddAccount(kUser2, kManaged));
390 ignore_result(manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
391 kDontUseLoginPassword));
392 ignore_result(manager_->AcquireTgt(kUser2, kPassword, kRememberPassword,
393 kDontUseLoginPassword));
394
395 base::FilePath password_path_2 =
396 storage_dir_.GetPath()
397 .Append(AccountManager::GetSafeFilenameForTesting(kUser2))
398 .Append("password");
399 EXPECT_TRUE(base::PathExists(password_path_));
400 EXPECT_TRUE(base::PathExists(password_path_2));
401
Lutz Justen781825e2019-07-13 07:49:44 +0200402 EXPECT_EQ(ERROR_NONE, manager_->ClearAccounts(
403 CLEAR_ONLY_UNMANAGED_REMEMBERED_PASSWORDS, {}));
Felipe Andrade89399f02019-11-11 15:52:14 +0100404 std::vector<Account> accounts = manager_->ListAccounts();
Lutz Justen2d420872019-06-25 14:17:21 +0200405 ASSERT_EQ(2u, accounts.size());
406 EXPECT_FALSE(base::PathExists(password_path_));
407 EXPECT_TRUE(base::PathExists(password_path_2));
408}
409
Lutz Justen781825e2019-07-13 07:49:44 +0200410// ClearAccounts(CLEAR_ONLY_MANAGED_ACCOUNTS) clears only managed accounts that
411// are not on the keep list.
412TEST_F(AccountManagerTest, ClearManagedPasswordsWithKeepListSuccess) {
413 ignore_result(manager_->AddAccount(kUser, kManaged));
414 ignore_result(manager_->AddAccount(kUser2, kManaged));
415 ignore_result(manager_->AddAccount(kUser3, kUnmanaged));
416
417 // Keep the managed kUser-account.
418 EXPECT_EQ(ERROR_NONE,
419 manager_->ClearAccounts(CLEAR_ONLY_MANAGED_ACCOUNTS, {kUser}));
Felipe Andrade89399f02019-11-11 15:52:14 +0100420 std::vector<Account> accounts = manager_->ListAccounts();
Lutz Justen781825e2019-07-13 07:49:44 +0200421 ASSERT_EQ(2u, accounts.size());
422 EXPECT_EQ(kUser, accounts[0].principal_name());
423 EXPECT_EQ(kUser3, accounts[1].principal_name());
424}
425
Lutz Justen6f582982019-05-15 10:24:22 +0200426// SetConfig() succeeds and writes the config to |krb5conf_path_|.
427TEST_F(AccountManagerTest, SetConfigSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200428 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200429
Lutz Justen04afd272019-06-14 16:31:26 +0200430 EXPECT_EQ(ERROR_NONE, SetConfig());
Lutz Justen6f582982019-05-15 10:24:22 +0200431 std::string krb5_conf;
432 EXPECT_TRUE(base::ReadFileToString(krb5conf_path_, &krb5_conf));
433 EXPECT_EQ(krb5_conf, kKrb5Conf);
434}
435
Lutz Justen90281402019-07-05 15:14:37 +0200436// SetConfig() calls ValidateConfig on the Kerberos interface.
437TEST_F(AccountManagerTest, SetConfigValidatesConfig) {
438 ignore_result(AddAccount());
439
440 krb5_->set_validate_config_error(ERROR_BAD_CONFIG);
441 EXPECT_EQ(ERROR_BAD_CONFIG, SetConfig());
442}
443
Lutz Justen6f582982019-05-15 10:24:22 +0200444// SetConfig() triggers KerberosFilesChanged if the credential cache exists.
445TEST_F(AccountManagerTest, SetConfigTriggersKFCIfCCExists) {
Lutz Justen04afd272019-06-14 16:31:26 +0200446 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200447
Lutz Justen04afd272019-06-14 16:31:26 +0200448 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200449 EXPECT_EQ(1, kerberos_files_changed_count_[kUser]);
Lutz Justen04afd272019-06-14 16:31:26 +0200450 EXPECT_EQ(ERROR_NONE, SetConfig());
Lutz Justen6f582982019-05-15 10:24:22 +0200451 EXPECT_EQ(2, kerberos_files_changed_count_[kUser]);
452}
453
Lutz Justen82d07ce2019-05-16 10:46:14 +0200454// SetConfig() does not trigger KerberosFilesChanged if the credential cache
455// does not exist.
Lutz Justen6f582982019-05-15 10:24:22 +0200456TEST_F(AccountManagerTest, SetConfigDoesNotTriggerKFCIfDoesNotCCExist) {
Lutz Justen04afd272019-06-14 16:31:26 +0200457 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200458
Lutz Justen04afd272019-06-14 16:31:26 +0200459 EXPECT_EQ(ERROR_NONE, SetConfig());
Lutz Justen6f582982019-05-15 10:24:22 +0200460 EXPECT_EQ(0, kerberos_files_changed_count_[kUser]);
461}
462
463// RemoveAccount() removes the config file.
464TEST_F(AccountManagerTest, RemoveAccountRemovesConfig) {
Lutz Justen04afd272019-06-14 16:31:26 +0200465 ignore_result(AddAccount());
466 ignore_result(SetConfig());
Lutz Justen6f582982019-05-15 10:24:22 +0200467
468 EXPECT_TRUE(base::PathExists(krb5conf_path_));
469 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
470 EXPECT_FALSE(base::PathExists(krb5conf_path_));
471}
472
Lutz Justen90281402019-07-05 15:14:37 +0200473// ValidateConfig() validates a good config successfully.
474TEST_F(AccountManagerTest, ValidateConfigSuccess) {
475 constexpr char kValidKrb5Conf[] = "";
476 ConfigErrorInfo error_info;
477 EXPECT_EQ(ERROR_NONE, manager_->ValidateConfig(kValidKrb5Conf, &error_info));
478 EXPECT_EQ(CONFIG_ERROR_NONE, error_info.code());
479}
480
481// ValidateConfig() returns the correct error for a bad config.
482TEST_F(AccountManagerTest, ValidateConfigFailure) {
483 ConfigErrorInfo expected_error_info;
484 expected_error_info.set_code(CONFIG_ERROR_SECTION_SYNTAX);
485 krb5_->set_config_error_info(expected_error_info);
486 krb5_->set_validate_config_error(ERROR_BAD_CONFIG);
487
488 constexpr char kBadKrb5Conf[] =
489 "[libdefaults]'); DROP TABLE KerberosTickets;--";
490 ConfigErrorInfo error_info;
491 EXPECT_EQ(ERROR_BAD_CONFIG,
492 manager_->ValidateConfig(kBadKrb5Conf, &error_info));
493 EXPECT_EQ(expected_error_info.SerializeAsString(),
494 error_info.SerializeAsString());
495}
496
Lutz Justen6f582982019-05-15 10:24:22 +0200497// AcquireTgt() succeeds and writes a credential cache file.
498TEST_F(AccountManagerTest, AcquireTgtSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200499 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200500
Lutz Justen04afd272019-06-14 16:31:26 +0200501 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200502 EXPECT_TRUE(base::PathExists(krb5cc_path_));
503}
504
505// AcquireTgt() triggers KerberosFilesChanged on success.
506TEST_F(AccountManagerTest, AcquireTgtTriggersKFCOnSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200507 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200508
509 EXPECT_EQ(0, kerberos_files_changed_count_[kUser]);
Lutz Justen04afd272019-06-14 16:31:26 +0200510 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200511 EXPECT_EQ(1, kerberos_files_changed_count_[kUser]);
512}
513
514// AcquireTgt() does not trigger KerberosFilesChanged on failure.
515TEST_F(AccountManagerTest, AcquireTgtDoesNotTriggerKFCOnFailure) {
Lutz Justen04afd272019-06-14 16:31:26 +0200516 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200517
518 krb5_->set_acquire_tgt_error(ERROR_UNKNOWN);
Lutz Justen04afd272019-06-14 16:31:26 +0200519 EXPECT_EQ(ERROR_UNKNOWN, AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200520 EXPECT_EQ(0, kerberos_files_changed_count_[kUser]);
521}
522
Lutz Justenc5690502019-05-24 17:00:54 +0200523// AcquireTgt() saves password to disk if |remember_password| is true and
524// removes the file again if |remember_password| is false.
525TEST_F(AccountManagerTest, AcquireTgtRemembersPasswordsIfWanted) {
Lutz Justen04afd272019-06-14 16:31:26 +0200526 ignore_result(AddAccount());
Lutz Justenc5690502019-05-24 17:00:54 +0200527
528 EXPECT_FALSE(base::PathExists(password_path_));
Lutz Justen04afd272019-06-14 16:31:26 +0200529 EXPECT_EQ(ERROR_NONE,
530 manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
531 kDontUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200532 EXPECT_TRUE(base::PathExists(password_path_));
533
Lutz Justen04afd272019-06-14 16:31:26 +0200534 EXPECT_EQ(ERROR_NONE,
535 manager_->AcquireTgt(kUser, kPassword, kDontRememberPassword,
536 kDontUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200537 EXPECT_FALSE(base::PathExists(password_path_));
538}
539
540// AcquireTgt() uses saved password if none is given, no matter if it should be
541// remembered again or not.
542TEST_F(AccountManagerTest, AcquireTgtLoadsRememberedPassword) {
Lutz Justen04afd272019-06-14 16:31:26 +0200543 ignore_result(AddAccount());
544 ignore_result(manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
545 kDontUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200546
547 // This should load stored password and keep it.
548 EXPECT_EQ(ERROR_NONE,
Lutz Justen04afd272019-06-14 16:31:26 +0200549 manager_->AcquireTgt(kUser, kEmptyPassword, kRememberPassword,
550 kDontUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200551 EXPECT_TRUE(base::PathExists(password_path_));
552
553 // This should load stored password, but erase it afterwards.
554 EXPECT_EQ(ERROR_NONE,
Lutz Justen04afd272019-06-14 16:31:26 +0200555 manager_->AcquireTgt(kUser, kEmptyPassword, kDontRememberPassword,
556 kDontUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200557 EXPECT_FALSE(base::PathExists(password_path_));
558
559 // Check that the fake krb5 interface returns an error for a missing password.
560 // This verifies that the above AcquireTgt() call actually loaded the
561 // password from disk.
562 EXPECT_EQ(ERROR_BAD_PASSWORD,
Lutz Justen04afd272019-06-14 16:31:26 +0200563 manager_->AcquireTgt(kUser, kEmptyPassword, kDontRememberPassword,
564 kDontUseLoginPassword));
565}
566
567// AcquireTgt() uses the login password if saved.
568TEST_F(AccountManagerTest, AcquireTgtUsesLoginPassword) {
569 ignore_result(AddAccount());
570
571 // Shouldn't explode if the login password not set yet.
572 EXPECT_EQ(ERROR_BAD_PASSWORD,
573 manager_->AcquireTgt(kUser, kEmptyPassword, kDontRememberPassword,
574 kUseLoginPassword));
575
576 SaveLoginPassword(kPassword);
577 krb5_->set_expected_password(kPassword);
578
579 // Uses the login password.
580 EXPECT_EQ(ERROR_NONE,
581 manager_->AcquireTgt(kUser, kEmptyPassword, kDontRememberPassword,
582 kUseLoginPassword));
583
584 // Check if auth fails without kUseLoginPassword.
585 EXPECT_EQ(ERROR_BAD_PASSWORD,
586 manager_->AcquireTgt(kUser, kEmptyPassword, kDontRememberPassword,
587 kDontUseLoginPassword));
588}
589
590// AcquireTgt() wipes a saved password if the login password is used.
591TEST_F(AccountManagerTest, AcquireTgtWipesStoredPasswordOnUsesLoginPassword) {
592 ignore_result(AddAccount());
593 ignore_result(manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
594 kDontUseLoginPassword));
595 EXPECT_TRUE(base::PathExists(password_path_));
596
597 SaveLoginPassword(kPassword);
598
599 // Note: kRememberPassword gets ignored if kUseLoginPassword is passed.
600 EXPECT_EQ(ERROR_NONE,
601 manager_->AcquireTgt(kUser, kEmptyPassword, kRememberPassword,
602 kUseLoginPassword));
603 EXPECT_FALSE(base::PathExists(password_path_));
604}
605
606// AcquireTgt() ignores the passed password if the login password is used.
607TEST_F(AccountManagerTest, AcquireTgtIgnoresPassedPasswordOnUsesLoginPassword) {
608 ignore_result(AddAccount());
609
610 SaveLoginPassword(kPassword);
611 krb5_->set_expected_password(kPassword);
612
613 // Auth works despite passed kPassword2 != expected kPassword because the
614 // login kPassword is used.
615 EXPECT_EQ(ERROR_NONE,
616 manager_->AcquireTgt(kUser, kPassword2, kDontRememberPassword,
617 kUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200618}
619
Felipe Andrade66aaf6b2020-03-24 13:05:57 +0100620// AcquireTgt() records all encryption types UMA stats on success.
621TEST_F(AccountManagerTest, AcquireTgtEnctypesMetricsAll) {
622 ignore_result(AddAccount());
623 ignore_result(SetConfig());
624
625 // The expected encryption type should be reported through |metric_|.
626 EXPECT_CALL(*metrics_,
627 ReportKerberosEncryptionTypes(KerberosEncryptionTypes::kAll));
628
629 EXPECT_EQ(ERROR_NONE, AcquireTgt());
630}
631
632// AcquireTgt() records strong encryption types UMA stats on success.
633TEST_F(AccountManagerTest, AcquireTgtEnctypesMetricsStrong) {
634 ignore_result(AddAccount());
635 ignore_result(SetConfig(kStrongKrb5Conf));
636
637 // The expected encryption type should be reported through |metric_|.
638 EXPECT_CALL(*metrics_,
639 ReportKerberosEncryptionTypes(KerberosEncryptionTypes::kStrong));
640
641 EXPECT_EQ(ERROR_NONE, AcquireTgt());
642}
643
644// AcquireTgt() records legacy encryption types UMA stats on success.
645TEST_F(AccountManagerTest, AcquireTgtEnctypesMetricsLegacy) {
646 ignore_result(AddAccount());
647 ignore_result(SetConfig(kLegacyKrb5Conf));
648
649 // The expected encryption type should be reported through |metric_|.
650 EXPECT_CALL(*metrics_,
651 ReportKerberosEncryptionTypes(KerberosEncryptionTypes::kLegacy));
652
653 EXPECT_EQ(ERROR_NONE, AcquireTgt());
654}
655
656// AcquireTgt() doesn't record encryption types UMA stats on failure.
657TEST_F(AccountManagerTest, AcquireTgtEnctypesMetricsFailure) {
658 ignore_result(AddAccount());
659 ignore_result(SetConfig());
660
661 // No encryption type should be reported through |metric_|.
662 EXPECT_CALL(*metrics_, ReportKerberosEncryptionTypes(_)).Times(0);
663
664 krb5_->set_acquire_tgt_error(ERROR_UNKNOWN);
665 EXPECT_EQ(ERROR_UNKNOWN, AcquireTgt());
666}
667
668// AcquireTgt() doesn't record encryption types UMA stats if no config is
669// available.
670TEST_F(AccountManagerTest, AcquireTgtEnctypesMetricsNoConfig) {
671 ignore_result(AddAccount());
672
673 // No encryption type should be reported through |metric_|.
674 EXPECT_CALL(*metrics_, ReportKerberosEncryptionTypes(_)).Times(0);
675
676 EXPECT_EQ(ERROR_NONE, AcquireTgt());
677}
678
Felipe Andrade90cb84e2020-04-07 20:28:33 +0200679// AcquireTgt() doesn't record encryption types UMA stats if config is invalid.
680TEST_F(AccountManagerTest, AcquireTgtEnctypesMetricsInvalidConfig) {
681 ignore_result(AddAccount());
682 ignore_result(SetConfig(kInvalidKrb5Conf));
683
684 // No encryption type should be reported through |metric_|.
685 EXPECT_CALL(*metrics_, ReportKerberosEncryptionTypes(_)).Times(0);
686
687 EXPECT_EQ(ERROR_NONE, AcquireTgt());
688}
689
Lutz Justen6f582982019-05-15 10:24:22 +0200690// RemoveAccount() removes the credential cache file.
691TEST_F(AccountManagerTest, RemoveAccountRemovesCC) {
Lutz Justen04afd272019-06-14 16:31:26 +0200692 ignore_result(AddAccount());
693 ignore_result(AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200694
695 EXPECT_TRUE(base::PathExists(krb5cc_path_));
696 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
697 EXPECT_FALSE(base::PathExists(krb5cc_path_));
698}
699
Lutz Justenc5690502019-05-24 17:00:54 +0200700// RemoveAccount() removes saved passwords.
701TEST_F(AccountManagerTest, RemoveAccountRemovesPassword) {
Lutz Justen04afd272019-06-14 16:31:26 +0200702 ignore_result(AddAccount());
703 ignore_result(manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
704 kDontUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200705
706 EXPECT_TRUE(base::PathExists(password_path_));
707 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
708 EXPECT_FALSE(base::PathExists(password_path_));
709}
710
Lutz Justen6f582982019-05-15 10:24:22 +0200711// ListAccounts() succeeds and contains the expected data.
712TEST_F(AccountManagerTest, ListAccountsSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200713 ignore_result(manager_->AddAccount(kUser, kManaged));
714 ignore_result(SetConfig());
715 ignore_result(manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
716 kDontUseLoginPassword));
717 SaveLoginPassword(kPassword);
718 ignore_result(manager_->AddAccount(kUser2, kUnmanaged));
719 // Note: kRememberPassword should be ignored here, see below.
720 ignore_result(manager_->AcquireTgt(kUser2, kPassword, kRememberPassword,
721 kUseLoginPassword));
Lutz Justen6f582982019-05-15 10:24:22 +0200722 EXPECT_TRUE(base::PathExists(krb5cc_path_));
723
724 // Set a fake tgt status.
725 constexpr int kRenewalSeconds = 10;
726 constexpr int kValiditySeconds = 90;
Lutz Justend925d712019-06-27 17:34:00 +0200727 krb5_->set_tgt_status(
728 Krb5Interface::TgtStatus(kValiditySeconds, kRenewalSeconds));
Lutz Justen6f582982019-05-15 10:24:22 +0200729
730 // Verify that ListAccounts returns the expected account.
Felipe Andrade89399f02019-11-11 15:52:14 +0100731 std::vector<Account> accounts = manager_->ListAccounts();
Lutz Justen04afd272019-06-14 16:31:26 +0200732 ASSERT_EQ(2u, accounts.size());
733
Lutz Justen6f582982019-05-15 10:24:22 +0200734 EXPECT_EQ(kUser, accounts[0].principal_name());
735 EXPECT_EQ(kKrb5Conf, accounts[0].krb5conf());
736 EXPECT_EQ(kRenewalSeconds, accounts[0].tgt_renewal_seconds());
737 EXPECT_EQ(kValiditySeconds, accounts[0].tgt_validity_seconds());
738 EXPECT_TRUE(accounts[0].is_managed());
Lutz Justenc5690502019-05-24 17:00:54 +0200739 EXPECT_TRUE(accounts[0].password_was_remembered());
Lutz Justen04afd272019-06-14 16:31:26 +0200740
741 EXPECT_EQ(kUser2, accounts[1].principal_name());
742 EXPECT_FALSE(accounts[1].password_was_remembered());
743 EXPECT_TRUE(accounts[1].use_login_password());
Lutz Justen6f582982019-05-15 10:24:22 +0200744}
745
746// ListAccounts() ignores failures in GetTgtStatus() and loading the config.
747TEST_F(AccountManagerTest, ListAccountsIgnoresFailures) {
Lutz Justen04afd272019-06-14 16:31:26 +0200748 ignore_result(AddAccount());
749 ignore_result(SetConfig());
750 ignore_result(AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200751 EXPECT_TRUE(base::PathExists(krb5cc_path_));
752
753 // Make reading the config fail.
754 EXPECT_TRUE(base::SetPosixFilePermissions(krb5conf_path_, 0));
755
756 // Make GetTgtStatus() fail.
757 krb5_->set_get_tgt_status_error(ERROR_UNKNOWN);
758
759 // ListAccounts() should still work, despite the errors.
Felipe Andrade89399f02019-11-11 15:52:14 +0100760 std::vector<Account> accounts = manager_->ListAccounts();
Lutz Justen6f582982019-05-15 10:24:22 +0200761 ASSERT_EQ(1u, accounts.size());
762 EXPECT_EQ(kUser, accounts[0].principal_name());
763
764 // The config should not be set since we made reading the file fail.
765 EXPECT_FALSE(accounts[0].has_krb5conf());
766
767 // tgt_*_seconds should not be set since we made GetTgtStatus() fail.
768 EXPECT_FALSE(accounts[0].has_tgt_renewal_seconds());
769 EXPECT_FALSE(accounts[0].has_tgt_validity_seconds());
770}
771
772// GetKerberosFiles returns empty KerberosFiles if there is no credential cache,
773// even if there is a config.
Felipe Andrade66aaf6b2020-03-24 13:05:57 +0100774TEST_F(AccountManagerTest, GetKerberosFilesSucceedsWithoutCC) {
Lutz Justen04afd272019-06-14 16:31:26 +0200775 ignore_result(AddAccount());
776 ignore_result(SetConfig());
Lutz Justen6f582982019-05-15 10:24:22 +0200777
778 KerberosFiles files;
779 EXPECT_EQ(ERROR_NONE, manager_->GetKerberosFiles(kUser, &files));
780 EXPECT_FALSE(files.has_krb5cc());
781 EXPECT_FALSE(files.has_krb5conf());
782}
783
784// GetKerberosFiles returns the expected KerberosFiles if there is a credential
785// cache.
Felipe Andrade66aaf6b2020-03-24 13:05:57 +0100786TEST_F(AccountManagerTest, GetKerberosFilesSucceedsWithCC) {
Lutz Justen04afd272019-06-14 16:31:26 +0200787 ignore_result(AddAccount());
788 ignore_result(SetConfig());
789 ignore_result(AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200790
791 KerberosFiles files;
792 EXPECT_EQ(ERROR_NONE, manager_->GetKerberosFiles(kUser, &files));
793 EXPECT_FALSE(files.krb5cc().empty());
794 EXPECT_EQ(kKrb5Conf, files.krb5conf());
795}
796
797// Most methods return ERROR_UNKNOWN_PRINCIPAL if called with such a principal.
798TEST_F(AccountManagerTest, MethodsReturnUnknownPrincipal) {
799 KerberosFiles files;
800 EXPECT_EQ(ERROR_UNKNOWN_PRINCIPAL_NAME, manager_->RemoveAccount(kUser));
Lutz Justen04afd272019-06-14 16:31:26 +0200801 EXPECT_EQ(ERROR_UNKNOWN_PRINCIPAL_NAME, SetConfig());
802 EXPECT_EQ(ERROR_UNKNOWN_PRINCIPAL_NAME, AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200803 EXPECT_EQ(ERROR_UNKNOWN_PRINCIPAL_NAME,
804 manager_->GetKerberosFiles(kUser, &files));
805}
806
807// Accounts can be saved to disk and loaded from disk.
808TEST_F(AccountManagerTest, SerializationSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200809 ignore_result(manager_->AddAccount(kUser, kManaged));
810 ignore_result(manager_->AcquireTgt(kUser, kPassword, kDontRememberPassword,
811 kUseLoginPassword));
812
813 ignore_result(manager_->AddAccount(kUser2, kUnmanaged));
814 ignore_result(manager_->AcquireTgt(kUser2, kPassword, kDontRememberPassword,
815 kDontUseLoginPassword));
Lutz Justen6f582982019-05-15 10:24:22 +0200816
817 EXPECT_EQ(ERROR_NONE, manager_->SaveAccounts());
Lutz Justen04afd272019-06-14 16:31:26 +0200818 AccountManager other_manager(
819 storage_dir_.GetPath(), kerberos_files_changed_,
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200820 kerberos_ticket_expiring_, std::make_unique<FakeKrb5Interface>(),
Lutz Justen2d857e12019-07-16 15:58:09 +0200821 std::make_unique<password_provider::FakePasswordProvider>(),
822 metrics_.get());
Lutz Justen6f582982019-05-15 10:24:22 +0200823 other_manager.LoadAccounts();
Felipe Andrade89399f02019-11-11 15:52:14 +0100824 std::vector<Account> accounts = other_manager.ListAccounts();
Lutz Justen6f582982019-05-15 10:24:22 +0200825 ASSERT_EQ(2u, accounts.size());
826
827 EXPECT_EQ(kUser, accounts[0].principal_name());
828 EXPECT_EQ(kUser2, accounts[1].principal_name());
829
830 EXPECT_TRUE(accounts[0].is_managed());
831 EXPECT_FALSE(accounts[1].is_managed());
832
Lutz Justen04afd272019-06-14 16:31:26 +0200833 EXPECT_TRUE(accounts[0].use_login_password());
834 EXPECT_FALSE(accounts[1].use_login_password());
835
Lutz Justen6f582982019-05-15 10:24:22 +0200836 // TODO(https://crbug.com/952239): Check additional Account properties.
837}
Lutz Justenb7ef5802019-05-14 14:03:20 +0200838
Lutz Justend925d712019-06-27 17:34:00 +0200839// The StartObservingTickets() method triggers KerberosTicketExpiring for
840// expired signals and starts observing valid tickets.
841TEST_F(AccountManagerTest, StartObservingTickets) {
842 krb5_->set_tgt_status(kValidTgt);
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200843 ignore_result(AddAccount());
844 ignore_result(SetConfig());
845 ignore_result(AcquireTgt());
846 EXPECT_EQ(0, kerberos_ticket_expiring_count_[kUser]);
Lutz Justend925d712019-06-27 17:34:00 +0200847 task_runner_->ClearPendingTasks();
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200848
Lutz Justend925d712019-06-27 17:34:00 +0200849 // Fake an expired ticket. Check that KerberosTicketExpiring is triggered, but
850 // no renewal task is scheduled.
851 krb5_->set_tgt_status(kExpiredTgt);
852 manager_->StartObservingTickets();
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200853 EXPECT_EQ(1, kerberos_ticket_expiring_count_[kUser]);
Lutz Justend925d712019-06-27 17:34:00 +0200854 EXPECT_EQ(0, task_runner_->GetPendingTaskCount());
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200855
Lutz Justend925d712019-06-27 17:34:00 +0200856 // Fake a valid ticket. Check that KerberosTicketExpiring is NOT triggered,
857 // but a renewal task is scheduled.
858 krb5_->set_tgt_status(kValidTgt);
859 EXPECT_EQ(0, task_runner_->GetPendingTaskCount());
860 manager_->StartObservingTickets();
861 EXPECT_EQ(1, task_runner_->GetPendingTaskCount());
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200862 EXPECT_EQ(1, kerberos_ticket_expiring_count_[kUser]);
Lutz Justend925d712019-06-27 17:34:00 +0200863 EXPECT_EQ(0, krb5_->renew_tgt_call_count());
864 task_runner_->FastForwardBy(task_runner_->NextPendingTaskDelay());
865 EXPECT_EQ(1, krb5_->renew_tgt_call_count());
866}
867
868// When a TGT is acquired successfully, automatic renewal is scheduled.
869TEST_F(AccountManagerTest, AcquireTgtSchedulesRenewalOnSuccess) {
870 ignore_result(AddAccount());
871
872 krb5_->set_tgt_status(kValidTgt);
873 EXPECT_EQ(0, task_runner_->GetPendingTaskCount());
874 EXPECT_EQ(ERROR_NONE, AcquireTgt());
875 EXPECT_EQ(1, task_runner_->GetPendingTaskCount());
876}
877
878// When a TGT fails to be acquired, no automatic renewal is scheduled.
879TEST_F(AccountManagerTest, AcquireTgtDoesNotScheduleRenewalOnFailure) {
880 ignore_result(AddAccount());
881
882 krb5_->set_tgt_status(kValidTgt);
883 krb5_->set_acquire_tgt_error(ERROR_UNKNOWN);
884 EXPECT_EQ(0, task_runner_->GetPendingTaskCount());
885 EXPECT_EQ(ERROR_UNKNOWN, AcquireTgt());
886 EXPECT_EQ(0, task_runner_->GetPendingTaskCount());
887}
888
889// A scheduled TGT renewal task calls |krb5_->RenewTgt()|.
890TEST_F(AccountManagerTest, AutoRenewalCallsRenewTgt) {
891 krb5_->set_tgt_status(kValidTgt);
892 ignore_result(AddAccount());
893 ignore_result(AcquireTgt());
894 int initial_acquire_tgt_call_count = krb5_->acquire_tgt_call_count();
895
896 // Set some return value for the RenewTgt() call and fast forward to scheduled
897 // renewal task.
898 const ErrorType expected_error = ERROR_UNKNOWN;
899 krb5_->set_renew_tgt_error(expected_error);
900 RunScheduledRenewalTask();
901
902 EXPECT_EQ(initial_acquire_tgt_call_count, krb5_->acquire_tgt_call_count());
903 EXPECT_EQ(expected_error, manager_->last_renew_tgt_error_for_testing());
904}
905
906// A scheduled TGT renewal task calls |krb5_->AcquireTgt()| using the login
907// password if the call to |krb5_->RenewTgt()| fails and the login password was
908// used for the initial AcquireTgt() call.
909TEST_F(AccountManagerTest, AutoRenewalUsesLoginPasswordIfRenewalFails) {
910 krb5_->set_tgt_status(kValidTgt);
911 ignore_result(AddAccount());
912
913 // Acquire TGT with login password.
914 SaveLoginPassword(kPassword);
915 krb5_->set_expected_password(kPassword);
916 EXPECT_EQ(ERROR_NONE,
917 manager_->AcquireTgt(kUser, std::string(), kDontRememberPassword,
918 kUseLoginPassword));
919 int initial_acquire_tgt_call_count = krb5_->acquire_tgt_call_count();
920
921 krb5_->set_renew_tgt_error(ERROR_UNKNOWN);
922 RunScheduledRenewalTask();
923
924 // The scheduled renewal task should have called AcquireTgt() with the login
925 // password and succeeded.
926 EXPECT_EQ(initial_acquire_tgt_call_count + 1,
927 krb5_->acquire_tgt_call_count());
928 EXPECT_EQ(ERROR_NONE, manager_->last_renew_tgt_error_for_testing());
929}
930
931// A scheduled TGT renewal task calls |krb5_->AcquireTgt()| using the remembered
932// password if the call to |krb5_->RenewTgt()| fails and the password was
933// remembered for the initial AcquireTgt() call.
934TEST_F(AccountManagerTest, AutoRenewalUsesRememberedPasswordIfRenewalFails) {
935 krb5_->set_tgt_status(kValidTgt);
936 ignore_result(AddAccount());
937
938 // Acquire TGT and remember password.
939 krb5_->set_expected_password(kPassword);
940 EXPECT_EQ(ERROR_NONE,
941 manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
942 kDontUseLoginPassword));
943 int initial_acquire_tgt_call_count = krb5_->acquire_tgt_call_count();
944
945 krb5_->set_renew_tgt_error(ERROR_UNKNOWN);
946 RunScheduledRenewalTask();
947
948 // The scheduled renewal task should have called AcquireTgt() with the
949 // remembered password and succeeded.
950 EXPECT_EQ(initial_acquire_tgt_call_count + 1,
951 krb5_->acquire_tgt_call_count());
952 EXPECT_EQ(ERROR_NONE, manager_->last_renew_tgt_error_for_testing());
953}
954
955// A scheduled TGT renewal task does not call |krb5_->AcquireTgt()| using the
956// remembered password if the call to |krb5_->RenewTgt()| succeeds and the
957// password was remembered for the initial AcquireTgt() call (similar for login
958// password, but we don't test that).
959TEST_F(AccountManagerTest, AutoRenewalDoesNotCallAcquireTgtIfRenewalSucceeds) {
960 krb5_->set_tgt_status(kValidTgt);
961 ignore_result(AddAccount());
962
963 // Acquire TGT and remember password.
964 krb5_->set_expected_password(kPassword);
965 EXPECT_EQ(ERROR_NONE,
966 manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
967 kDontUseLoginPassword));
968 int initial_acquire_tgt_call_count = krb5_->acquire_tgt_call_count();
969
970 krb5_->set_renew_tgt_error(ERROR_NONE);
971 RunScheduledRenewalTask();
972
973 // The scheduled renewal task should NOT have called AcquireTgt() again since
974 // |krb5_->RenewTgt()|.
975 EXPECT_EQ(initial_acquire_tgt_call_count, krb5_->acquire_tgt_call_count());
976 EXPECT_EQ(ERROR_NONE, manager_->last_renew_tgt_error_for_testing());
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200977}
978
Lutz Justen33601802019-07-03 22:40:57 +0200979// Verifies that all files written have the expected access permissions.
980// Unfortunately, file ownership can't be tested as the test won't run as
981// kerberosd user nor can it switch to it.
982TEST_F(AccountManagerTest, FilePermissions) {
983 constexpr int kFileMode_rw =
984 base::FILE_PERMISSION_READ_BY_USER | base::FILE_PERMISSION_WRITE_BY_USER;
985 constexpr int kFileMode_rw_r =
986 kFileMode_rw | base::FILE_PERMISSION_READ_BY_GROUP;
987 constexpr int kFileMode_rw_r__r =
988 kFileMode_rw_r | base::FILE_PERMISSION_READ_BY_OTHERS;
989 constexpr int kFileMode_rwxrwx =
990 base::FILE_PERMISSION_USER_MASK | base::FILE_PERMISSION_GROUP_MASK;
991
992 // Wrap the fake krb5 in a jail wrapper to get the file permissions of krb5cc
993 // right. Note that we can't use a Krb5JailWrapper for the whole test since
994 // that would break the counters in FakeKrb5Interface (they would be inc'ed in
995 // another process!).
996 manager_->WrapKrb5ForTesting();
997
998 // Can't set user in this test.
999 Krb5JailWrapper::DisableChangeUserForTesting(true);
1000
1001 EXPECT_EQ(ERROR_NONE, AddAccount());
1002 EXPECT_EQ(ERROR_NONE, SetConfig());
1003 EXPECT_EQ(ERROR_NONE,
1004 manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
1005 kDontUseLoginPassword));
1006
1007 int mode;
1008
1009 EXPECT_TRUE(GetPosixFilePermissions(accounts_path_, &mode));
1010 EXPECT_EQ(kFileMode_rw, mode);
1011
1012 EXPECT_TRUE(GetPosixFilePermissions(account_dir_, &mode));
1013 EXPECT_EQ(kFileMode_rwxrwx, mode);
1014
1015 EXPECT_TRUE(GetPosixFilePermissions(krb5cc_path_, &mode));
1016 EXPECT_EQ(kFileMode_rw_r, mode);
1017
1018 EXPECT_TRUE(GetPosixFilePermissions(krb5conf_path_, &mode));
1019 EXPECT_EQ(kFileMode_rw_r__r, mode);
1020
1021 EXPECT_TRUE(GetPosixFilePermissions(password_path_, &mode));
1022 EXPECT_EQ(kFileMode_rw, mode);
1023}
1024
Lutz Justen2d857e12019-07-16 15:58:09 +02001025// Tests that [Should]ReportDailyUsageStats is called as advertised.
1026TEST_F(AccountManagerTest, ReportDailyUsageStats) {
1027 // ShouldReportDailyUsageStats() should be called by GetKerberosFiles() even
1028 // if there is no account, and if that returns true, ReportDailyUsageStats()
1029 // should be called as well.
1030 EXPECT_CALL(*metrics_, ShouldReportDailyUsageStats()).WillOnce(Return(true));
1031 EXPECT_CALL(*metrics_, ReportDailyUsageStats(0, 0, 0, 0, 0));
1032 KerberosFiles files;
1033 EXPECT_EQ(ERROR_UNKNOWN_PRINCIPAL_NAME,
1034 manager_->GetKerberosFiles(kUser, &files));
1035 Mock::VerifyAndClearExpectations(metrics_.get());
1036
1037 AddAccount();
1038
1039 // ShouldReportDailyUsageStats() should be called by AcquireTgt(), but if that
1040 // returns false, ReportDailyUsageStats() should NOT be called.
1041 EXPECT_CALL(*metrics_, ShouldReportDailyUsageStats()).WillOnce(Return(false));
1042 EXPECT_CALL(*metrics_, ReportDailyUsageStats(_, _, _, _, _)).Times(0);
1043 AcquireTgt();
1044 Mock::VerifyAndClearExpectations(metrics_.get());
1045
1046 // ShouldReportDailyUsageStats() should be called by AcquireTgt(), and if that
1047 // returns true, ReportDailyUsageStats() should be called as well.
1048 EXPECT_CALL(*metrics_, ShouldReportDailyUsageStats()).WillOnce(Return(true));
1049 EXPECT_CALL(*metrics_, ReportDailyUsageStats(_, _, _, _, _));
1050 AcquireTgt();
1051 Mock::VerifyAndClearExpectations(metrics_.get());
1052}
1053
1054TEST_F(AccountManagerTest, AccountStats) {
1055 SaveLoginPassword(kPassword);
1056
1057 EXPECT_EQ(ERROR_NONE, manager_->AddAccount(kUser, kManaged));
1058 EXPECT_EQ(ERROR_NONE, manager_->AddAccount(kUser2, kManaged));
1059 EXPECT_EQ(ERROR_NONE, manager_->AddAccount(kUser3, kUnmanaged));
1060
1061 // Set metrics up so that the stats are reported on the last call.
1062 EXPECT_CALL(*metrics_, ShouldReportDailyUsageStats())
1063 .WillOnce(Return(false))
1064 .WillOnce(Return(false))
1065 .WillOnce(Return(true));
1066
1067 // 3 accounts total, 2 managed, 1 unmanaged, 1 remembering the password, 1
1068 // using the login password.
1069 EXPECT_CALL(*metrics_, ReportDailyUsageStats(3, 2, 1, 1, 1));
1070
1071 EXPECT_EQ(ERROR_NONE,
1072 manager_->AcquireTgt(kUser, kPassword, kDontRememberPassword,
1073 kDontUseLoginPassword));
1074 EXPECT_EQ(ERROR_NONE,
1075 manager_->AcquireTgt(kUser2, kPassword, kRememberPassword,
1076 kDontUseLoginPassword));
1077 EXPECT_EQ(ERROR_NONE,
1078 manager_->AcquireTgt(kUser3, kEmptyPassword, kDontRememberPassword,
1079 kUseLoginPassword));
1080}
1081
Lutz Justenb7ef5802019-05-14 14:03:20 +02001082} // namespace kerberos