blob: 6d8e733912b1dc8c7e5540b571953e1fdbd9660d [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>
Lutz Justend925d712019-06-27 17:34:00 +020015#include <base/memory/ref_counted.h>
16#include <base/test/test_mock_time_task_runner.h>
Lutz Justen2d857e12019-07-16 15:58:09 +020017#include <gmock/gmock.h>
Lutz Justenb7ef5802019-05-14 14:03:20 +020018#include <gtest/gtest.h>
Lutz Justen04afd272019-06-14 16:31:26 +020019#include <libpasswordprovider/fake_password_provider.h>
20#include <libpasswordprovider/password_provider_test_utils.h>
Lutz Justenb7ef5802019-05-14 14:03:20 +020021
Lutz Justene39cbd42019-05-14 14:52:24 +020022#include "kerberos/fake_krb5_interface.h"
Lutz Justen2d857e12019-07-16 15:58:09 +020023#include "kerberos/kerberos_metrics.h"
Lutz Justen33601802019-07-03 22:40:57 +020024#include "kerberos/krb5_jail_wrapper.h"
Lutz Justene39cbd42019-05-14 14:52:24 +020025
Lutz Justen2d857e12019-07-16 15:58:09 +020026using testing::_;
27using testing::Mock;
28using testing::NiceMock;
29using testing::Return;
30
Lutz Justend925d712019-06-27 17:34:00 +020031namespace kerberos {
Lutz Justenb7ef5802019-05-14 14:03:20 +020032namespace {
Lutz Justen6f582982019-05-15 10:24:22 +020033
Lutz Justenb7ef5802019-05-14 14:03:20 +020034constexpr char kUser[] = "user@REALM.COM";
Lutz Justen6f582982019-05-15 10:24:22 +020035constexpr char kUser2[] = "user2@REALM2.COM";
Lutz Justen781825e2019-07-13 07:49:44 +020036constexpr char kUser3[] = "user3@REALM3.COM";
Lutz Justen6f582982019-05-15 10:24:22 +020037constexpr char kPassword[] = "i<3k3R8e5Oz";
Lutz Justen04afd272019-06-14 16:31:26 +020038constexpr char kPassword2[] = "ih4zf00d";
Lutz Justen6f582982019-05-15 10:24:22 +020039constexpr char kKrb5Conf[] = R"(
40 [libdefaults]
41 default_realm = REALM.COM)";
42
Lutz Justend925d712019-06-27 17:34:00 +020043constexpr Krb5Interface::TgtStatus kValidTgt(3600, 3600);
44constexpr Krb5Interface::TgtStatus kExpiredTgt(0, 0);
45
Lutz Justen04afd272019-06-14 16:31:26 +020046// Convenience defines to make code more readable
47constexpr bool kManaged = true;
48constexpr bool kUnmanaged = false;
49
50constexpr bool kRememberPassword = true;
51constexpr bool kDontRememberPassword = false;
52
53constexpr bool kUseLoginPassword = true;
54constexpr bool kDontUseLoginPassword = false;
55
56constexpr char kEmptyPassword[] = "";
57
Lutz Justen2d857e12019-07-16 15:58:09 +020058class MockMetrics : public KerberosMetrics {
59 public:
60 explicit MockMetrics(const base::FilePath& storage_dir)
61 : KerberosMetrics(storage_dir) {}
62 ~MockMetrics() override = default;
63
64 MOCK_METHOD0(ShouldReportDailyUsageStats, bool());
65 MOCK_METHOD5(ReportDailyUsageStats, void(int, int, int, int, int));
66
67 private:
68 DISALLOW_COPY_AND_ASSIGN(MockMetrics);
69};
70
Lutz Justen6f582982019-05-15 10:24:22 +020071} // namespace
Lutz Justenb7ef5802019-05-14 14:03:20 +020072
Lutz Justenb7ef5802019-05-14 14:03:20 +020073class AccountManagerTest : public ::testing::Test {
74 public:
Lutz Justen6f582982019-05-15 10:24:22 +020075 AccountManagerTest()
76 : kerberos_files_changed_(
77 base::BindRepeating(&AccountManagerTest::OnKerberosFilesChanged,
Lutz Justen8eeb4a22019-06-19 17:00:32 +020078 base::Unretained(this))),
79 kerberos_ticket_expiring_(
80 base::BindRepeating(&AccountManagerTest::OnKerberosTicketExpiring,
Lutz Justen6f582982019-05-15 10:24:22 +020081 base::Unretained(this))) {}
Lutz Justenb7ef5802019-05-14 14:03:20 +020082 ~AccountManagerTest() override = default;
83
84 void SetUp() override {
85 ::testing::Test::SetUp();
86
87 // Create temp directory for files written during tests.
88 CHECK(storage_dir_.CreateUniqueTempDir());
Lutz Justen6f582982019-05-15 10:24:22 +020089 accounts_path_ = storage_dir_.GetPath().Append("accounts");
Lutz Justen33601802019-07-03 22:40:57 +020090 account_dir_ = storage_dir_.GetPath().Append(
Lutz Justenc5690502019-05-24 17:00:54 +020091 AccountManager::GetSafeFilenameForTesting(kUser));
Lutz Justen33601802019-07-03 22:40:57 +020092 krb5cc_path_ = account_dir_.Append("krb5cc");
93 krb5conf_path_ = account_dir_.Append("krb5.conf");
94 password_path_ = account_dir_.Append("password");
Lutz Justenb7ef5802019-05-14 14:03:20 +020095
Lutz Justen6f582982019-05-15 10:24:22 +020096 // Create the manager with a fake krb5 interface.
97 auto krb5 = std::make_unique<FakeKrb5Interface>();
Lutz Justen04afd272019-06-14 16:31:26 +020098 auto password_provider =
99 std::make_unique<password_provider::FakePasswordProvider>();
Lutz Justen2d857e12019-07-16 15:58:09 +0200100 metrics_ = std::make_unique<NiceMock<MockMetrics>>(storage_dir_.GetPath());
Lutz Justen6f582982019-05-15 10:24:22 +0200101 krb5_ = krb5.get();
Lutz Justen04afd272019-06-14 16:31:26 +0200102 password_provider_ = password_provider.get();
Lutz Justenb7ef5802019-05-14 14:03:20 +0200103 manager_ = std::make_unique<AccountManager>(
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200104 storage_dir_.GetPath(), kerberos_files_changed_,
105 kerberos_ticket_expiring_, std::move(krb5),
Lutz Justen2d857e12019-07-16 15:58:09 +0200106 std::move(password_provider), metrics_.get());
Lutz Justenb7ef5802019-05-14 14:03:20 +0200107 }
108
Lutz Justen82d07ce2019-05-16 10:46:14 +0200109 void TearDown() override {
110 // Make sure the file stored on disk contains the same accounts as the
111 // manager instance. This catches cases where AccountManager forgets to save
112 // accounts on some change.
113 if (base::PathExists(accounts_path_)) {
114 std::vector<Account> accounts;
115 EXPECT_EQ(ERROR_NONE, manager_->ListAccounts(&accounts));
116
Lutz Justen04afd272019-06-14 16:31:26 +0200117 AccountManager other_manager(
118 storage_dir_.GetPath(), kerberos_files_changed_,
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200119 kerberos_ticket_expiring_, std::make_unique<FakeKrb5Interface>(),
Lutz Justen2d857e12019-07-16 15:58:09 +0200120 std::make_unique<password_provider::FakePasswordProvider>(),
121 metrics_.get());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200122 other_manager.LoadAccounts();
123 std::vector<Account> other_accounts;
124 EXPECT_EQ(ERROR_NONE, other_manager.ListAccounts(&other_accounts));
125
126 ASSERT_NO_FATAL_FAILURE(ExpectAccountsEqual(accounts, other_accounts));
127 }
128
129 ::testing::Test::TearDown();
130 }
131
Lutz Justen04afd272019-06-14 16:31:26 +0200132 // Add account with default settings.
133 ErrorType AddAccount() { return manager_->AddAccount(kUser, kUnmanaged); }
134
135 // Sets some default Kerberos configuration.
136 ErrorType SetConfig() { return manager_->SetConfig(kUser, kKrb5Conf); }
137
138 // Acquire Kerberos ticket with default credentials and settings.
139 ErrorType AcquireTgt() {
140 return manager_->AcquireTgt(kUser, kPassword, kDontRememberPassword,
141 kDontUseLoginPassword);
142 }
143
144 void SaveLoginPassword(const char* password) {
145 auto password_ptr = password_provider::test::CreatePassword(password);
146 password_provider_->SavePassword(*password_ptr);
147 }
148
Lutz Justend925d712019-06-27 17:34:00 +0200149 // Fast forwards to the next scheduled task (assumed to be the renewal task)
150 // and verifies expectation that |krb5_->RenewTgt() was called|.
151 void RunScheduledRenewalTask() {
152 int initial_count = krb5_->renew_tgt_call_count();
153 EXPECT_EQ(1, task_runner_->GetPendingTaskCount());
154 task_runner_->FastForwardBy(task_runner_->NextPendingTaskDelay());
155 EXPECT_EQ(initial_count + 1, krb5_->renew_tgt_call_count());
156 }
157
Lutz Justenb7ef5802019-05-14 14:03:20 +0200158 protected:
159 void OnKerberosFilesChanged(const std::string& principal_name) {
160 kerberos_files_changed_count_[principal_name]++;
161 }
162
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200163 void OnKerberosTicketExpiring(const std::string& principal_name) {
164 kerberos_ticket_expiring_count_[principal_name]++;
165 }
166
Lutz Justen82d07ce2019-05-16 10:46:14 +0200167 void ExpectAccountsEqual(const std::vector<Account>& account_list_1,
168 const std::vector<Account>& account_list_2) {
169 ASSERT_EQ(account_list_1.size(), account_list_2.size());
170 for (size_t n = 0; n < account_list_1.size(); ++n) {
171 const Account& account1 = account_list_1[n];
172 const Account& account2 = account_list_2[n];
173
174 EXPECT_EQ(account1.principal_name(), account2.principal_name());
175 EXPECT_EQ(account1.is_managed(), account2.is_managed());
Lutz Justen04afd272019-06-14 16:31:26 +0200176 EXPECT_EQ(account1.use_login_password(), account2.use_login_password());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200177 // TODO(https://crbug.com/952239): Check additional properties.
178 }
179 }
180
Lutz Justenb7ef5802019-05-14 14:03:20 +0200181 std::unique_ptr<AccountManager> manager_;
Lutz Justen6f582982019-05-15 10:24:22 +0200182
Lutz Justen04afd272019-06-14 16:31:26 +0200183 // Fake Kerberos interface used by |manager_|. Not owned.
Lutz Justen6f582982019-05-15 10:24:22 +0200184 FakeKrb5Interface* krb5_;
185
Lutz Justen04afd272019-06-14 16:31:26 +0200186 // Fake password provider to get the login password. Not owned.
187 password_provider::FakePasswordProvider* password_provider_;
188
Lutz Justen2d857e12019-07-16 15:58:09 +0200189 // Mock metrics for testing UMA stat recording.
190 std::unique_ptr<NiceMock<MockMetrics>> metrics_;
191
Lutz Justen6f582982019-05-15 10:24:22 +0200192 // Paths of files stored by |manager_|.
Lutz Justenb7ef5802019-05-14 14:03:20 +0200193 base::ScopedTempDir storage_dir_;
Lutz Justen6f582982019-05-15 10:24:22 +0200194 base::FilePath accounts_path_;
Lutz Justen33601802019-07-03 22:40:57 +0200195 base::FilePath account_dir_;
Lutz Justen6f582982019-05-15 10:24:22 +0200196 base::FilePath krb5conf_path_;
197 base::FilePath krb5cc_path_;
Lutz Justenc5690502019-05-24 17:00:54 +0200198 base::FilePath password_path_;
Lutz Justen6f582982019-05-15 10:24:22 +0200199
200 AccountManager::KerberosFilesChangedCallback kerberos_files_changed_;
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200201 AccountManager::KerberosTicketExpiringCallback kerberos_ticket_expiring_;
202
Lutz Justenb7ef5802019-05-14 14:03:20 +0200203 std::map<std::string, int> kerberos_files_changed_count_;
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200204 std::map<std::string, int> kerberos_ticket_expiring_count_;
Lutz Justenb7ef5802019-05-14 14:03:20 +0200205
Lutz Justend925d712019-06-27 17:34:00 +0200206 scoped_refptr<base::TestMockTimeTaskRunner> task_runner_{
207 new base::TestMockTimeTaskRunner()};
208 base::TestMockTimeTaskRunner::ScopedContext scoped_context_{task_runner_};
209
Lutz Justenb7ef5802019-05-14 14:03:20 +0200210 private:
211 DISALLOW_COPY_AND_ASSIGN(AccountManagerTest);
212};
213
Lutz Justen6f582982019-05-15 10:24:22 +0200214// Adding an account succeeds and serializes the file on disk.
Lutz Justenb7ef5802019-05-14 14:03:20 +0200215TEST_F(AccountManagerTest, AddAccountSuccess) {
Lutz Justen6f582982019-05-15 10:24:22 +0200216 EXPECT_FALSE(base::PathExists(accounts_path_));
Lutz Justen04afd272019-06-14 16:31:26 +0200217 EXPECT_EQ(ERROR_NONE, AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200218 EXPECT_TRUE(base::PathExists(accounts_path_));
Lutz Justenb7ef5802019-05-14 14:03:20 +0200219}
220
Lutz Justen6f582982019-05-15 10:24:22 +0200221// AddAccount() fails if the same account is added twice.
Lutz Justenb7ef5802019-05-14 14:03:20 +0200222TEST_F(AccountManagerTest, AddDuplicateAccountFail) {
Lutz Justen04afd272019-06-14 16:31:26 +0200223 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200224
225 EXPECT_TRUE(base::DeleteFile(accounts_path_, false /* recursive */));
Lutz Justen04afd272019-06-14 16:31:26 +0200226 EXPECT_EQ(ERROR_DUPLICATE_PRINCIPAL_NAME, AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200227 EXPECT_FALSE(base::PathExists(accounts_path_));
Lutz Justenb7ef5802019-05-14 14:03:20 +0200228}
229
Lutz Justen6f582982019-05-15 10:24:22 +0200230// Adding a managed account overwrites an existing unmanaged account.
231TEST_F(AccountManagerTest, ManagedOverridesUnmanaged) {
Lutz Justen04afd272019-06-14 16:31:26 +0200232 ignore_result(manager_->AddAccount(kUser, kUnmanaged));
Lutz Justen6f582982019-05-15 10:24:22 +0200233
Lutz Justen04afd272019-06-14 16:31:26 +0200234 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200235 EXPECT_TRUE(base::PathExists(krb5cc_path_));
236
237 // Overwriting with a managed account should wipe existing files and make the
238 // account managed.
Lutz Justen6f582982019-05-15 10:24:22 +0200239 EXPECT_EQ(ERROR_DUPLICATE_PRINCIPAL_NAME,
Lutz Justen04afd272019-06-14 16:31:26 +0200240 manager_->AddAccount(kUser, kManaged));
Lutz Justen82d07ce2019-05-16 10:46:14 +0200241 EXPECT_FALSE(base::PathExists(krb5cc_path_));
242
Lutz Justen6f582982019-05-15 10:24:22 +0200243 std::vector<Account> accounts;
244 EXPECT_EQ(ERROR_NONE, manager_->ListAccounts(&accounts));
245 ASSERT_EQ(1u, accounts.size());
246 EXPECT_TRUE(accounts[0].is_managed());
247}
248
249// Adding an unmanaged account does not overwrite an existing managed account.
250TEST_F(AccountManagerTest, UnmanagedDoesNotOverrideManaged) {
Lutz Justen04afd272019-06-14 16:31:26 +0200251 ignore_result(manager_->AddAccount(kUser, kManaged));
Lutz Justen6f582982019-05-15 10:24:22 +0200252
253 EXPECT_EQ(ERROR_DUPLICATE_PRINCIPAL_NAME,
Lutz Justen04afd272019-06-14 16:31:26 +0200254 manager_->AddAccount(kUser, kUnmanaged));
Lutz Justen6f582982019-05-15 10:24:22 +0200255 std::vector<Account> accounts;
256 EXPECT_EQ(ERROR_NONE, manager_->ListAccounts(&accounts));
257 ASSERT_EQ(1u, accounts.size());
258 EXPECT_TRUE(accounts[0].is_managed());
259}
260
261// RemoveAccount() succeeds if the account exists and serializes the file on
262// disk.
Lutz Justenb7ef5802019-05-14 14:03:20 +0200263TEST_F(AccountManagerTest, RemoveAccountSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200264 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200265
266 EXPECT_TRUE(base::DeleteFile(accounts_path_, false /* recursive */));
Lutz Justenb7ef5802019-05-14 14:03:20 +0200267 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
Lutz Justen6f582982019-05-15 10:24:22 +0200268 EXPECT_TRUE(base::PathExists(accounts_path_));
Lutz Justenb7ef5802019-05-14 14:03:20 +0200269}
270
Lutz Justen6f582982019-05-15 10:24:22 +0200271// RemoveAccount() fails if the account does not exist.
Lutz Justenb7ef5802019-05-14 14:03:20 +0200272TEST_F(AccountManagerTest, RemoveUnknownAccountFail) {
273 EXPECT_EQ(ERROR_UNKNOWN_PRINCIPAL_NAME, manager_->RemoveAccount(kUser));
Lutz Justen6f582982019-05-15 10:24:22 +0200274 EXPECT_FALSE(base::PathExists(accounts_path_));
275}
276
277// RemoveAccount() does not trigger KerberosFilesChanged if the credential cache
278// does not exists.
279TEST_F(AccountManagerTest, RemoveAccountTriggersKFCIfCCExists) {
Lutz Justen04afd272019-06-14 16:31:26 +0200280 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200281
282 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
283 EXPECT_EQ(0, kerberos_files_changed_count_[kUser]);
284}
285
286// RemoveAccount() triggers KerberosFilesChanged if the credential cache exists.
287TEST_F(AccountManagerTest, RemoveAccountDoesNotTriggerKFCIfCCDoesNotExist) {
Lutz Justen04afd272019-06-14 16:31:26 +0200288 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200289
Lutz Justen04afd272019-06-14 16:31:26 +0200290 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200291 EXPECT_EQ(1, kerberos_files_changed_count_[kUser]);
292 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
293 EXPECT_EQ(2, kerberos_files_changed_count_[kUser]);
Lutz Justenb7ef5802019-05-14 14:03:20 +0200294}
295
296// Repeatedly calling AddAccount() and RemoveAccount() succeeds.
297TEST_F(AccountManagerTest, RepeatedAddRemoveSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200298 ignore_result(AddAccount());
Lutz Justenb7ef5802019-05-14 14:03:20 +0200299 ignore_result(manager_->RemoveAccount(kUser));
Lutz Justen6f582982019-05-15 10:24:22 +0200300
Lutz Justen04afd272019-06-14 16:31:26 +0200301 EXPECT_EQ(ERROR_NONE, AddAccount());
Lutz Justenb7ef5802019-05-14 14:03:20 +0200302 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
303}
304
Lutz Justen2d420872019-06-25 14:17:21 +0200305// ClearAccounts(CLEAR_ALL) clears all accounts.
306TEST_F(AccountManagerTest, ClearAccountsSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200307 ignore_result(manager_->AddAccount(kUser, kUnmanaged));
308 ignore_result(manager_->AddAccount(kUser2, kManaged));
Lutz Justen82d07ce2019-05-16 10:46:14 +0200309
Lutz Justen781825e2019-07-13 07:49:44 +0200310 EXPECT_EQ(ERROR_NONE, manager_->ClearAccounts(CLEAR_ALL, {}));
Lutz Justen82d07ce2019-05-16 10:46:14 +0200311 std::vector<Account> accounts;
312 EXPECT_EQ(ERROR_NONE, manager_->ListAccounts(&accounts));
313 EXPECT_EQ(0u, accounts.size());
314}
315
Lutz Justen2d420872019-06-25 14:17:21 +0200316// ClearAccounts(CLEAR_ALL) wipes Kerberos configuration and credential cache.
317TEST_F(AccountManagerTest, ClearAccountsRemovesKerberosFiles) {
Lutz Justen04afd272019-06-14 16:31:26 +0200318 ignore_result(AddAccount());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200319
Lutz Justen04afd272019-06-14 16:31:26 +0200320 EXPECT_EQ(ERROR_NONE, SetConfig());
321 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200322 EXPECT_TRUE(base::PathExists(krb5conf_path_));
323 EXPECT_TRUE(base::PathExists(krb5cc_path_));
Lutz Justen781825e2019-07-13 07:49:44 +0200324 EXPECT_EQ(ERROR_NONE, manager_->ClearAccounts(CLEAR_ALL, {}));
Lutz Justen82d07ce2019-05-16 10:46:14 +0200325 EXPECT_FALSE(base::PathExists(krb5conf_path_));
326 EXPECT_FALSE(base::PathExists(krb5cc_path_));
327}
328
Lutz Justen2d420872019-06-25 14:17:21 +0200329// ClearAccounts(CLEAR_ALL) triggers KerberosFilesChanged if the credential
330// cache exists.
331TEST_F(AccountManagerTest, ClearAccountsTriggersKFCIfCCExists) {
Lutz Justen04afd272019-06-14 16:31:26 +0200332 ignore_result(AddAccount());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200333
Lutz Justen04afd272019-06-14 16:31:26 +0200334 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200335 EXPECT_EQ(1, kerberos_files_changed_count_[kUser]);
Lutz Justen781825e2019-07-13 07:49:44 +0200336 EXPECT_EQ(ERROR_NONE, manager_->ClearAccounts(CLEAR_ALL, {}));
Lutz Justen82d07ce2019-05-16 10:46:14 +0200337 EXPECT_EQ(2, kerberos_files_changed_count_[kUser]);
338}
339
Lutz Justen2d420872019-06-25 14:17:21 +0200340// ClearAccounts(CLEAR_ALL) does not trigger KerberosFilesChanged if the
341// credential cache does not exist.
342TEST_F(AccountManagerTest, ClearAccountsDoesNotTriggerKFCIfDoesNotCCExist) {
Lutz Justen04afd272019-06-14 16:31:26 +0200343 ignore_result(AddAccount());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200344
Lutz Justen781825e2019-07-13 07:49:44 +0200345 EXPECT_EQ(ERROR_NONE, manager_->ClearAccounts(CLEAR_ALL, {}));
Lutz Justen82d07ce2019-05-16 10:46:14 +0200346 EXPECT_EQ(0, kerberos_files_changed_count_[kUser]);
347}
348
Lutz Justen2d420872019-06-25 14:17:21 +0200349// ClearAccounts(CLEAR_ONLY_UNMANAGED_ACCOUNTS) clears only unmanaged accounts.
350TEST_F(AccountManagerTest, ClearUnmanagedAccountsSuccess) {
351 ignore_result(manager_->AddAccount(kUser, kUnmanaged));
352 ignore_result(manager_->AddAccount(kUser2, kManaged));
353
Lutz Justen781825e2019-07-13 07:49:44 +0200354 EXPECT_EQ(ERROR_NONE,
355 manager_->ClearAccounts(CLEAR_ONLY_UNMANAGED_ACCOUNTS, {}));
Lutz Justen2d420872019-06-25 14:17:21 +0200356 std::vector<Account> accounts;
357 EXPECT_EQ(ERROR_NONE, manager_->ListAccounts(&accounts));
358 ASSERT_EQ(1u, accounts.size());
359 EXPECT_EQ(kUser2, accounts[0].principal_name());
360}
361
362// ClearAccounts(CLEAR_ONLY_UNMANAGED_REMEMBERED_PASSWORDS) clears only
363// passwords of unmanaged accounts.
364TEST_F(AccountManagerTest, ClearUnmanagedPasswordsSuccess) {
365 // kUser is unmanaged, kUser2 is managed.
366 ignore_result(manager_->AddAccount(kUser, kUnmanaged));
367 ignore_result(manager_->AddAccount(kUser2, kManaged));
368 ignore_result(manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
369 kDontUseLoginPassword));
370 ignore_result(manager_->AcquireTgt(kUser2, kPassword, kRememberPassword,
371 kDontUseLoginPassword));
372
373 base::FilePath password_path_2 =
374 storage_dir_.GetPath()
375 .Append(AccountManager::GetSafeFilenameForTesting(kUser2))
376 .Append("password");
377 EXPECT_TRUE(base::PathExists(password_path_));
378 EXPECT_TRUE(base::PathExists(password_path_2));
379
Lutz Justen781825e2019-07-13 07:49:44 +0200380 EXPECT_EQ(ERROR_NONE, manager_->ClearAccounts(
381 CLEAR_ONLY_UNMANAGED_REMEMBERED_PASSWORDS, {}));
Lutz Justen2d420872019-06-25 14:17:21 +0200382 std::vector<Account> accounts;
383 EXPECT_EQ(ERROR_NONE, manager_->ListAccounts(&accounts));
384 ASSERT_EQ(2u, accounts.size());
385 EXPECT_FALSE(base::PathExists(password_path_));
386 EXPECT_TRUE(base::PathExists(password_path_2));
387}
388
Lutz Justen781825e2019-07-13 07:49:44 +0200389// ClearAccounts(CLEAR_ONLY_MANAGED_ACCOUNTS) clears only managed accounts that
390// are not on the keep list.
391TEST_F(AccountManagerTest, ClearManagedPasswordsWithKeepListSuccess) {
392 ignore_result(manager_->AddAccount(kUser, kManaged));
393 ignore_result(manager_->AddAccount(kUser2, kManaged));
394 ignore_result(manager_->AddAccount(kUser3, kUnmanaged));
395
396 // Keep the managed kUser-account.
397 EXPECT_EQ(ERROR_NONE,
398 manager_->ClearAccounts(CLEAR_ONLY_MANAGED_ACCOUNTS, {kUser}));
399 std::vector<Account> accounts;
400 EXPECT_EQ(ERROR_NONE, manager_->ListAccounts(&accounts));
401 ASSERT_EQ(2u, accounts.size());
402 EXPECT_EQ(kUser, accounts[0].principal_name());
403 EXPECT_EQ(kUser3, accounts[1].principal_name());
404}
405
Lutz Justen6f582982019-05-15 10:24:22 +0200406// SetConfig() succeeds and writes the config to |krb5conf_path_|.
407TEST_F(AccountManagerTest, SetConfigSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200408 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200409
Lutz Justen04afd272019-06-14 16:31:26 +0200410 EXPECT_EQ(ERROR_NONE, SetConfig());
Lutz Justen6f582982019-05-15 10:24:22 +0200411 std::string krb5_conf;
412 EXPECT_TRUE(base::ReadFileToString(krb5conf_path_, &krb5_conf));
413 EXPECT_EQ(krb5_conf, kKrb5Conf);
414}
415
Lutz Justen90281402019-07-05 15:14:37 +0200416// SetConfig() calls ValidateConfig on the Kerberos interface.
417TEST_F(AccountManagerTest, SetConfigValidatesConfig) {
418 ignore_result(AddAccount());
419
420 krb5_->set_validate_config_error(ERROR_BAD_CONFIG);
421 EXPECT_EQ(ERROR_BAD_CONFIG, SetConfig());
422}
423
Lutz Justen6f582982019-05-15 10:24:22 +0200424// SetConfig() triggers KerberosFilesChanged if the credential cache exists.
425TEST_F(AccountManagerTest, SetConfigTriggersKFCIfCCExists) {
Lutz Justen04afd272019-06-14 16:31:26 +0200426 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200427
Lutz Justen04afd272019-06-14 16:31:26 +0200428 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200429 EXPECT_EQ(1, kerberos_files_changed_count_[kUser]);
Lutz Justen04afd272019-06-14 16:31:26 +0200430 EXPECT_EQ(ERROR_NONE, SetConfig());
Lutz Justen6f582982019-05-15 10:24:22 +0200431 EXPECT_EQ(2, kerberos_files_changed_count_[kUser]);
432}
433
Lutz Justen82d07ce2019-05-16 10:46:14 +0200434// SetConfig() does not trigger KerberosFilesChanged if the credential cache
435// does not exist.
Lutz Justen6f582982019-05-15 10:24:22 +0200436TEST_F(AccountManagerTest, SetConfigDoesNotTriggerKFCIfDoesNotCCExist) {
Lutz Justen04afd272019-06-14 16:31:26 +0200437 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200438
Lutz Justen04afd272019-06-14 16:31:26 +0200439 EXPECT_EQ(ERROR_NONE, SetConfig());
Lutz Justen6f582982019-05-15 10:24:22 +0200440 EXPECT_EQ(0, kerberos_files_changed_count_[kUser]);
441}
442
443// RemoveAccount() removes the config file.
444TEST_F(AccountManagerTest, RemoveAccountRemovesConfig) {
Lutz Justen04afd272019-06-14 16:31:26 +0200445 ignore_result(AddAccount());
446 ignore_result(SetConfig());
Lutz Justen6f582982019-05-15 10:24:22 +0200447
448 EXPECT_TRUE(base::PathExists(krb5conf_path_));
449 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
450 EXPECT_FALSE(base::PathExists(krb5conf_path_));
451}
452
Lutz Justen90281402019-07-05 15:14:37 +0200453// ValidateConfig() validates a good config successfully.
454TEST_F(AccountManagerTest, ValidateConfigSuccess) {
455 constexpr char kValidKrb5Conf[] = "";
456 ConfigErrorInfo error_info;
457 EXPECT_EQ(ERROR_NONE, manager_->ValidateConfig(kValidKrb5Conf, &error_info));
458 EXPECT_EQ(CONFIG_ERROR_NONE, error_info.code());
459}
460
461// ValidateConfig() returns the correct error for a bad config.
462TEST_F(AccountManagerTest, ValidateConfigFailure) {
463 ConfigErrorInfo expected_error_info;
464 expected_error_info.set_code(CONFIG_ERROR_SECTION_SYNTAX);
465 krb5_->set_config_error_info(expected_error_info);
466 krb5_->set_validate_config_error(ERROR_BAD_CONFIG);
467
468 constexpr char kBadKrb5Conf[] =
469 "[libdefaults]'); DROP TABLE KerberosTickets;--";
470 ConfigErrorInfo error_info;
471 EXPECT_EQ(ERROR_BAD_CONFIG,
472 manager_->ValidateConfig(kBadKrb5Conf, &error_info));
473 EXPECT_EQ(expected_error_info.SerializeAsString(),
474 error_info.SerializeAsString());
475}
476
Lutz Justen6f582982019-05-15 10:24:22 +0200477// AcquireTgt() succeeds and writes a credential cache file.
478TEST_F(AccountManagerTest, AcquireTgtSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200479 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200480
Lutz Justen04afd272019-06-14 16:31:26 +0200481 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200482 EXPECT_TRUE(base::PathExists(krb5cc_path_));
483}
484
485// AcquireTgt() triggers KerberosFilesChanged on success.
486TEST_F(AccountManagerTest, AcquireTgtTriggersKFCOnSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200487 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200488
489 EXPECT_EQ(0, kerberos_files_changed_count_[kUser]);
Lutz Justen04afd272019-06-14 16:31:26 +0200490 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200491 EXPECT_EQ(1, kerberos_files_changed_count_[kUser]);
492}
493
494// AcquireTgt() does not trigger KerberosFilesChanged on failure.
495TEST_F(AccountManagerTest, AcquireTgtDoesNotTriggerKFCOnFailure) {
Lutz Justen04afd272019-06-14 16:31:26 +0200496 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200497
498 krb5_->set_acquire_tgt_error(ERROR_UNKNOWN);
Lutz Justen04afd272019-06-14 16:31:26 +0200499 EXPECT_EQ(ERROR_UNKNOWN, AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200500 EXPECT_EQ(0, kerberos_files_changed_count_[kUser]);
501}
502
Lutz Justenc5690502019-05-24 17:00:54 +0200503// AcquireTgt() saves password to disk if |remember_password| is true and
504// removes the file again if |remember_password| is false.
505TEST_F(AccountManagerTest, AcquireTgtRemembersPasswordsIfWanted) {
Lutz Justen04afd272019-06-14 16:31:26 +0200506 ignore_result(AddAccount());
Lutz Justenc5690502019-05-24 17:00:54 +0200507
508 EXPECT_FALSE(base::PathExists(password_path_));
Lutz Justen04afd272019-06-14 16:31:26 +0200509 EXPECT_EQ(ERROR_NONE,
510 manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
511 kDontUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200512 EXPECT_TRUE(base::PathExists(password_path_));
513
Lutz Justen04afd272019-06-14 16:31:26 +0200514 EXPECT_EQ(ERROR_NONE,
515 manager_->AcquireTgt(kUser, kPassword, kDontRememberPassword,
516 kDontUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200517 EXPECT_FALSE(base::PathExists(password_path_));
518}
519
520// AcquireTgt() uses saved password if none is given, no matter if it should be
521// remembered again or not.
522TEST_F(AccountManagerTest, AcquireTgtLoadsRememberedPassword) {
Lutz Justen04afd272019-06-14 16:31:26 +0200523 ignore_result(AddAccount());
524 ignore_result(manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
525 kDontUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200526
527 // This should load stored password and keep it.
528 EXPECT_EQ(ERROR_NONE,
Lutz Justen04afd272019-06-14 16:31:26 +0200529 manager_->AcquireTgt(kUser, kEmptyPassword, kRememberPassword,
530 kDontUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200531 EXPECT_TRUE(base::PathExists(password_path_));
532
533 // This should load stored password, but erase it afterwards.
534 EXPECT_EQ(ERROR_NONE,
Lutz Justen04afd272019-06-14 16:31:26 +0200535 manager_->AcquireTgt(kUser, kEmptyPassword, kDontRememberPassword,
536 kDontUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200537 EXPECT_FALSE(base::PathExists(password_path_));
538
539 // Check that the fake krb5 interface returns an error for a missing password.
540 // This verifies that the above AcquireTgt() call actually loaded the
541 // password from disk.
542 EXPECT_EQ(ERROR_BAD_PASSWORD,
Lutz Justen04afd272019-06-14 16:31:26 +0200543 manager_->AcquireTgt(kUser, kEmptyPassword, kDontRememberPassword,
544 kDontUseLoginPassword));
545}
546
547// AcquireTgt() uses the login password if saved.
548TEST_F(AccountManagerTest, AcquireTgtUsesLoginPassword) {
549 ignore_result(AddAccount());
550
551 // Shouldn't explode if the login password not set yet.
552 EXPECT_EQ(ERROR_BAD_PASSWORD,
553 manager_->AcquireTgt(kUser, kEmptyPassword, kDontRememberPassword,
554 kUseLoginPassword));
555
556 SaveLoginPassword(kPassword);
557 krb5_->set_expected_password(kPassword);
558
559 // Uses the login password.
560 EXPECT_EQ(ERROR_NONE,
561 manager_->AcquireTgt(kUser, kEmptyPassword, kDontRememberPassword,
562 kUseLoginPassword));
563
564 // Check if auth fails without kUseLoginPassword.
565 EXPECT_EQ(ERROR_BAD_PASSWORD,
566 manager_->AcquireTgt(kUser, kEmptyPassword, kDontRememberPassword,
567 kDontUseLoginPassword));
568}
569
570// AcquireTgt() wipes a saved password if the login password is used.
571TEST_F(AccountManagerTest, AcquireTgtWipesStoredPasswordOnUsesLoginPassword) {
572 ignore_result(AddAccount());
573 ignore_result(manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
574 kDontUseLoginPassword));
575 EXPECT_TRUE(base::PathExists(password_path_));
576
577 SaveLoginPassword(kPassword);
578
579 // Note: kRememberPassword gets ignored if kUseLoginPassword is passed.
580 EXPECT_EQ(ERROR_NONE,
581 manager_->AcquireTgt(kUser, kEmptyPassword, kRememberPassword,
582 kUseLoginPassword));
583 EXPECT_FALSE(base::PathExists(password_path_));
584}
585
586// AcquireTgt() ignores the passed password if the login password is used.
587TEST_F(AccountManagerTest, AcquireTgtIgnoresPassedPasswordOnUsesLoginPassword) {
588 ignore_result(AddAccount());
589
590 SaveLoginPassword(kPassword);
591 krb5_->set_expected_password(kPassword);
592
593 // Auth works despite passed kPassword2 != expected kPassword because the
594 // login kPassword is used.
595 EXPECT_EQ(ERROR_NONE,
596 manager_->AcquireTgt(kUser, kPassword2, kDontRememberPassword,
597 kUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200598}
599
Lutz Justen6f582982019-05-15 10:24:22 +0200600// RemoveAccount() removes the credential cache file.
601TEST_F(AccountManagerTest, RemoveAccountRemovesCC) {
Lutz Justen04afd272019-06-14 16:31:26 +0200602 ignore_result(AddAccount());
603 ignore_result(AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200604
605 EXPECT_TRUE(base::PathExists(krb5cc_path_));
606 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
607 EXPECT_FALSE(base::PathExists(krb5cc_path_));
608}
609
Lutz Justenc5690502019-05-24 17:00:54 +0200610// RemoveAccount() removes saved passwords.
611TEST_F(AccountManagerTest, RemoveAccountRemovesPassword) {
Lutz Justen04afd272019-06-14 16:31:26 +0200612 ignore_result(AddAccount());
613 ignore_result(manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
614 kDontUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200615
616 EXPECT_TRUE(base::PathExists(password_path_));
617 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
618 EXPECT_FALSE(base::PathExists(password_path_));
619}
620
Lutz Justen6f582982019-05-15 10:24:22 +0200621// ListAccounts() succeeds and contains the expected data.
622TEST_F(AccountManagerTest, ListAccountsSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200623 ignore_result(manager_->AddAccount(kUser, kManaged));
624 ignore_result(SetConfig());
625 ignore_result(manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
626 kDontUseLoginPassword));
627 SaveLoginPassword(kPassword);
628 ignore_result(manager_->AddAccount(kUser2, kUnmanaged));
629 // Note: kRememberPassword should be ignored here, see below.
630 ignore_result(manager_->AcquireTgt(kUser2, kPassword, kRememberPassword,
631 kUseLoginPassword));
Lutz Justen6f582982019-05-15 10:24:22 +0200632 EXPECT_TRUE(base::PathExists(krb5cc_path_));
633
634 // Set a fake tgt status.
635 constexpr int kRenewalSeconds = 10;
636 constexpr int kValiditySeconds = 90;
Lutz Justend925d712019-06-27 17:34:00 +0200637 krb5_->set_tgt_status(
638 Krb5Interface::TgtStatus(kValiditySeconds, kRenewalSeconds));
Lutz Justen6f582982019-05-15 10:24:22 +0200639
640 // Verify that ListAccounts returns the expected account.
641 std::vector<Account> accounts;
642 EXPECT_EQ(ERROR_NONE, manager_->ListAccounts(&accounts));
Lutz Justen04afd272019-06-14 16:31:26 +0200643 ASSERT_EQ(2u, accounts.size());
644
Lutz Justen6f582982019-05-15 10:24:22 +0200645 EXPECT_EQ(kUser, accounts[0].principal_name());
646 EXPECT_EQ(kKrb5Conf, accounts[0].krb5conf());
647 EXPECT_EQ(kRenewalSeconds, accounts[0].tgt_renewal_seconds());
648 EXPECT_EQ(kValiditySeconds, accounts[0].tgt_validity_seconds());
649 EXPECT_TRUE(accounts[0].is_managed());
Lutz Justenc5690502019-05-24 17:00:54 +0200650 EXPECT_TRUE(accounts[0].password_was_remembered());
Lutz Justen04afd272019-06-14 16:31:26 +0200651
652 EXPECT_EQ(kUser2, accounts[1].principal_name());
653 EXPECT_FALSE(accounts[1].password_was_remembered());
654 EXPECT_TRUE(accounts[1].use_login_password());
Lutz Justen6f582982019-05-15 10:24:22 +0200655}
656
657// ListAccounts() ignores failures in GetTgtStatus() and loading the config.
658TEST_F(AccountManagerTest, ListAccountsIgnoresFailures) {
Lutz Justen04afd272019-06-14 16:31:26 +0200659 ignore_result(AddAccount());
660 ignore_result(SetConfig());
661 ignore_result(AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200662 EXPECT_TRUE(base::PathExists(krb5cc_path_));
663
664 // Make reading the config fail.
665 EXPECT_TRUE(base::SetPosixFilePermissions(krb5conf_path_, 0));
666
667 // Make GetTgtStatus() fail.
668 krb5_->set_get_tgt_status_error(ERROR_UNKNOWN);
669
670 // ListAccounts() should still work, despite the errors.
671 std::vector<Account> accounts;
672 EXPECT_EQ(ERROR_NONE, manager_->ListAccounts(&accounts));
673 ASSERT_EQ(1u, accounts.size());
674 EXPECT_EQ(kUser, accounts[0].principal_name());
675
676 // The config should not be set since we made reading the file fail.
677 EXPECT_FALSE(accounts[0].has_krb5conf());
678
679 // tgt_*_seconds should not be set since we made GetTgtStatus() fail.
680 EXPECT_FALSE(accounts[0].has_tgt_renewal_seconds());
681 EXPECT_FALSE(accounts[0].has_tgt_validity_seconds());
682}
683
684// GetKerberosFiles returns empty KerberosFiles if there is no credential cache,
685// even if there is a config.
686TEST_F(AccountManagerTest, GetKerberosFilesSucceesWithoutCC) {
Lutz Justen04afd272019-06-14 16:31:26 +0200687 ignore_result(AddAccount());
688 ignore_result(SetConfig());
Lutz Justen6f582982019-05-15 10:24:22 +0200689
690 KerberosFiles files;
691 EXPECT_EQ(ERROR_NONE, manager_->GetKerberosFiles(kUser, &files));
692 EXPECT_FALSE(files.has_krb5cc());
693 EXPECT_FALSE(files.has_krb5conf());
694}
695
696// GetKerberosFiles returns the expected KerberosFiles if there is a credential
697// cache.
698TEST_F(AccountManagerTest, GetKerberosFilesSucceesWithCC) {
Lutz Justen04afd272019-06-14 16:31:26 +0200699 ignore_result(AddAccount());
700 ignore_result(SetConfig());
701 ignore_result(AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200702
703 KerberosFiles files;
704 EXPECT_EQ(ERROR_NONE, manager_->GetKerberosFiles(kUser, &files));
705 EXPECT_FALSE(files.krb5cc().empty());
706 EXPECT_EQ(kKrb5Conf, files.krb5conf());
707}
708
709// Most methods return ERROR_UNKNOWN_PRINCIPAL if called with such a principal.
710TEST_F(AccountManagerTest, MethodsReturnUnknownPrincipal) {
711 KerberosFiles files;
712 EXPECT_EQ(ERROR_UNKNOWN_PRINCIPAL_NAME, manager_->RemoveAccount(kUser));
Lutz Justen04afd272019-06-14 16:31:26 +0200713 EXPECT_EQ(ERROR_UNKNOWN_PRINCIPAL_NAME, SetConfig());
714 EXPECT_EQ(ERROR_UNKNOWN_PRINCIPAL_NAME, AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200715 EXPECT_EQ(ERROR_UNKNOWN_PRINCIPAL_NAME,
716 manager_->GetKerberosFiles(kUser, &files));
717}
718
719// Accounts can be saved to disk and loaded from disk.
720TEST_F(AccountManagerTest, SerializationSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200721 ignore_result(manager_->AddAccount(kUser, kManaged));
722 ignore_result(manager_->AcquireTgt(kUser, kPassword, kDontRememberPassword,
723 kUseLoginPassword));
724
725 ignore_result(manager_->AddAccount(kUser2, kUnmanaged));
726 ignore_result(manager_->AcquireTgt(kUser2, kPassword, kDontRememberPassword,
727 kDontUseLoginPassword));
Lutz Justen6f582982019-05-15 10:24:22 +0200728
729 EXPECT_EQ(ERROR_NONE, manager_->SaveAccounts());
Lutz Justen04afd272019-06-14 16:31:26 +0200730 AccountManager other_manager(
731 storage_dir_.GetPath(), kerberos_files_changed_,
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200732 kerberos_ticket_expiring_, std::make_unique<FakeKrb5Interface>(),
Lutz Justen2d857e12019-07-16 15:58:09 +0200733 std::make_unique<password_provider::FakePasswordProvider>(),
734 metrics_.get());
Lutz Justen6f582982019-05-15 10:24:22 +0200735 other_manager.LoadAccounts();
736 std::vector<Account> accounts;
Lutz Justen82d07ce2019-05-16 10:46:14 +0200737 EXPECT_EQ(ERROR_NONE, other_manager.ListAccounts(&accounts));
Lutz Justen6f582982019-05-15 10:24:22 +0200738 ASSERT_EQ(2u, accounts.size());
739
740 EXPECT_EQ(kUser, accounts[0].principal_name());
741 EXPECT_EQ(kUser2, accounts[1].principal_name());
742
743 EXPECT_TRUE(accounts[0].is_managed());
744 EXPECT_FALSE(accounts[1].is_managed());
745
Lutz Justen04afd272019-06-14 16:31:26 +0200746 EXPECT_TRUE(accounts[0].use_login_password());
747 EXPECT_FALSE(accounts[1].use_login_password());
748
Lutz Justen6f582982019-05-15 10:24:22 +0200749 // TODO(https://crbug.com/952239): Check additional Account properties.
750}
Lutz Justenb7ef5802019-05-14 14:03:20 +0200751
Lutz Justend925d712019-06-27 17:34:00 +0200752// The StartObservingTickets() method triggers KerberosTicketExpiring for
753// expired signals and starts observing valid tickets.
754TEST_F(AccountManagerTest, StartObservingTickets) {
755 krb5_->set_tgt_status(kValidTgt);
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200756 ignore_result(AddAccount());
757 ignore_result(SetConfig());
758 ignore_result(AcquireTgt());
759 EXPECT_EQ(0, kerberos_ticket_expiring_count_[kUser]);
Lutz Justend925d712019-06-27 17:34:00 +0200760 task_runner_->ClearPendingTasks();
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200761
Lutz Justend925d712019-06-27 17:34:00 +0200762 // Fake an expired ticket. Check that KerberosTicketExpiring is triggered, but
763 // no renewal task is scheduled.
764 krb5_->set_tgt_status(kExpiredTgt);
765 manager_->StartObservingTickets();
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200766 EXPECT_EQ(1, kerberos_ticket_expiring_count_[kUser]);
Lutz Justend925d712019-06-27 17:34:00 +0200767 EXPECT_EQ(0, task_runner_->GetPendingTaskCount());
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200768
Lutz Justend925d712019-06-27 17:34:00 +0200769 // Fake a valid ticket. Check that KerberosTicketExpiring is NOT triggered,
770 // but a renewal task is scheduled.
771 krb5_->set_tgt_status(kValidTgt);
772 EXPECT_EQ(0, task_runner_->GetPendingTaskCount());
773 manager_->StartObservingTickets();
774 EXPECT_EQ(1, task_runner_->GetPendingTaskCount());
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200775 EXPECT_EQ(1, kerberos_ticket_expiring_count_[kUser]);
Lutz Justend925d712019-06-27 17:34:00 +0200776 EXPECT_EQ(0, krb5_->renew_tgt_call_count());
777 task_runner_->FastForwardBy(task_runner_->NextPendingTaskDelay());
778 EXPECT_EQ(1, krb5_->renew_tgt_call_count());
779}
780
781// When a TGT is acquired successfully, automatic renewal is scheduled.
782TEST_F(AccountManagerTest, AcquireTgtSchedulesRenewalOnSuccess) {
783 ignore_result(AddAccount());
784
785 krb5_->set_tgt_status(kValidTgt);
786 EXPECT_EQ(0, task_runner_->GetPendingTaskCount());
787 EXPECT_EQ(ERROR_NONE, AcquireTgt());
788 EXPECT_EQ(1, task_runner_->GetPendingTaskCount());
789}
790
791// When a TGT fails to be acquired, no automatic renewal is scheduled.
792TEST_F(AccountManagerTest, AcquireTgtDoesNotScheduleRenewalOnFailure) {
793 ignore_result(AddAccount());
794
795 krb5_->set_tgt_status(kValidTgt);
796 krb5_->set_acquire_tgt_error(ERROR_UNKNOWN);
797 EXPECT_EQ(0, task_runner_->GetPendingTaskCount());
798 EXPECT_EQ(ERROR_UNKNOWN, AcquireTgt());
799 EXPECT_EQ(0, task_runner_->GetPendingTaskCount());
800}
801
802// A scheduled TGT renewal task calls |krb5_->RenewTgt()|.
803TEST_F(AccountManagerTest, AutoRenewalCallsRenewTgt) {
804 krb5_->set_tgt_status(kValidTgt);
805 ignore_result(AddAccount());
806 ignore_result(AcquireTgt());
807 int initial_acquire_tgt_call_count = krb5_->acquire_tgt_call_count();
808
809 // Set some return value for the RenewTgt() call and fast forward to scheduled
810 // renewal task.
811 const ErrorType expected_error = ERROR_UNKNOWN;
812 krb5_->set_renew_tgt_error(expected_error);
813 RunScheduledRenewalTask();
814
815 EXPECT_EQ(initial_acquire_tgt_call_count, krb5_->acquire_tgt_call_count());
816 EXPECT_EQ(expected_error, manager_->last_renew_tgt_error_for_testing());
817}
818
819// A scheduled TGT renewal task calls |krb5_->AcquireTgt()| using the login
820// password if the call to |krb5_->RenewTgt()| fails and the login password was
821// used for the initial AcquireTgt() call.
822TEST_F(AccountManagerTest, AutoRenewalUsesLoginPasswordIfRenewalFails) {
823 krb5_->set_tgt_status(kValidTgt);
824 ignore_result(AddAccount());
825
826 // Acquire TGT with login password.
827 SaveLoginPassword(kPassword);
828 krb5_->set_expected_password(kPassword);
829 EXPECT_EQ(ERROR_NONE,
830 manager_->AcquireTgt(kUser, std::string(), kDontRememberPassword,
831 kUseLoginPassword));
832 int initial_acquire_tgt_call_count = krb5_->acquire_tgt_call_count();
833
834 krb5_->set_renew_tgt_error(ERROR_UNKNOWN);
835 RunScheduledRenewalTask();
836
837 // The scheduled renewal task should have called AcquireTgt() with the login
838 // password and succeeded.
839 EXPECT_EQ(initial_acquire_tgt_call_count + 1,
840 krb5_->acquire_tgt_call_count());
841 EXPECT_EQ(ERROR_NONE, manager_->last_renew_tgt_error_for_testing());
842}
843
844// A scheduled TGT renewal task calls |krb5_->AcquireTgt()| using the remembered
845// password if the call to |krb5_->RenewTgt()| fails and the password was
846// remembered for the initial AcquireTgt() call.
847TEST_F(AccountManagerTest, AutoRenewalUsesRememberedPasswordIfRenewalFails) {
848 krb5_->set_tgt_status(kValidTgt);
849 ignore_result(AddAccount());
850
851 // Acquire TGT and remember password.
852 krb5_->set_expected_password(kPassword);
853 EXPECT_EQ(ERROR_NONE,
854 manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
855 kDontUseLoginPassword));
856 int initial_acquire_tgt_call_count = krb5_->acquire_tgt_call_count();
857
858 krb5_->set_renew_tgt_error(ERROR_UNKNOWN);
859 RunScheduledRenewalTask();
860
861 // The scheduled renewal task should have called AcquireTgt() with the
862 // remembered password and succeeded.
863 EXPECT_EQ(initial_acquire_tgt_call_count + 1,
864 krb5_->acquire_tgt_call_count());
865 EXPECT_EQ(ERROR_NONE, manager_->last_renew_tgt_error_for_testing());
866}
867
868// A scheduled TGT renewal task does not call |krb5_->AcquireTgt()| using the
869// remembered password if the call to |krb5_->RenewTgt()| succeeds and the
870// password was remembered for the initial AcquireTgt() call (similar for login
871// password, but we don't test that).
872TEST_F(AccountManagerTest, AutoRenewalDoesNotCallAcquireTgtIfRenewalSucceeds) {
873 krb5_->set_tgt_status(kValidTgt);
874 ignore_result(AddAccount());
875
876 // Acquire TGT and remember password.
877 krb5_->set_expected_password(kPassword);
878 EXPECT_EQ(ERROR_NONE,
879 manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
880 kDontUseLoginPassword));
881 int initial_acquire_tgt_call_count = krb5_->acquire_tgt_call_count();
882
883 krb5_->set_renew_tgt_error(ERROR_NONE);
884 RunScheduledRenewalTask();
885
886 // The scheduled renewal task should NOT have called AcquireTgt() again since
887 // |krb5_->RenewTgt()|.
888 EXPECT_EQ(initial_acquire_tgt_call_count, krb5_->acquire_tgt_call_count());
889 EXPECT_EQ(ERROR_NONE, manager_->last_renew_tgt_error_for_testing());
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200890}
891
Lutz Justen33601802019-07-03 22:40:57 +0200892// Verifies that all files written have the expected access permissions.
893// Unfortunately, file ownership can't be tested as the test won't run as
894// kerberosd user nor can it switch to it.
895TEST_F(AccountManagerTest, FilePermissions) {
896 constexpr int kFileMode_rw =
897 base::FILE_PERMISSION_READ_BY_USER | base::FILE_PERMISSION_WRITE_BY_USER;
898 constexpr int kFileMode_rw_r =
899 kFileMode_rw | base::FILE_PERMISSION_READ_BY_GROUP;
900 constexpr int kFileMode_rw_r__r =
901 kFileMode_rw_r | base::FILE_PERMISSION_READ_BY_OTHERS;
902 constexpr int kFileMode_rwxrwx =
903 base::FILE_PERMISSION_USER_MASK | base::FILE_PERMISSION_GROUP_MASK;
904
905 // Wrap the fake krb5 in a jail wrapper to get the file permissions of krb5cc
906 // right. Note that we can't use a Krb5JailWrapper for the whole test since
907 // that would break the counters in FakeKrb5Interface (they would be inc'ed in
908 // another process!).
909 manager_->WrapKrb5ForTesting();
910
911 // Can't set user in this test.
912 Krb5JailWrapper::DisableChangeUserForTesting(true);
913
914 EXPECT_EQ(ERROR_NONE, AddAccount());
915 EXPECT_EQ(ERROR_NONE, SetConfig());
916 EXPECT_EQ(ERROR_NONE,
917 manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
918 kDontUseLoginPassword));
919
920 int mode;
921
922 EXPECT_TRUE(GetPosixFilePermissions(accounts_path_, &mode));
923 EXPECT_EQ(kFileMode_rw, mode);
924
925 EXPECT_TRUE(GetPosixFilePermissions(account_dir_, &mode));
926 EXPECT_EQ(kFileMode_rwxrwx, mode);
927
928 EXPECT_TRUE(GetPosixFilePermissions(krb5cc_path_, &mode));
929 EXPECT_EQ(kFileMode_rw_r, mode);
930
931 EXPECT_TRUE(GetPosixFilePermissions(krb5conf_path_, &mode));
932 EXPECT_EQ(kFileMode_rw_r__r, mode);
933
934 EXPECT_TRUE(GetPosixFilePermissions(password_path_, &mode));
935 EXPECT_EQ(kFileMode_rw, mode);
936}
937
Lutz Justen2d857e12019-07-16 15:58:09 +0200938// Tests that [Should]ReportDailyUsageStats is called as advertised.
939TEST_F(AccountManagerTest, ReportDailyUsageStats) {
940 // ShouldReportDailyUsageStats() should be called by GetKerberosFiles() even
941 // if there is no account, and if that returns true, ReportDailyUsageStats()
942 // should be called as well.
943 EXPECT_CALL(*metrics_, ShouldReportDailyUsageStats()).WillOnce(Return(true));
944 EXPECT_CALL(*metrics_, ReportDailyUsageStats(0, 0, 0, 0, 0));
945 KerberosFiles files;
946 EXPECT_EQ(ERROR_UNKNOWN_PRINCIPAL_NAME,
947 manager_->GetKerberosFiles(kUser, &files));
948 Mock::VerifyAndClearExpectations(metrics_.get());
949
950 AddAccount();
951
952 // ShouldReportDailyUsageStats() should be called by AcquireTgt(), but if that
953 // returns false, ReportDailyUsageStats() should NOT be called.
954 EXPECT_CALL(*metrics_, ShouldReportDailyUsageStats()).WillOnce(Return(false));
955 EXPECT_CALL(*metrics_, ReportDailyUsageStats(_, _, _, _, _)).Times(0);
956 AcquireTgt();
957 Mock::VerifyAndClearExpectations(metrics_.get());
958
959 // ShouldReportDailyUsageStats() should be called by AcquireTgt(), and if that
960 // returns true, ReportDailyUsageStats() should be called as well.
961 EXPECT_CALL(*metrics_, ShouldReportDailyUsageStats()).WillOnce(Return(true));
962 EXPECT_CALL(*metrics_, ReportDailyUsageStats(_, _, _, _, _));
963 AcquireTgt();
964 Mock::VerifyAndClearExpectations(metrics_.get());
965}
966
967TEST_F(AccountManagerTest, AccountStats) {
968 SaveLoginPassword(kPassword);
969
970 EXPECT_EQ(ERROR_NONE, manager_->AddAccount(kUser, kManaged));
971 EXPECT_EQ(ERROR_NONE, manager_->AddAccount(kUser2, kManaged));
972 EXPECT_EQ(ERROR_NONE, manager_->AddAccount(kUser3, kUnmanaged));
973
974 // Set metrics up so that the stats are reported on the last call.
975 EXPECT_CALL(*metrics_, ShouldReportDailyUsageStats())
976 .WillOnce(Return(false))
977 .WillOnce(Return(false))
978 .WillOnce(Return(true));
979
980 // 3 accounts total, 2 managed, 1 unmanaged, 1 remembering the password, 1
981 // using the login password.
982 EXPECT_CALL(*metrics_, ReportDailyUsageStats(3, 2, 1, 1, 1));
983
984 EXPECT_EQ(ERROR_NONE,
985 manager_->AcquireTgt(kUser, kPassword, kDontRememberPassword,
986 kDontUseLoginPassword));
987 EXPECT_EQ(ERROR_NONE,
988 manager_->AcquireTgt(kUser2, kPassword, kRememberPassword,
989 kDontUseLoginPassword));
990 EXPECT_EQ(ERROR_NONE,
991 manager_->AcquireTgt(kUser3, kEmptyPassword, kDontRememberPassword,
992 kUseLoginPassword));
993}
994
Lutz Justenb7ef5802019-05-14 14:03:20 +0200995} // namespace kerberos