blob: a33f20e5cd70d267974a0b592a28506fd5b5d2c2 [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>
Lutz Justene39cbd42019-05-14 14:52:24 +020012#include <base/files/file_path.h>
Lutz Justenb7ef5802019-05-14 14:03:20 +020013#include <base/files/file_util.h>
14#include <base/files/scoped_temp_dir.h>
15#include <gmock/gmock.h>
16#include <gtest/gtest.h>
Lutz Justen04afd272019-06-14 16:31:26 +020017#include <libpasswordprovider/fake_password_provider.h>
18#include <libpasswordprovider/password_provider_test_utils.h>
Lutz Justenb7ef5802019-05-14 14:03:20 +020019
Lutz Justene39cbd42019-05-14 14:52:24 +020020#include "kerberos/fake_krb5_interface.h"
21
Lutz Justenb7ef5802019-05-14 14:03:20 +020022namespace {
Lutz Justen6f582982019-05-15 10:24:22 +020023
Lutz Justenb7ef5802019-05-14 14:03:20 +020024constexpr char kUser[] = "user@REALM.COM";
Lutz Justen6f582982019-05-15 10:24:22 +020025constexpr char kUser2[] = "user2@REALM2.COM";
26constexpr char kPassword[] = "i<3k3R8e5Oz";
Lutz Justen04afd272019-06-14 16:31:26 +020027constexpr char kPassword2[] = "ih4zf00d";
Lutz Justen6f582982019-05-15 10:24:22 +020028constexpr char kKrb5Conf[] = R"(
29 [libdefaults]
30 default_realm = REALM.COM)";
31
Lutz Justen04afd272019-06-14 16:31:26 +020032// Convenience defines to make code more readable
33constexpr bool kManaged = true;
34constexpr bool kUnmanaged = false;
35
36constexpr bool kRememberPassword = true;
37constexpr bool kDontRememberPassword = false;
38
39constexpr bool kUseLoginPassword = true;
40constexpr bool kDontUseLoginPassword = false;
41
42constexpr char kEmptyPassword[] = "";
43
Lutz Justen6f582982019-05-15 10:24:22 +020044} // namespace
Lutz Justenb7ef5802019-05-14 14:03:20 +020045
46namespace kerberos {
47
48class AccountManagerTest : public ::testing::Test {
49 public:
Lutz Justen6f582982019-05-15 10:24:22 +020050 AccountManagerTest()
51 : kerberos_files_changed_(
52 base::BindRepeating(&AccountManagerTest::OnKerberosFilesChanged,
Lutz Justen8eeb4a22019-06-19 17:00:32 +020053 base::Unretained(this))),
54 kerberos_ticket_expiring_(
55 base::BindRepeating(&AccountManagerTest::OnKerberosTicketExpiring,
Lutz Justen6f582982019-05-15 10:24:22 +020056 base::Unretained(this))) {}
Lutz Justenb7ef5802019-05-14 14:03:20 +020057 ~AccountManagerTest() override = default;
58
59 void SetUp() override {
60 ::testing::Test::SetUp();
61
62 // Create temp directory for files written during tests.
63 CHECK(storage_dir_.CreateUniqueTempDir());
Lutz Justen6f582982019-05-15 10:24:22 +020064 accounts_path_ = storage_dir_.GetPath().Append("accounts");
Lutz Justenc5690502019-05-24 17:00:54 +020065 const base::FilePath account_dir = storage_dir_.GetPath().Append(
66 AccountManager::GetSafeFilenameForTesting(kUser));
67 krb5cc_path_ = account_dir.Append("krb5cc");
68 krb5conf_path_ = account_dir.Append("krb5.conf");
69 password_path_ = account_dir.Append("password");
Lutz Justenb7ef5802019-05-14 14:03:20 +020070
Lutz Justen6f582982019-05-15 10:24:22 +020071 // Create the manager with a fake krb5 interface.
72 auto krb5 = std::make_unique<FakeKrb5Interface>();
Lutz Justen04afd272019-06-14 16:31:26 +020073 auto password_provider =
74 std::make_unique<password_provider::FakePasswordProvider>();
Lutz Justen6f582982019-05-15 10:24:22 +020075 krb5_ = krb5.get();
Lutz Justen04afd272019-06-14 16:31:26 +020076 password_provider_ = password_provider.get();
Lutz Justenb7ef5802019-05-14 14:03:20 +020077 manager_ = std::make_unique<AccountManager>(
Lutz Justen8eeb4a22019-06-19 17:00:32 +020078 storage_dir_.GetPath(), kerberos_files_changed_,
79 kerberos_ticket_expiring_, std::move(krb5),
Lutz Justen04afd272019-06-14 16:31:26 +020080 std::move(password_provider));
Lutz Justenb7ef5802019-05-14 14:03:20 +020081 }
82
Lutz Justen82d07ce2019-05-16 10:46:14 +020083 void TearDown() override {
84 // Make sure the file stored on disk contains the same accounts as the
85 // manager instance. This catches cases where AccountManager forgets to save
86 // accounts on some change.
87 if (base::PathExists(accounts_path_)) {
88 std::vector<Account> accounts;
89 EXPECT_EQ(ERROR_NONE, manager_->ListAccounts(&accounts));
90
Lutz Justen04afd272019-06-14 16:31:26 +020091 AccountManager other_manager(
92 storage_dir_.GetPath(), kerberos_files_changed_,
Lutz Justen8eeb4a22019-06-19 17:00:32 +020093 kerberos_ticket_expiring_, std::make_unique<FakeKrb5Interface>(),
Lutz Justen04afd272019-06-14 16:31:26 +020094 std::make_unique<password_provider::FakePasswordProvider>());
Lutz Justen82d07ce2019-05-16 10:46:14 +020095 other_manager.LoadAccounts();
96 std::vector<Account> other_accounts;
97 EXPECT_EQ(ERROR_NONE, other_manager.ListAccounts(&other_accounts));
98
99 ASSERT_NO_FATAL_FAILURE(ExpectAccountsEqual(accounts, other_accounts));
100 }
101
102 ::testing::Test::TearDown();
103 }
104
Lutz Justen04afd272019-06-14 16:31:26 +0200105 // Add account with default settings.
106 ErrorType AddAccount() { return manager_->AddAccount(kUser, kUnmanaged); }
107
108 // Sets some default Kerberos configuration.
109 ErrorType SetConfig() { return manager_->SetConfig(kUser, kKrb5Conf); }
110
111 // Acquire Kerberos ticket with default credentials and settings.
112 ErrorType AcquireTgt() {
113 return manager_->AcquireTgt(kUser, kPassword, kDontRememberPassword,
114 kDontUseLoginPassword);
115 }
116
117 void SaveLoginPassword(const char* password) {
118 auto password_ptr = password_provider::test::CreatePassword(password);
119 password_provider_->SavePassword(*password_ptr);
120 }
121
Lutz Justenb7ef5802019-05-14 14:03:20 +0200122 protected:
123 void OnKerberosFilesChanged(const std::string& principal_name) {
124 kerberos_files_changed_count_[principal_name]++;
125 }
126
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200127 void OnKerberosTicketExpiring(const std::string& principal_name) {
128 kerberos_ticket_expiring_count_[principal_name]++;
129 }
130
Lutz Justen82d07ce2019-05-16 10:46:14 +0200131 void ExpectAccountsEqual(const std::vector<Account>& account_list_1,
132 const std::vector<Account>& account_list_2) {
133 ASSERT_EQ(account_list_1.size(), account_list_2.size());
134 for (size_t n = 0; n < account_list_1.size(); ++n) {
135 const Account& account1 = account_list_1[n];
136 const Account& account2 = account_list_2[n];
137
138 EXPECT_EQ(account1.principal_name(), account2.principal_name());
139 EXPECT_EQ(account1.is_managed(), account2.is_managed());
Lutz Justen04afd272019-06-14 16:31:26 +0200140 EXPECT_EQ(account1.use_login_password(), account2.use_login_password());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200141 // TODO(https://crbug.com/952239): Check additional properties.
142 }
143 }
144
Lutz Justenb7ef5802019-05-14 14:03:20 +0200145 std::unique_ptr<AccountManager> manager_;
Lutz Justen6f582982019-05-15 10:24:22 +0200146
Lutz Justen04afd272019-06-14 16:31:26 +0200147 // Fake Kerberos interface used by |manager_|. Not owned.
Lutz Justen6f582982019-05-15 10:24:22 +0200148 FakeKrb5Interface* krb5_;
149
Lutz Justen04afd272019-06-14 16:31:26 +0200150 // Fake password provider to get the login password. Not owned.
151 password_provider::FakePasswordProvider* password_provider_;
152
Lutz Justen6f582982019-05-15 10:24:22 +0200153 // Paths of files stored by |manager_|.
Lutz Justenb7ef5802019-05-14 14:03:20 +0200154 base::ScopedTempDir storage_dir_;
Lutz Justen6f582982019-05-15 10:24:22 +0200155 base::FilePath accounts_path_;
156 base::FilePath krb5conf_path_;
157 base::FilePath krb5cc_path_;
Lutz Justenc5690502019-05-24 17:00:54 +0200158 base::FilePath password_path_;
Lutz Justen6f582982019-05-15 10:24:22 +0200159
160 AccountManager::KerberosFilesChangedCallback kerberos_files_changed_;
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200161 AccountManager::KerberosTicketExpiringCallback kerberos_ticket_expiring_;
162
Lutz Justenb7ef5802019-05-14 14:03:20 +0200163 std::map<std::string, int> kerberos_files_changed_count_;
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200164 std::map<std::string, int> kerberos_ticket_expiring_count_;
Lutz Justenb7ef5802019-05-14 14:03:20 +0200165
166 private:
167 DISALLOW_COPY_AND_ASSIGN(AccountManagerTest);
168};
169
Lutz Justen6f582982019-05-15 10:24:22 +0200170// Adding an account succeeds and serializes the file on disk.
Lutz Justenb7ef5802019-05-14 14:03:20 +0200171TEST_F(AccountManagerTest, AddAccountSuccess) {
Lutz Justen6f582982019-05-15 10:24:22 +0200172 EXPECT_FALSE(base::PathExists(accounts_path_));
Lutz Justen04afd272019-06-14 16:31:26 +0200173 EXPECT_EQ(ERROR_NONE, AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200174 EXPECT_TRUE(base::PathExists(accounts_path_));
Lutz Justenb7ef5802019-05-14 14:03:20 +0200175}
176
Lutz Justen6f582982019-05-15 10:24:22 +0200177// AddAccount() fails if the same account is added twice.
Lutz Justenb7ef5802019-05-14 14:03:20 +0200178TEST_F(AccountManagerTest, AddDuplicateAccountFail) {
Lutz Justen04afd272019-06-14 16:31:26 +0200179 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200180
181 EXPECT_TRUE(base::DeleteFile(accounts_path_, false /* recursive */));
Lutz Justen04afd272019-06-14 16:31:26 +0200182 EXPECT_EQ(ERROR_DUPLICATE_PRINCIPAL_NAME, AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200183 EXPECT_FALSE(base::PathExists(accounts_path_));
Lutz Justenb7ef5802019-05-14 14:03:20 +0200184}
185
Lutz Justen6f582982019-05-15 10:24:22 +0200186// Adding a managed account overwrites an existing unmanaged account.
187TEST_F(AccountManagerTest, ManagedOverridesUnmanaged) {
Lutz Justen04afd272019-06-14 16:31:26 +0200188 ignore_result(manager_->AddAccount(kUser, kUnmanaged));
Lutz Justen6f582982019-05-15 10:24:22 +0200189
Lutz Justen04afd272019-06-14 16:31:26 +0200190 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200191 EXPECT_TRUE(base::PathExists(krb5cc_path_));
192
193 // Overwriting with a managed account should wipe existing files and make the
194 // account managed.
Lutz Justen6f582982019-05-15 10:24:22 +0200195 EXPECT_EQ(ERROR_DUPLICATE_PRINCIPAL_NAME,
Lutz Justen04afd272019-06-14 16:31:26 +0200196 manager_->AddAccount(kUser, kManaged));
Lutz Justen82d07ce2019-05-16 10:46:14 +0200197 EXPECT_FALSE(base::PathExists(krb5cc_path_));
198
Lutz Justen6f582982019-05-15 10:24:22 +0200199 std::vector<Account> accounts;
200 EXPECT_EQ(ERROR_NONE, manager_->ListAccounts(&accounts));
201 ASSERT_EQ(1u, accounts.size());
202 EXPECT_TRUE(accounts[0].is_managed());
203}
204
205// Adding an unmanaged account does not overwrite an existing managed account.
206TEST_F(AccountManagerTest, UnmanagedDoesNotOverrideManaged) {
Lutz Justen04afd272019-06-14 16:31:26 +0200207 ignore_result(manager_->AddAccount(kUser, kManaged));
Lutz Justen6f582982019-05-15 10:24:22 +0200208
209 EXPECT_EQ(ERROR_DUPLICATE_PRINCIPAL_NAME,
Lutz Justen04afd272019-06-14 16:31:26 +0200210 manager_->AddAccount(kUser, kUnmanaged));
Lutz Justen6f582982019-05-15 10:24:22 +0200211 std::vector<Account> accounts;
212 EXPECT_EQ(ERROR_NONE, manager_->ListAccounts(&accounts));
213 ASSERT_EQ(1u, accounts.size());
214 EXPECT_TRUE(accounts[0].is_managed());
215}
216
217// RemoveAccount() succeeds if the account exists and serializes the file on
218// disk.
Lutz Justenb7ef5802019-05-14 14:03:20 +0200219TEST_F(AccountManagerTest, RemoveAccountSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200220 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200221
222 EXPECT_TRUE(base::DeleteFile(accounts_path_, false /* recursive */));
Lutz Justenb7ef5802019-05-14 14:03:20 +0200223 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
Lutz Justen6f582982019-05-15 10:24:22 +0200224 EXPECT_TRUE(base::PathExists(accounts_path_));
Lutz Justenb7ef5802019-05-14 14:03:20 +0200225}
226
Lutz Justen6f582982019-05-15 10:24:22 +0200227// RemoveAccount() fails if the account does not exist.
Lutz Justenb7ef5802019-05-14 14:03:20 +0200228TEST_F(AccountManagerTest, RemoveUnknownAccountFail) {
229 EXPECT_EQ(ERROR_UNKNOWN_PRINCIPAL_NAME, manager_->RemoveAccount(kUser));
Lutz Justen6f582982019-05-15 10:24:22 +0200230 EXPECT_FALSE(base::PathExists(accounts_path_));
231}
232
233// RemoveAccount() does not trigger KerberosFilesChanged if the credential cache
234// does not exists.
235TEST_F(AccountManagerTest, RemoveAccountTriggersKFCIfCCExists) {
Lutz Justen04afd272019-06-14 16:31:26 +0200236 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200237
238 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
239 EXPECT_EQ(0, kerberos_files_changed_count_[kUser]);
240}
241
242// RemoveAccount() triggers KerberosFilesChanged if the credential cache exists.
243TEST_F(AccountManagerTest, RemoveAccountDoesNotTriggerKFCIfCCDoesNotExist) {
Lutz Justen04afd272019-06-14 16:31:26 +0200244 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200245
Lutz Justen04afd272019-06-14 16:31:26 +0200246 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200247 EXPECT_EQ(1, kerberos_files_changed_count_[kUser]);
248 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
249 EXPECT_EQ(2, kerberos_files_changed_count_[kUser]);
Lutz Justenb7ef5802019-05-14 14:03:20 +0200250}
251
252// Repeatedly calling AddAccount() and RemoveAccount() succeeds.
253TEST_F(AccountManagerTest, RepeatedAddRemoveSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200254 ignore_result(AddAccount());
Lutz Justenb7ef5802019-05-14 14:03:20 +0200255 ignore_result(manager_->RemoveAccount(kUser));
Lutz Justen6f582982019-05-15 10:24:22 +0200256
Lutz Justen04afd272019-06-14 16:31:26 +0200257 EXPECT_EQ(ERROR_NONE, AddAccount());
Lutz Justenb7ef5802019-05-14 14:03:20 +0200258 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
259}
260
Lutz Justen2d420872019-06-25 14:17:21 +0200261// ClearAccounts(CLEAR_ALL) clears all accounts.
262TEST_F(AccountManagerTest, ClearAccountsSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200263 ignore_result(manager_->AddAccount(kUser, kUnmanaged));
264 ignore_result(manager_->AddAccount(kUser2, kManaged));
Lutz Justen82d07ce2019-05-16 10:46:14 +0200265
Lutz Justen2d420872019-06-25 14:17:21 +0200266 EXPECT_EQ(ERROR_NONE, manager_->ClearAccounts(CLEAR_ALL));
Lutz Justen82d07ce2019-05-16 10:46:14 +0200267 std::vector<Account> accounts;
268 EXPECT_EQ(ERROR_NONE, manager_->ListAccounts(&accounts));
269 EXPECT_EQ(0u, accounts.size());
270}
271
Lutz Justen2d420872019-06-25 14:17:21 +0200272// ClearAccounts(CLEAR_ALL) wipes Kerberos configuration and credential cache.
273TEST_F(AccountManagerTest, ClearAccountsRemovesKerberosFiles) {
Lutz Justen04afd272019-06-14 16:31:26 +0200274 ignore_result(AddAccount());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200275
Lutz Justen04afd272019-06-14 16:31:26 +0200276 EXPECT_EQ(ERROR_NONE, SetConfig());
277 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200278 EXPECT_TRUE(base::PathExists(krb5conf_path_));
279 EXPECT_TRUE(base::PathExists(krb5cc_path_));
Lutz Justen2d420872019-06-25 14:17:21 +0200280 EXPECT_EQ(ERROR_NONE, manager_->ClearAccounts(CLEAR_ALL));
Lutz Justen82d07ce2019-05-16 10:46:14 +0200281 EXPECT_FALSE(base::PathExists(krb5conf_path_));
282 EXPECT_FALSE(base::PathExists(krb5cc_path_));
283}
284
Lutz Justen2d420872019-06-25 14:17:21 +0200285// ClearAccounts(CLEAR_ALL) triggers KerberosFilesChanged if the credential
286// cache exists.
287TEST_F(AccountManagerTest, ClearAccountsTriggersKFCIfCCExists) {
Lutz Justen04afd272019-06-14 16:31:26 +0200288 ignore_result(AddAccount());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200289
Lutz Justen04afd272019-06-14 16:31:26 +0200290 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200291 EXPECT_EQ(1, kerberos_files_changed_count_[kUser]);
Lutz Justen2d420872019-06-25 14:17:21 +0200292 EXPECT_EQ(ERROR_NONE, manager_->ClearAccounts(CLEAR_ALL));
Lutz Justen82d07ce2019-05-16 10:46:14 +0200293 EXPECT_EQ(2, kerberos_files_changed_count_[kUser]);
294}
295
Lutz Justen2d420872019-06-25 14:17:21 +0200296// ClearAccounts(CLEAR_ALL) does not trigger KerberosFilesChanged if the
297// credential cache does not exist.
298TEST_F(AccountManagerTest, ClearAccountsDoesNotTriggerKFCIfDoesNotCCExist) {
Lutz Justen04afd272019-06-14 16:31:26 +0200299 ignore_result(AddAccount());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200300
Lutz Justen2d420872019-06-25 14:17:21 +0200301 EXPECT_EQ(ERROR_NONE, manager_->ClearAccounts(CLEAR_ALL));
Lutz Justen82d07ce2019-05-16 10:46:14 +0200302 EXPECT_EQ(0, kerberos_files_changed_count_[kUser]);
303}
304
Lutz Justen2d420872019-06-25 14:17:21 +0200305// ClearAccounts(CLEAR_ONLY_UNMANAGED_ACCOUNTS) clears only unmanaged accounts.
306TEST_F(AccountManagerTest, ClearUnmanagedAccountsSuccess) {
307 ignore_result(manager_->AddAccount(kUser, kUnmanaged));
308 ignore_result(manager_->AddAccount(kUser2, kManaged));
309
310 EXPECT_EQ(ERROR_NONE, manager_->ClearAccounts(CLEAR_ONLY_UNMANAGED_ACCOUNTS));
311 std::vector<Account> accounts;
312 EXPECT_EQ(ERROR_NONE, manager_->ListAccounts(&accounts));
313 ASSERT_EQ(1u, accounts.size());
314 EXPECT_EQ(kUser2, accounts[0].principal_name());
315}
316
317// ClearAccounts(CLEAR_ONLY_UNMANAGED_REMEMBERED_PASSWORDS) clears only
318// passwords of unmanaged accounts.
319TEST_F(AccountManagerTest, ClearUnmanagedPasswordsSuccess) {
320 // kUser is unmanaged, kUser2 is managed.
321 ignore_result(manager_->AddAccount(kUser, kUnmanaged));
322 ignore_result(manager_->AddAccount(kUser2, kManaged));
323 ignore_result(manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
324 kDontUseLoginPassword));
325 ignore_result(manager_->AcquireTgt(kUser2, kPassword, kRememberPassword,
326 kDontUseLoginPassword));
327
328 base::FilePath password_path_2 =
329 storage_dir_.GetPath()
330 .Append(AccountManager::GetSafeFilenameForTesting(kUser2))
331 .Append("password");
332 EXPECT_TRUE(base::PathExists(password_path_));
333 EXPECT_TRUE(base::PathExists(password_path_2));
334
335 EXPECT_EQ(ERROR_NONE,
336 manager_->ClearAccounts(CLEAR_ONLY_UNMANAGED_REMEMBERED_PASSWORDS));
337 std::vector<Account> accounts;
338 EXPECT_EQ(ERROR_NONE, manager_->ListAccounts(&accounts));
339 ASSERT_EQ(2u, accounts.size());
340 EXPECT_FALSE(base::PathExists(password_path_));
341 EXPECT_TRUE(base::PathExists(password_path_2));
342}
343
Lutz Justen6f582982019-05-15 10:24:22 +0200344// SetConfig() succeeds and writes the config to |krb5conf_path_|.
345TEST_F(AccountManagerTest, SetConfigSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200346 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200347
Lutz Justen04afd272019-06-14 16:31:26 +0200348 EXPECT_EQ(ERROR_NONE, SetConfig());
Lutz Justen6f582982019-05-15 10:24:22 +0200349 std::string krb5_conf;
350 EXPECT_TRUE(base::ReadFileToString(krb5conf_path_, &krb5_conf));
351 EXPECT_EQ(krb5_conf, kKrb5Conf);
352}
353
354// SetConfig() triggers KerberosFilesChanged if the credential cache exists.
355TEST_F(AccountManagerTest, SetConfigTriggersKFCIfCCExists) {
Lutz Justen04afd272019-06-14 16:31:26 +0200356 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200357
Lutz Justen04afd272019-06-14 16:31:26 +0200358 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200359 EXPECT_EQ(1, kerberos_files_changed_count_[kUser]);
Lutz Justen04afd272019-06-14 16:31:26 +0200360 EXPECT_EQ(ERROR_NONE, SetConfig());
Lutz Justen6f582982019-05-15 10:24:22 +0200361 EXPECT_EQ(2, kerberos_files_changed_count_[kUser]);
362}
363
Lutz Justen82d07ce2019-05-16 10:46:14 +0200364// SetConfig() does not trigger KerberosFilesChanged if the credential cache
365// does not exist.
Lutz Justen6f582982019-05-15 10:24:22 +0200366TEST_F(AccountManagerTest, SetConfigDoesNotTriggerKFCIfDoesNotCCExist) {
Lutz Justen04afd272019-06-14 16:31:26 +0200367 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200368
Lutz Justen04afd272019-06-14 16:31:26 +0200369 EXPECT_EQ(ERROR_NONE, SetConfig());
Lutz Justen6f582982019-05-15 10:24:22 +0200370 EXPECT_EQ(0, kerberos_files_changed_count_[kUser]);
371}
372
373// RemoveAccount() removes the config file.
374TEST_F(AccountManagerTest, RemoveAccountRemovesConfig) {
Lutz Justen04afd272019-06-14 16:31:26 +0200375 ignore_result(AddAccount());
376 ignore_result(SetConfig());
Lutz Justen6f582982019-05-15 10:24:22 +0200377
378 EXPECT_TRUE(base::PathExists(krb5conf_path_));
379 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
380 EXPECT_FALSE(base::PathExists(krb5conf_path_));
381}
382
383// AcquireTgt() succeeds and writes a credential cache file.
384TEST_F(AccountManagerTest, AcquireTgtSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200385 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200386
Lutz Justen04afd272019-06-14 16:31:26 +0200387 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200388 EXPECT_TRUE(base::PathExists(krb5cc_path_));
389}
390
391// AcquireTgt() triggers KerberosFilesChanged on success.
392TEST_F(AccountManagerTest, AcquireTgtTriggersKFCOnSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200393 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200394
395 EXPECT_EQ(0, kerberos_files_changed_count_[kUser]);
Lutz Justen04afd272019-06-14 16:31:26 +0200396 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200397 EXPECT_EQ(1, kerberos_files_changed_count_[kUser]);
398}
399
400// AcquireTgt() does not trigger KerberosFilesChanged on failure.
401TEST_F(AccountManagerTest, AcquireTgtDoesNotTriggerKFCOnFailure) {
Lutz Justen04afd272019-06-14 16:31:26 +0200402 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200403
404 krb5_->set_acquire_tgt_error(ERROR_UNKNOWN);
Lutz Justen04afd272019-06-14 16:31:26 +0200405 EXPECT_EQ(ERROR_UNKNOWN, AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200406 EXPECT_EQ(0, kerberos_files_changed_count_[kUser]);
407}
408
Lutz Justenc5690502019-05-24 17:00:54 +0200409// AcquireTgt() saves password to disk if |remember_password| is true and
410// removes the file again if |remember_password| is false.
411TEST_F(AccountManagerTest, AcquireTgtRemembersPasswordsIfWanted) {
Lutz Justen04afd272019-06-14 16:31:26 +0200412 ignore_result(AddAccount());
Lutz Justenc5690502019-05-24 17:00:54 +0200413
414 EXPECT_FALSE(base::PathExists(password_path_));
Lutz Justen04afd272019-06-14 16:31:26 +0200415 EXPECT_EQ(ERROR_NONE,
416 manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
417 kDontUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200418 EXPECT_TRUE(base::PathExists(password_path_));
419
Lutz Justen04afd272019-06-14 16:31:26 +0200420 EXPECT_EQ(ERROR_NONE,
421 manager_->AcquireTgt(kUser, kPassword, kDontRememberPassword,
422 kDontUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200423 EXPECT_FALSE(base::PathExists(password_path_));
424}
425
426// AcquireTgt() uses saved password if none is given, no matter if it should be
427// remembered again or not.
428TEST_F(AccountManagerTest, AcquireTgtLoadsRememberedPassword) {
Lutz Justen04afd272019-06-14 16:31:26 +0200429 ignore_result(AddAccount());
430 ignore_result(manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
431 kDontUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200432
433 // This should load stored password and keep it.
434 EXPECT_EQ(ERROR_NONE,
Lutz Justen04afd272019-06-14 16:31:26 +0200435 manager_->AcquireTgt(kUser, kEmptyPassword, kRememberPassword,
436 kDontUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200437 EXPECT_TRUE(base::PathExists(password_path_));
438
439 // This should load stored password, but erase it afterwards.
440 EXPECT_EQ(ERROR_NONE,
Lutz Justen04afd272019-06-14 16:31:26 +0200441 manager_->AcquireTgt(kUser, kEmptyPassword, kDontRememberPassword,
442 kDontUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200443 EXPECT_FALSE(base::PathExists(password_path_));
444
445 // Check that the fake krb5 interface returns an error for a missing password.
446 // This verifies that the above AcquireTgt() call actually loaded the
447 // password from disk.
448 EXPECT_EQ(ERROR_BAD_PASSWORD,
Lutz Justen04afd272019-06-14 16:31:26 +0200449 manager_->AcquireTgt(kUser, kEmptyPassword, kDontRememberPassword,
450 kDontUseLoginPassword));
451}
452
453// AcquireTgt() uses the login password if saved.
454TEST_F(AccountManagerTest, AcquireTgtUsesLoginPassword) {
455 ignore_result(AddAccount());
456
457 // Shouldn't explode if the login password not set yet.
458 EXPECT_EQ(ERROR_BAD_PASSWORD,
459 manager_->AcquireTgt(kUser, kEmptyPassword, kDontRememberPassword,
460 kUseLoginPassword));
461
462 SaveLoginPassword(kPassword);
463 krb5_->set_expected_password(kPassword);
464
465 // Uses the login password.
466 EXPECT_EQ(ERROR_NONE,
467 manager_->AcquireTgt(kUser, kEmptyPassword, kDontRememberPassword,
468 kUseLoginPassword));
469
470 // Check if auth fails without kUseLoginPassword.
471 EXPECT_EQ(ERROR_BAD_PASSWORD,
472 manager_->AcquireTgt(kUser, kEmptyPassword, kDontRememberPassword,
473 kDontUseLoginPassword));
474}
475
476// AcquireTgt() wipes a saved password if the login password is used.
477TEST_F(AccountManagerTest, AcquireTgtWipesStoredPasswordOnUsesLoginPassword) {
478 ignore_result(AddAccount());
479 ignore_result(manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
480 kDontUseLoginPassword));
481 EXPECT_TRUE(base::PathExists(password_path_));
482
483 SaveLoginPassword(kPassword);
484
485 // Note: kRememberPassword gets ignored if kUseLoginPassword is passed.
486 EXPECT_EQ(ERROR_NONE,
487 manager_->AcquireTgt(kUser, kEmptyPassword, kRememberPassword,
488 kUseLoginPassword));
489 EXPECT_FALSE(base::PathExists(password_path_));
490}
491
492// AcquireTgt() ignores the passed password if the login password is used.
493TEST_F(AccountManagerTest, AcquireTgtIgnoresPassedPasswordOnUsesLoginPassword) {
494 ignore_result(AddAccount());
495
496 SaveLoginPassword(kPassword);
497 krb5_->set_expected_password(kPassword);
498
499 // Auth works despite passed kPassword2 != expected kPassword because the
500 // login kPassword is used.
501 EXPECT_EQ(ERROR_NONE,
502 manager_->AcquireTgt(kUser, kPassword2, kDontRememberPassword,
503 kUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200504}
505
Lutz Justen6f582982019-05-15 10:24:22 +0200506// RemoveAccount() removes the credential cache file.
507TEST_F(AccountManagerTest, RemoveAccountRemovesCC) {
Lutz Justen04afd272019-06-14 16:31:26 +0200508 ignore_result(AddAccount());
509 ignore_result(AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200510
511 EXPECT_TRUE(base::PathExists(krb5cc_path_));
512 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
513 EXPECT_FALSE(base::PathExists(krb5cc_path_));
514}
515
Lutz Justenc5690502019-05-24 17:00:54 +0200516// RemoveAccount() removes saved passwords.
517TEST_F(AccountManagerTest, RemoveAccountRemovesPassword) {
Lutz Justen04afd272019-06-14 16:31:26 +0200518 ignore_result(AddAccount());
519 ignore_result(manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
520 kDontUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200521
522 EXPECT_TRUE(base::PathExists(password_path_));
523 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
524 EXPECT_FALSE(base::PathExists(password_path_));
525}
526
Lutz Justen6f582982019-05-15 10:24:22 +0200527// ListAccounts() succeeds and contains the expected data.
528TEST_F(AccountManagerTest, ListAccountsSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200529 ignore_result(manager_->AddAccount(kUser, kManaged));
530 ignore_result(SetConfig());
531 ignore_result(manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
532 kDontUseLoginPassword));
533 SaveLoginPassword(kPassword);
534 ignore_result(manager_->AddAccount(kUser2, kUnmanaged));
535 // Note: kRememberPassword should be ignored here, see below.
536 ignore_result(manager_->AcquireTgt(kUser2, kPassword, kRememberPassword,
537 kUseLoginPassword));
Lutz Justen6f582982019-05-15 10:24:22 +0200538 EXPECT_TRUE(base::PathExists(krb5cc_path_));
539
540 // Set a fake tgt status.
541 constexpr int kRenewalSeconds = 10;
542 constexpr int kValiditySeconds = 90;
543 Krb5Interface::TgtStatus status;
544 status.renewal_seconds = kRenewalSeconds;
545 status.validity_seconds = kValiditySeconds;
546 krb5_->set_tgt_status(std::move(status));
547
548 // Verify that ListAccounts returns the expected account.
549 std::vector<Account> accounts;
550 EXPECT_EQ(ERROR_NONE, manager_->ListAccounts(&accounts));
Lutz Justen04afd272019-06-14 16:31:26 +0200551 ASSERT_EQ(2u, accounts.size());
552
Lutz Justen6f582982019-05-15 10:24:22 +0200553 EXPECT_EQ(kUser, accounts[0].principal_name());
554 EXPECT_EQ(kKrb5Conf, accounts[0].krb5conf());
555 EXPECT_EQ(kRenewalSeconds, accounts[0].tgt_renewal_seconds());
556 EXPECT_EQ(kValiditySeconds, accounts[0].tgt_validity_seconds());
557 EXPECT_TRUE(accounts[0].is_managed());
Lutz Justenc5690502019-05-24 17:00:54 +0200558 EXPECT_TRUE(accounts[0].password_was_remembered());
Lutz Justen04afd272019-06-14 16:31:26 +0200559
560 EXPECT_EQ(kUser2, accounts[1].principal_name());
561 EXPECT_FALSE(accounts[1].password_was_remembered());
562 EXPECT_TRUE(accounts[1].use_login_password());
Lutz Justen6f582982019-05-15 10:24:22 +0200563}
564
565// ListAccounts() ignores failures in GetTgtStatus() and loading the config.
566TEST_F(AccountManagerTest, ListAccountsIgnoresFailures) {
Lutz Justen04afd272019-06-14 16:31:26 +0200567 ignore_result(AddAccount());
568 ignore_result(SetConfig());
569 ignore_result(AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200570 EXPECT_TRUE(base::PathExists(krb5cc_path_));
571
572 // Make reading the config fail.
573 EXPECT_TRUE(base::SetPosixFilePermissions(krb5conf_path_, 0));
574
575 // Make GetTgtStatus() fail.
576 krb5_->set_get_tgt_status_error(ERROR_UNKNOWN);
577
578 // ListAccounts() should still work, despite the errors.
579 std::vector<Account> accounts;
580 EXPECT_EQ(ERROR_NONE, manager_->ListAccounts(&accounts));
581 ASSERT_EQ(1u, accounts.size());
582 EXPECT_EQ(kUser, accounts[0].principal_name());
583
584 // The config should not be set since we made reading the file fail.
585 EXPECT_FALSE(accounts[0].has_krb5conf());
586
587 // tgt_*_seconds should not be set since we made GetTgtStatus() fail.
588 EXPECT_FALSE(accounts[0].has_tgt_renewal_seconds());
589 EXPECT_FALSE(accounts[0].has_tgt_validity_seconds());
590}
591
592// GetKerberosFiles returns empty KerberosFiles if there is no credential cache,
593// even if there is a config.
594TEST_F(AccountManagerTest, GetKerberosFilesSucceesWithoutCC) {
Lutz Justen04afd272019-06-14 16:31:26 +0200595 ignore_result(AddAccount());
596 ignore_result(SetConfig());
Lutz Justen6f582982019-05-15 10:24:22 +0200597
598 KerberosFiles files;
599 EXPECT_EQ(ERROR_NONE, manager_->GetKerberosFiles(kUser, &files));
600 EXPECT_FALSE(files.has_krb5cc());
601 EXPECT_FALSE(files.has_krb5conf());
602}
603
604// GetKerberosFiles returns the expected KerberosFiles if there is a credential
605// cache.
606TEST_F(AccountManagerTest, GetKerberosFilesSucceesWithCC) {
Lutz Justen04afd272019-06-14 16:31:26 +0200607 ignore_result(AddAccount());
608 ignore_result(SetConfig());
609 ignore_result(AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200610
611 KerberosFiles files;
612 EXPECT_EQ(ERROR_NONE, manager_->GetKerberosFiles(kUser, &files));
613 EXPECT_FALSE(files.krb5cc().empty());
614 EXPECT_EQ(kKrb5Conf, files.krb5conf());
615}
616
617// Most methods return ERROR_UNKNOWN_PRINCIPAL if called with such a principal.
618TEST_F(AccountManagerTest, MethodsReturnUnknownPrincipal) {
619 KerberosFiles files;
620 EXPECT_EQ(ERROR_UNKNOWN_PRINCIPAL_NAME, manager_->RemoveAccount(kUser));
Lutz Justen04afd272019-06-14 16:31:26 +0200621 EXPECT_EQ(ERROR_UNKNOWN_PRINCIPAL_NAME, SetConfig());
622 EXPECT_EQ(ERROR_UNKNOWN_PRINCIPAL_NAME, AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200623 EXPECT_EQ(ERROR_UNKNOWN_PRINCIPAL_NAME,
624 manager_->GetKerberosFiles(kUser, &files));
625}
626
627// Accounts can be saved to disk and loaded from disk.
628TEST_F(AccountManagerTest, SerializationSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200629 ignore_result(manager_->AddAccount(kUser, kManaged));
630 ignore_result(manager_->AcquireTgt(kUser, kPassword, kDontRememberPassword,
631 kUseLoginPassword));
632
633 ignore_result(manager_->AddAccount(kUser2, kUnmanaged));
634 ignore_result(manager_->AcquireTgt(kUser2, kPassword, kDontRememberPassword,
635 kDontUseLoginPassword));
Lutz Justen6f582982019-05-15 10:24:22 +0200636
637 EXPECT_EQ(ERROR_NONE, manager_->SaveAccounts());
Lutz Justen04afd272019-06-14 16:31:26 +0200638 AccountManager other_manager(
639 storage_dir_.GetPath(), kerberos_files_changed_,
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200640 kerberos_ticket_expiring_, std::make_unique<FakeKrb5Interface>(),
Lutz Justen04afd272019-06-14 16:31:26 +0200641 std::make_unique<password_provider::FakePasswordProvider>());
Lutz Justen6f582982019-05-15 10:24:22 +0200642 other_manager.LoadAccounts();
643 std::vector<Account> accounts;
Lutz Justen82d07ce2019-05-16 10:46:14 +0200644 EXPECT_EQ(ERROR_NONE, other_manager.ListAccounts(&accounts));
Lutz Justen6f582982019-05-15 10:24:22 +0200645 ASSERT_EQ(2u, accounts.size());
646
647 EXPECT_EQ(kUser, accounts[0].principal_name());
648 EXPECT_EQ(kUser2, accounts[1].principal_name());
649
650 EXPECT_TRUE(accounts[0].is_managed());
651 EXPECT_FALSE(accounts[1].is_managed());
652
Lutz Justen04afd272019-06-14 16:31:26 +0200653 EXPECT_TRUE(accounts[0].use_login_password());
654 EXPECT_FALSE(accounts[1].use_login_password());
655
Lutz Justen6f582982019-05-15 10:24:22 +0200656 // TODO(https://crbug.com/952239): Check additional Account properties.
657}
Lutz Justenb7ef5802019-05-14 14:03:20 +0200658
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200659// The TriggerKerberosTicketExpiringForExpiredTickets() method works fine.
660TEST_F(AccountManagerTest, TriggerKerberosTicketExpiringForExpiredTickets) {
661 ignore_result(AddAccount());
662 ignore_result(SetConfig());
663 ignore_result(AcquireTgt());
664 EXPECT_EQ(0, kerberos_ticket_expiring_count_[kUser]);
665
666 // Fake an expired ticket.
667 Krb5Interface::TgtStatus status;
668 status.validity_seconds = 0;
669 krb5_->set_tgt_status(status);
670 manager_->TriggerKerberosTicketExpiringForExpiredTickets();
671 EXPECT_EQ(1, kerberos_ticket_expiring_count_[kUser]);
672
673 // Fake a valid ticket.
674 status.validity_seconds = 1;
675 krb5_->set_tgt_status(status);
676 manager_->TriggerKerberosTicketExpiringForExpiredTickets();
677 EXPECT_EQ(1, kerberos_ticket_expiring_count_[kUser]);
678}
679
Lutz Justenb7ef5802019-05-14 14:03:20 +0200680} // namespace kerberos