blob: 3e97d06fbd9981ea01c149d9b2e3ac641e927dd2 [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]
Felipe Andrade66aaf6b2020-03-24 13:05:57 +010041 forwardable = true)";
42constexpr char kStrongKrb5Conf[] = R"(
43 [libdefaults]
44 forwardable = true
45 default_tkt_enctypes = aes256-cts-hmac-sha1-96
46 default_tgs_enctypes = aes256-cts-hmac-sha1-96
47 permitted_enctypes = aes256-cts-hmac-sha1-96)";
48constexpr char kLegacyKrb5Conf[] = R"(
49 [libdefaults]
50 forwardable = true
51 default_tkt_enctypes = arcfour-hmac
52 default_tgs_enctypes = arcfour-hmac
53 permitted_enctypes = arcfour-hmac)";
Lutz Justen6f582982019-05-15 10:24:22 +020054
Lutz Justend925d712019-06-27 17:34:00 +020055constexpr Krb5Interface::TgtStatus kValidTgt(3600, 3600);
56constexpr Krb5Interface::TgtStatus kExpiredTgt(0, 0);
57
Lutz Justen04afd272019-06-14 16:31:26 +020058// Convenience defines to make code more readable
59constexpr bool kManaged = true;
60constexpr bool kUnmanaged = false;
61
62constexpr bool kRememberPassword = true;
63constexpr bool kDontRememberPassword = false;
64
65constexpr bool kUseLoginPassword = true;
66constexpr bool kDontUseLoginPassword = false;
67
68constexpr char kEmptyPassword[] = "";
69
Lutz Justen2d857e12019-07-16 15:58:09 +020070class MockMetrics : public KerberosMetrics {
71 public:
72 explicit MockMetrics(const base::FilePath& storage_dir)
73 : KerberosMetrics(storage_dir) {}
74 ~MockMetrics() override = default;
75
Ben Chan60470012019-09-24 14:01:54 -070076 MOCK_METHOD(bool, ShouldReportDailyUsageStats, (), (override));
77 MOCK_METHOD(void,
78 ReportDailyUsageStats,
79 (int, int, int, int, int),
80 (override));
Felipe Andrade66aaf6b2020-03-24 13:05:57 +010081 MOCK_METHOD(void,
82 ReportKerberosEncryptionTypes,
83 (KerberosEncryptionTypes),
84 (override));
Lutz Justen2d857e12019-07-16 15:58:09 +020085
86 private:
87 DISALLOW_COPY_AND_ASSIGN(MockMetrics);
88};
89
Lutz Justen6f582982019-05-15 10:24:22 +020090} // namespace
Lutz Justenb7ef5802019-05-14 14:03:20 +020091
Lutz Justenb7ef5802019-05-14 14:03:20 +020092class AccountManagerTest : public ::testing::Test {
93 public:
Lutz Justen6f582982019-05-15 10:24:22 +020094 AccountManagerTest()
95 : kerberos_files_changed_(
96 base::BindRepeating(&AccountManagerTest::OnKerberosFilesChanged,
Lutz Justen8eeb4a22019-06-19 17:00:32 +020097 base::Unretained(this))),
98 kerberos_ticket_expiring_(
99 base::BindRepeating(&AccountManagerTest::OnKerberosTicketExpiring,
Lutz Justen6f582982019-05-15 10:24:22 +0200100 base::Unretained(this))) {}
Lutz Justenb7ef5802019-05-14 14:03:20 +0200101 ~AccountManagerTest() override = default;
102
103 void SetUp() override {
104 ::testing::Test::SetUp();
105
106 // Create temp directory for files written during tests.
107 CHECK(storage_dir_.CreateUniqueTempDir());
Lutz Justen6f582982019-05-15 10:24:22 +0200108 accounts_path_ = storage_dir_.GetPath().Append("accounts");
Lutz Justen33601802019-07-03 22:40:57 +0200109 account_dir_ = storage_dir_.GetPath().Append(
Lutz Justenc5690502019-05-24 17:00:54 +0200110 AccountManager::GetSafeFilenameForTesting(kUser));
Lutz Justen33601802019-07-03 22:40:57 +0200111 krb5cc_path_ = account_dir_.Append("krb5cc");
112 krb5conf_path_ = account_dir_.Append("krb5.conf");
113 password_path_ = account_dir_.Append("password");
Lutz Justenb7ef5802019-05-14 14:03:20 +0200114
Lutz Justen6f582982019-05-15 10:24:22 +0200115 // Create the manager with a fake krb5 interface.
116 auto krb5 = std::make_unique<FakeKrb5Interface>();
Lutz Justen04afd272019-06-14 16:31:26 +0200117 auto password_provider =
118 std::make_unique<password_provider::FakePasswordProvider>();
Lutz Justen2d857e12019-07-16 15:58:09 +0200119 metrics_ = std::make_unique<NiceMock<MockMetrics>>(storage_dir_.GetPath());
Lutz Justen6f582982019-05-15 10:24:22 +0200120 krb5_ = krb5.get();
Lutz Justen04afd272019-06-14 16:31:26 +0200121 password_provider_ = password_provider.get();
Lutz Justenb7ef5802019-05-14 14:03:20 +0200122 manager_ = std::make_unique<AccountManager>(
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200123 storage_dir_.GetPath(), kerberos_files_changed_,
124 kerberos_ticket_expiring_, std::move(krb5),
Lutz Justen2d857e12019-07-16 15:58:09 +0200125 std::move(password_provider), metrics_.get());
Lutz Justenb7ef5802019-05-14 14:03:20 +0200126 }
127
Lutz Justen82d07ce2019-05-16 10:46:14 +0200128 void TearDown() override {
129 // Make sure the file stored on disk contains the same accounts as the
130 // manager instance. This catches cases where AccountManager forgets to save
131 // accounts on some change.
132 if (base::PathExists(accounts_path_)) {
Felipe Andrade89399f02019-11-11 15:52:14 +0100133 std::vector<Account> accounts = manager_->ListAccounts();
Lutz Justen82d07ce2019-05-16 10:46:14 +0200134
Lutz Justen04afd272019-06-14 16:31:26 +0200135 AccountManager other_manager(
136 storage_dir_.GetPath(), kerberos_files_changed_,
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200137 kerberos_ticket_expiring_, std::make_unique<FakeKrb5Interface>(),
Lutz Justen2d857e12019-07-16 15:58:09 +0200138 std::make_unique<password_provider::FakePasswordProvider>(),
139 metrics_.get());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200140 other_manager.LoadAccounts();
Felipe Andrade89399f02019-11-11 15:52:14 +0100141 std::vector<Account> other_accounts = other_manager.ListAccounts();
Lutz Justen82d07ce2019-05-16 10:46:14 +0200142
143 ASSERT_NO_FATAL_FAILURE(ExpectAccountsEqual(accounts, other_accounts));
144 }
145
146 ::testing::Test::TearDown();
147 }
148
Lutz Justen04afd272019-06-14 16:31:26 +0200149 // Add account with default settings.
150 ErrorType AddAccount() { return manager_->AddAccount(kUser, kUnmanaged); }
151
152 // Sets some default Kerberos configuration.
Felipe Andrade66aaf6b2020-03-24 13:05:57 +0100153 ErrorType SetConfig() { return SetConfig(kKrb5Conf); }
154
155 // Sets Kerberos configuration.
156 ErrorType SetConfig(const std::string& config) {
157 return manager_->SetConfig(kUser, config);
158 }
Lutz Justen04afd272019-06-14 16:31:26 +0200159
160 // Acquire Kerberos ticket with default credentials and settings.
161 ErrorType AcquireTgt() {
162 return manager_->AcquireTgt(kUser, kPassword, kDontRememberPassword,
163 kDontUseLoginPassword);
164 }
165
166 void SaveLoginPassword(const char* password) {
167 auto password_ptr = password_provider::test::CreatePassword(password);
168 password_provider_->SavePassword(*password_ptr);
169 }
170
Lutz Justend925d712019-06-27 17:34:00 +0200171 // Fast forwards to the next scheduled task (assumed to be the renewal task)
172 // and verifies expectation that |krb5_->RenewTgt() was called|.
173 void RunScheduledRenewalTask() {
174 int initial_count = krb5_->renew_tgt_call_count();
175 EXPECT_EQ(1, task_runner_->GetPendingTaskCount());
176 task_runner_->FastForwardBy(task_runner_->NextPendingTaskDelay());
177 EXPECT_EQ(initial_count + 1, krb5_->renew_tgt_call_count());
178 }
179
Lutz Justenb7ef5802019-05-14 14:03:20 +0200180 protected:
181 void OnKerberosFilesChanged(const std::string& principal_name) {
182 kerberos_files_changed_count_[principal_name]++;
183 }
184
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200185 void OnKerberosTicketExpiring(const std::string& principal_name) {
186 kerberos_ticket_expiring_count_[principal_name]++;
187 }
188
Lutz Justen82d07ce2019-05-16 10:46:14 +0200189 void ExpectAccountsEqual(const std::vector<Account>& account_list_1,
190 const std::vector<Account>& account_list_2) {
191 ASSERT_EQ(account_list_1.size(), account_list_2.size());
192 for (size_t n = 0; n < account_list_1.size(); ++n) {
193 const Account& account1 = account_list_1[n];
194 const Account& account2 = account_list_2[n];
195
196 EXPECT_EQ(account1.principal_name(), account2.principal_name());
197 EXPECT_EQ(account1.is_managed(), account2.is_managed());
Lutz Justen04afd272019-06-14 16:31:26 +0200198 EXPECT_EQ(account1.use_login_password(), account2.use_login_password());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200199 // TODO(https://crbug.com/952239): Check additional properties.
200 }
201 }
202
Lutz Justenb7ef5802019-05-14 14:03:20 +0200203 std::unique_ptr<AccountManager> manager_;
Lutz Justen6f582982019-05-15 10:24:22 +0200204
Lutz Justen04afd272019-06-14 16:31:26 +0200205 // Fake Kerberos interface used by |manager_|. Not owned.
Lutz Justen6f582982019-05-15 10:24:22 +0200206 FakeKrb5Interface* krb5_;
207
Lutz Justen04afd272019-06-14 16:31:26 +0200208 // Fake password provider to get the login password. Not owned.
209 password_provider::FakePasswordProvider* password_provider_;
210
Lutz Justen2d857e12019-07-16 15:58:09 +0200211 // Mock metrics for testing UMA stat recording.
212 std::unique_ptr<NiceMock<MockMetrics>> metrics_;
213
Lutz Justen6f582982019-05-15 10:24:22 +0200214 // Paths of files stored by |manager_|.
Lutz Justenb7ef5802019-05-14 14:03:20 +0200215 base::ScopedTempDir storage_dir_;
Lutz Justen6f582982019-05-15 10:24:22 +0200216 base::FilePath accounts_path_;
Lutz Justen33601802019-07-03 22:40:57 +0200217 base::FilePath account_dir_;
Lutz Justen6f582982019-05-15 10:24:22 +0200218 base::FilePath krb5conf_path_;
219 base::FilePath krb5cc_path_;
Lutz Justenc5690502019-05-24 17:00:54 +0200220 base::FilePath password_path_;
Lutz Justen6f582982019-05-15 10:24:22 +0200221
222 AccountManager::KerberosFilesChangedCallback kerberos_files_changed_;
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200223 AccountManager::KerberosTicketExpiringCallback kerberos_ticket_expiring_;
224
Lutz Justenb7ef5802019-05-14 14:03:20 +0200225 std::map<std::string, int> kerberos_files_changed_count_;
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200226 std::map<std::string, int> kerberos_ticket_expiring_count_;
Lutz Justenb7ef5802019-05-14 14:03:20 +0200227
Lutz Justend925d712019-06-27 17:34:00 +0200228 scoped_refptr<base::TestMockTimeTaskRunner> task_runner_{
229 new base::TestMockTimeTaskRunner()};
230 base::TestMockTimeTaskRunner::ScopedContext scoped_context_{task_runner_};
231
Lutz Justenb7ef5802019-05-14 14:03:20 +0200232 private:
233 DISALLOW_COPY_AND_ASSIGN(AccountManagerTest);
234};
235
Lutz Justen6f582982019-05-15 10:24:22 +0200236// Adding an account succeeds and serializes the file on disk.
Lutz Justenb7ef5802019-05-14 14:03:20 +0200237TEST_F(AccountManagerTest, AddAccountSuccess) {
Lutz Justen6f582982019-05-15 10:24:22 +0200238 EXPECT_FALSE(base::PathExists(accounts_path_));
Lutz Justen04afd272019-06-14 16:31:26 +0200239 EXPECT_EQ(ERROR_NONE, AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200240 EXPECT_TRUE(base::PathExists(accounts_path_));
Lutz Justenb7ef5802019-05-14 14:03:20 +0200241}
242
Lutz Justen6f582982019-05-15 10:24:22 +0200243// AddAccount() fails if the same account is added twice.
Lutz Justenb7ef5802019-05-14 14:03:20 +0200244TEST_F(AccountManagerTest, AddDuplicateAccountFail) {
Lutz Justen04afd272019-06-14 16:31:26 +0200245 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200246
247 EXPECT_TRUE(base::DeleteFile(accounts_path_, false /* recursive */));
Lutz Justen04afd272019-06-14 16:31:26 +0200248 EXPECT_EQ(ERROR_DUPLICATE_PRINCIPAL_NAME, AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200249 EXPECT_FALSE(base::PathExists(accounts_path_));
Lutz Justenb7ef5802019-05-14 14:03:20 +0200250}
251
Lutz Justen6f582982019-05-15 10:24:22 +0200252// Adding a managed account overwrites an existing unmanaged account.
253TEST_F(AccountManagerTest, ManagedOverridesUnmanaged) {
Lutz Justen04afd272019-06-14 16:31:26 +0200254 ignore_result(manager_->AddAccount(kUser, kUnmanaged));
Lutz Justen6f582982019-05-15 10:24:22 +0200255
Lutz Justen04afd272019-06-14 16:31:26 +0200256 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200257 EXPECT_TRUE(base::PathExists(krb5cc_path_));
258
259 // Overwriting with a managed account should wipe existing files and make the
260 // account managed.
Lutz Justen6f582982019-05-15 10:24:22 +0200261 EXPECT_EQ(ERROR_DUPLICATE_PRINCIPAL_NAME,
Lutz Justen04afd272019-06-14 16:31:26 +0200262 manager_->AddAccount(kUser, kManaged));
Lutz Justen82d07ce2019-05-16 10:46:14 +0200263 EXPECT_FALSE(base::PathExists(krb5cc_path_));
264
Felipe Andrade89399f02019-11-11 15:52:14 +0100265 std::vector<Account> accounts = manager_->ListAccounts();
Lutz Justen6f582982019-05-15 10:24:22 +0200266 ASSERT_EQ(1u, accounts.size());
267 EXPECT_TRUE(accounts[0].is_managed());
268}
269
270// Adding an unmanaged account does not overwrite an existing managed account.
271TEST_F(AccountManagerTest, UnmanagedDoesNotOverrideManaged) {
Lutz Justen04afd272019-06-14 16:31:26 +0200272 ignore_result(manager_->AddAccount(kUser, kManaged));
Lutz Justen6f582982019-05-15 10:24:22 +0200273
274 EXPECT_EQ(ERROR_DUPLICATE_PRINCIPAL_NAME,
Lutz Justen04afd272019-06-14 16:31:26 +0200275 manager_->AddAccount(kUser, kUnmanaged));
Felipe Andrade89399f02019-11-11 15:52:14 +0100276 std::vector<Account> accounts = manager_->ListAccounts();
Lutz Justen6f582982019-05-15 10:24:22 +0200277 ASSERT_EQ(1u, accounts.size());
278 EXPECT_TRUE(accounts[0].is_managed());
279}
280
281// RemoveAccount() succeeds if the account exists and serializes the file on
282// disk.
Lutz Justenb7ef5802019-05-14 14:03:20 +0200283TEST_F(AccountManagerTest, RemoveAccountSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200284 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200285
286 EXPECT_TRUE(base::DeleteFile(accounts_path_, false /* recursive */));
Lutz Justenb7ef5802019-05-14 14:03:20 +0200287 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
Lutz Justen6f582982019-05-15 10:24:22 +0200288 EXPECT_TRUE(base::PathExists(accounts_path_));
Lutz Justenb7ef5802019-05-14 14:03:20 +0200289}
290
Lutz Justen6f582982019-05-15 10:24:22 +0200291// RemoveAccount() fails if the account does not exist.
Lutz Justenb7ef5802019-05-14 14:03:20 +0200292TEST_F(AccountManagerTest, RemoveUnknownAccountFail) {
293 EXPECT_EQ(ERROR_UNKNOWN_PRINCIPAL_NAME, manager_->RemoveAccount(kUser));
Lutz Justen6f582982019-05-15 10:24:22 +0200294 EXPECT_FALSE(base::PathExists(accounts_path_));
295}
296
297// RemoveAccount() does not trigger KerberosFilesChanged if the credential cache
298// does not exists.
299TEST_F(AccountManagerTest, RemoveAccountTriggersKFCIfCCExists) {
Lutz Justen04afd272019-06-14 16:31:26 +0200300 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200301
302 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
303 EXPECT_EQ(0, kerberos_files_changed_count_[kUser]);
304}
305
306// RemoveAccount() triggers KerberosFilesChanged if the credential cache exists.
307TEST_F(AccountManagerTest, RemoveAccountDoesNotTriggerKFCIfCCDoesNotExist) {
Lutz Justen04afd272019-06-14 16:31:26 +0200308 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200309
Lutz Justen04afd272019-06-14 16:31:26 +0200310 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200311 EXPECT_EQ(1, kerberos_files_changed_count_[kUser]);
312 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
313 EXPECT_EQ(2, kerberos_files_changed_count_[kUser]);
Lutz Justenb7ef5802019-05-14 14:03:20 +0200314}
315
316// Repeatedly calling AddAccount() and RemoveAccount() succeeds.
317TEST_F(AccountManagerTest, RepeatedAddRemoveSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200318 ignore_result(AddAccount());
Lutz Justenb7ef5802019-05-14 14:03:20 +0200319 ignore_result(manager_->RemoveAccount(kUser));
Lutz Justen6f582982019-05-15 10:24:22 +0200320
Lutz Justen04afd272019-06-14 16:31:26 +0200321 EXPECT_EQ(ERROR_NONE, AddAccount());
Lutz Justenb7ef5802019-05-14 14:03:20 +0200322 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
323}
324
Lutz Justen2d420872019-06-25 14:17:21 +0200325// ClearAccounts(CLEAR_ALL) clears all accounts.
326TEST_F(AccountManagerTest, ClearAccountsSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200327 ignore_result(manager_->AddAccount(kUser, kUnmanaged));
328 ignore_result(manager_->AddAccount(kUser2, kManaged));
Lutz Justen82d07ce2019-05-16 10:46:14 +0200329
Lutz Justen781825e2019-07-13 07:49:44 +0200330 EXPECT_EQ(ERROR_NONE, manager_->ClearAccounts(CLEAR_ALL, {}));
Felipe Andrade89399f02019-11-11 15:52:14 +0100331 std::vector<Account> accounts = manager_->ListAccounts();
Lutz Justen82d07ce2019-05-16 10:46:14 +0200332 EXPECT_EQ(0u, accounts.size());
333}
334
Lutz Justen2d420872019-06-25 14:17:21 +0200335// ClearAccounts(CLEAR_ALL) wipes Kerberos configuration and credential cache.
336TEST_F(AccountManagerTest, ClearAccountsRemovesKerberosFiles) {
Lutz Justen04afd272019-06-14 16:31:26 +0200337 ignore_result(AddAccount());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200338
Lutz Justen04afd272019-06-14 16:31:26 +0200339 EXPECT_EQ(ERROR_NONE, SetConfig());
340 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200341 EXPECT_TRUE(base::PathExists(krb5conf_path_));
342 EXPECT_TRUE(base::PathExists(krb5cc_path_));
Lutz Justen781825e2019-07-13 07:49:44 +0200343 EXPECT_EQ(ERROR_NONE, manager_->ClearAccounts(CLEAR_ALL, {}));
Lutz Justen82d07ce2019-05-16 10:46:14 +0200344 EXPECT_FALSE(base::PathExists(krb5conf_path_));
345 EXPECT_FALSE(base::PathExists(krb5cc_path_));
346}
347
Lutz Justen2d420872019-06-25 14:17:21 +0200348// ClearAccounts(CLEAR_ALL) triggers KerberosFilesChanged if the credential
349// cache exists.
350TEST_F(AccountManagerTest, ClearAccountsTriggersKFCIfCCExists) {
Lutz Justen04afd272019-06-14 16:31:26 +0200351 ignore_result(AddAccount());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200352
Lutz Justen04afd272019-06-14 16:31:26 +0200353 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200354 EXPECT_EQ(1, kerberos_files_changed_count_[kUser]);
Lutz Justen781825e2019-07-13 07:49:44 +0200355 EXPECT_EQ(ERROR_NONE, manager_->ClearAccounts(CLEAR_ALL, {}));
Lutz Justen82d07ce2019-05-16 10:46:14 +0200356 EXPECT_EQ(2, kerberos_files_changed_count_[kUser]);
357}
358
Lutz Justen2d420872019-06-25 14:17:21 +0200359// ClearAccounts(CLEAR_ALL) does not trigger KerberosFilesChanged if the
360// credential cache does not exist.
361TEST_F(AccountManagerTest, ClearAccountsDoesNotTriggerKFCIfDoesNotCCExist) {
Lutz Justen04afd272019-06-14 16:31:26 +0200362 ignore_result(AddAccount());
Lutz Justen82d07ce2019-05-16 10:46:14 +0200363
Lutz Justen781825e2019-07-13 07:49:44 +0200364 EXPECT_EQ(ERROR_NONE, manager_->ClearAccounts(CLEAR_ALL, {}));
Lutz Justen82d07ce2019-05-16 10:46:14 +0200365 EXPECT_EQ(0, kerberos_files_changed_count_[kUser]);
366}
367
Lutz Justen2d420872019-06-25 14:17:21 +0200368// ClearAccounts(CLEAR_ONLY_UNMANAGED_ACCOUNTS) clears only unmanaged accounts.
369TEST_F(AccountManagerTest, ClearUnmanagedAccountsSuccess) {
370 ignore_result(manager_->AddAccount(kUser, kUnmanaged));
371 ignore_result(manager_->AddAccount(kUser2, kManaged));
372
Lutz Justen781825e2019-07-13 07:49:44 +0200373 EXPECT_EQ(ERROR_NONE,
374 manager_->ClearAccounts(CLEAR_ONLY_UNMANAGED_ACCOUNTS, {}));
Felipe Andrade89399f02019-11-11 15:52:14 +0100375 std::vector<Account> accounts = manager_->ListAccounts();
Lutz Justen2d420872019-06-25 14:17:21 +0200376 ASSERT_EQ(1u, accounts.size());
377 EXPECT_EQ(kUser2, accounts[0].principal_name());
378}
379
380// ClearAccounts(CLEAR_ONLY_UNMANAGED_REMEMBERED_PASSWORDS) clears only
381// passwords of unmanaged accounts.
382TEST_F(AccountManagerTest, ClearUnmanagedPasswordsSuccess) {
383 // kUser is unmanaged, kUser2 is managed.
384 ignore_result(manager_->AddAccount(kUser, kUnmanaged));
385 ignore_result(manager_->AddAccount(kUser2, kManaged));
386 ignore_result(manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
387 kDontUseLoginPassword));
388 ignore_result(manager_->AcquireTgt(kUser2, kPassword, kRememberPassword,
389 kDontUseLoginPassword));
390
391 base::FilePath password_path_2 =
392 storage_dir_.GetPath()
393 .Append(AccountManager::GetSafeFilenameForTesting(kUser2))
394 .Append("password");
395 EXPECT_TRUE(base::PathExists(password_path_));
396 EXPECT_TRUE(base::PathExists(password_path_2));
397
Lutz Justen781825e2019-07-13 07:49:44 +0200398 EXPECT_EQ(ERROR_NONE, manager_->ClearAccounts(
399 CLEAR_ONLY_UNMANAGED_REMEMBERED_PASSWORDS, {}));
Felipe Andrade89399f02019-11-11 15:52:14 +0100400 std::vector<Account> accounts = manager_->ListAccounts();
Lutz Justen2d420872019-06-25 14:17:21 +0200401 ASSERT_EQ(2u, accounts.size());
402 EXPECT_FALSE(base::PathExists(password_path_));
403 EXPECT_TRUE(base::PathExists(password_path_2));
404}
405
Lutz Justen781825e2019-07-13 07:49:44 +0200406// ClearAccounts(CLEAR_ONLY_MANAGED_ACCOUNTS) clears only managed accounts that
407// are not on the keep list.
408TEST_F(AccountManagerTest, ClearManagedPasswordsWithKeepListSuccess) {
409 ignore_result(manager_->AddAccount(kUser, kManaged));
410 ignore_result(manager_->AddAccount(kUser2, kManaged));
411 ignore_result(manager_->AddAccount(kUser3, kUnmanaged));
412
413 // Keep the managed kUser-account.
414 EXPECT_EQ(ERROR_NONE,
415 manager_->ClearAccounts(CLEAR_ONLY_MANAGED_ACCOUNTS, {kUser}));
Felipe Andrade89399f02019-11-11 15:52:14 +0100416 std::vector<Account> accounts = manager_->ListAccounts();
Lutz Justen781825e2019-07-13 07:49:44 +0200417 ASSERT_EQ(2u, accounts.size());
418 EXPECT_EQ(kUser, accounts[0].principal_name());
419 EXPECT_EQ(kUser3, accounts[1].principal_name());
420}
421
Lutz Justen6f582982019-05-15 10:24:22 +0200422// SetConfig() succeeds and writes the config to |krb5conf_path_|.
423TEST_F(AccountManagerTest, SetConfigSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200424 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200425
Lutz Justen04afd272019-06-14 16:31:26 +0200426 EXPECT_EQ(ERROR_NONE, SetConfig());
Lutz Justen6f582982019-05-15 10:24:22 +0200427 std::string krb5_conf;
428 EXPECT_TRUE(base::ReadFileToString(krb5conf_path_, &krb5_conf));
429 EXPECT_EQ(krb5_conf, kKrb5Conf);
430}
431
Lutz Justen90281402019-07-05 15:14:37 +0200432// SetConfig() calls ValidateConfig on the Kerberos interface.
433TEST_F(AccountManagerTest, SetConfigValidatesConfig) {
434 ignore_result(AddAccount());
435
436 krb5_->set_validate_config_error(ERROR_BAD_CONFIG);
437 EXPECT_EQ(ERROR_BAD_CONFIG, SetConfig());
438}
439
Lutz Justen6f582982019-05-15 10:24:22 +0200440// SetConfig() triggers KerberosFilesChanged if the credential cache exists.
441TEST_F(AccountManagerTest, SetConfigTriggersKFCIfCCExists) {
Lutz Justen04afd272019-06-14 16:31:26 +0200442 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200443
Lutz Justen04afd272019-06-14 16:31:26 +0200444 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200445 EXPECT_EQ(1, kerberos_files_changed_count_[kUser]);
Lutz Justen04afd272019-06-14 16:31:26 +0200446 EXPECT_EQ(ERROR_NONE, SetConfig());
Lutz Justen6f582982019-05-15 10:24:22 +0200447 EXPECT_EQ(2, kerberos_files_changed_count_[kUser]);
448}
449
Lutz Justen82d07ce2019-05-16 10:46:14 +0200450// SetConfig() does not trigger KerberosFilesChanged if the credential cache
451// does not exist.
Lutz Justen6f582982019-05-15 10:24:22 +0200452TEST_F(AccountManagerTest, SetConfigDoesNotTriggerKFCIfDoesNotCCExist) {
Lutz Justen04afd272019-06-14 16:31:26 +0200453 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200454
Lutz Justen04afd272019-06-14 16:31:26 +0200455 EXPECT_EQ(ERROR_NONE, SetConfig());
Lutz Justen6f582982019-05-15 10:24:22 +0200456 EXPECT_EQ(0, kerberos_files_changed_count_[kUser]);
457}
458
459// RemoveAccount() removes the config file.
460TEST_F(AccountManagerTest, RemoveAccountRemovesConfig) {
Lutz Justen04afd272019-06-14 16:31:26 +0200461 ignore_result(AddAccount());
462 ignore_result(SetConfig());
Lutz Justen6f582982019-05-15 10:24:22 +0200463
464 EXPECT_TRUE(base::PathExists(krb5conf_path_));
465 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
466 EXPECT_FALSE(base::PathExists(krb5conf_path_));
467}
468
Lutz Justen90281402019-07-05 15:14:37 +0200469// ValidateConfig() validates a good config successfully.
470TEST_F(AccountManagerTest, ValidateConfigSuccess) {
471 constexpr char kValidKrb5Conf[] = "";
472 ConfigErrorInfo error_info;
473 EXPECT_EQ(ERROR_NONE, manager_->ValidateConfig(kValidKrb5Conf, &error_info));
474 EXPECT_EQ(CONFIG_ERROR_NONE, error_info.code());
475}
476
477// ValidateConfig() returns the correct error for a bad config.
478TEST_F(AccountManagerTest, ValidateConfigFailure) {
479 ConfigErrorInfo expected_error_info;
480 expected_error_info.set_code(CONFIG_ERROR_SECTION_SYNTAX);
481 krb5_->set_config_error_info(expected_error_info);
482 krb5_->set_validate_config_error(ERROR_BAD_CONFIG);
483
484 constexpr char kBadKrb5Conf[] =
485 "[libdefaults]'); DROP TABLE KerberosTickets;--";
486 ConfigErrorInfo error_info;
487 EXPECT_EQ(ERROR_BAD_CONFIG,
488 manager_->ValidateConfig(kBadKrb5Conf, &error_info));
489 EXPECT_EQ(expected_error_info.SerializeAsString(),
490 error_info.SerializeAsString());
491}
492
Lutz Justen6f582982019-05-15 10:24:22 +0200493// AcquireTgt() succeeds and writes a credential cache file.
494TEST_F(AccountManagerTest, AcquireTgtSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200495 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200496
Lutz Justen04afd272019-06-14 16:31:26 +0200497 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200498 EXPECT_TRUE(base::PathExists(krb5cc_path_));
499}
500
501// AcquireTgt() triggers KerberosFilesChanged on success.
502TEST_F(AccountManagerTest, AcquireTgtTriggersKFCOnSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200503 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200504
505 EXPECT_EQ(0, kerberos_files_changed_count_[kUser]);
Lutz Justen04afd272019-06-14 16:31:26 +0200506 EXPECT_EQ(ERROR_NONE, AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200507 EXPECT_EQ(1, kerberos_files_changed_count_[kUser]);
508}
509
510// AcquireTgt() does not trigger KerberosFilesChanged on failure.
511TEST_F(AccountManagerTest, AcquireTgtDoesNotTriggerKFCOnFailure) {
Lutz Justen04afd272019-06-14 16:31:26 +0200512 ignore_result(AddAccount());
Lutz Justen6f582982019-05-15 10:24:22 +0200513
514 krb5_->set_acquire_tgt_error(ERROR_UNKNOWN);
Lutz Justen04afd272019-06-14 16:31:26 +0200515 EXPECT_EQ(ERROR_UNKNOWN, AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200516 EXPECT_EQ(0, kerberos_files_changed_count_[kUser]);
517}
518
Lutz Justenc5690502019-05-24 17:00:54 +0200519// AcquireTgt() saves password to disk if |remember_password| is true and
520// removes the file again if |remember_password| is false.
521TEST_F(AccountManagerTest, AcquireTgtRemembersPasswordsIfWanted) {
Lutz Justen04afd272019-06-14 16:31:26 +0200522 ignore_result(AddAccount());
Lutz Justenc5690502019-05-24 17:00:54 +0200523
524 EXPECT_FALSE(base::PathExists(password_path_));
Lutz Justen04afd272019-06-14 16:31:26 +0200525 EXPECT_EQ(ERROR_NONE,
526 manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
527 kDontUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200528 EXPECT_TRUE(base::PathExists(password_path_));
529
Lutz Justen04afd272019-06-14 16:31:26 +0200530 EXPECT_EQ(ERROR_NONE,
531 manager_->AcquireTgt(kUser, kPassword, kDontRememberPassword,
532 kDontUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200533 EXPECT_FALSE(base::PathExists(password_path_));
534}
535
536// AcquireTgt() uses saved password if none is given, no matter if it should be
537// remembered again or not.
538TEST_F(AccountManagerTest, AcquireTgtLoadsRememberedPassword) {
Lutz Justen04afd272019-06-14 16:31:26 +0200539 ignore_result(AddAccount());
540 ignore_result(manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
541 kDontUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200542
543 // This should load stored password and keep it.
544 EXPECT_EQ(ERROR_NONE,
Lutz Justen04afd272019-06-14 16:31:26 +0200545 manager_->AcquireTgt(kUser, kEmptyPassword, kRememberPassword,
546 kDontUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200547 EXPECT_TRUE(base::PathExists(password_path_));
548
549 // This should load stored password, but erase it afterwards.
550 EXPECT_EQ(ERROR_NONE,
Lutz Justen04afd272019-06-14 16:31:26 +0200551 manager_->AcquireTgt(kUser, kEmptyPassword, kDontRememberPassword,
552 kDontUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200553 EXPECT_FALSE(base::PathExists(password_path_));
554
555 // Check that the fake krb5 interface returns an error for a missing password.
556 // This verifies that the above AcquireTgt() call actually loaded the
557 // password from disk.
558 EXPECT_EQ(ERROR_BAD_PASSWORD,
Lutz Justen04afd272019-06-14 16:31:26 +0200559 manager_->AcquireTgt(kUser, kEmptyPassword, kDontRememberPassword,
560 kDontUseLoginPassword));
561}
562
563// AcquireTgt() uses the login password if saved.
564TEST_F(AccountManagerTest, AcquireTgtUsesLoginPassword) {
565 ignore_result(AddAccount());
566
567 // Shouldn't explode if the login password not set yet.
568 EXPECT_EQ(ERROR_BAD_PASSWORD,
569 manager_->AcquireTgt(kUser, kEmptyPassword, kDontRememberPassword,
570 kUseLoginPassword));
571
572 SaveLoginPassword(kPassword);
573 krb5_->set_expected_password(kPassword);
574
575 // Uses the login password.
576 EXPECT_EQ(ERROR_NONE,
577 manager_->AcquireTgt(kUser, kEmptyPassword, kDontRememberPassword,
578 kUseLoginPassword));
579
580 // Check if auth fails without kUseLoginPassword.
581 EXPECT_EQ(ERROR_BAD_PASSWORD,
582 manager_->AcquireTgt(kUser, kEmptyPassword, kDontRememberPassword,
583 kDontUseLoginPassword));
584}
585
586// AcquireTgt() wipes a saved password if the login password is used.
587TEST_F(AccountManagerTest, AcquireTgtWipesStoredPasswordOnUsesLoginPassword) {
588 ignore_result(AddAccount());
589 ignore_result(manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
590 kDontUseLoginPassword));
591 EXPECT_TRUE(base::PathExists(password_path_));
592
593 SaveLoginPassword(kPassword);
594
595 // Note: kRememberPassword gets ignored if kUseLoginPassword is passed.
596 EXPECT_EQ(ERROR_NONE,
597 manager_->AcquireTgt(kUser, kEmptyPassword, kRememberPassword,
598 kUseLoginPassword));
599 EXPECT_FALSE(base::PathExists(password_path_));
600}
601
602// AcquireTgt() ignores the passed password if the login password is used.
603TEST_F(AccountManagerTest, AcquireTgtIgnoresPassedPasswordOnUsesLoginPassword) {
604 ignore_result(AddAccount());
605
606 SaveLoginPassword(kPassword);
607 krb5_->set_expected_password(kPassword);
608
609 // Auth works despite passed kPassword2 != expected kPassword because the
610 // login kPassword is used.
611 EXPECT_EQ(ERROR_NONE,
612 manager_->AcquireTgt(kUser, kPassword2, kDontRememberPassword,
613 kUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200614}
615
Felipe Andrade66aaf6b2020-03-24 13:05:57 +0100616// AcquireTgt() records all encryption types UMA stats on success.
617TEST_F(AccountManagerTest, AcquireTgtEnctypesMetricsAll) {
618 ignore_result(AddAccount());
619 ignore_result(SetConfig());
620
621 // The expected encryption type should be reported through |metric_|.
622 EXPECT_CALL(*metrics_,
623 ReportKerberosEncryptionTypes(KerberosEncryptionTypes::kAll));
624
625 EXPECT_EQ(ERROR_NONE, AcquireTgt());
626}
627
628// AcquireTgt() records strong encryption types UMA stats on success.
629TEST_F(AccountManagerTest, AcquireTgtEnctypesMetricsStrong) {
630 ignore_result(AddAccount());
631 ignore_result(SetConfig(kStrongKrb5Conf));
632
633 // The expected encryption type should be reported through |metric_|.
634 EXPECT_CALL(*metrics_,
635 ReportKerberosEncryptionTypes(KerberosEncryptionTypes::kStrong));
636
637 EXPECT_EQ(ERROR_NONE, AcquireTgt());
638}
639
640// AcquireTgt() records legacy encryption types UMA stats on success.
641TEST_F(AccountManagerTest, AcquireTgtEnctypesMetricsLegacy) {
642 ignore_result(AddAccount());
643 ignore_result(SetConfig(kLegacyKrb5Conf));
644
645 // The expected encryption type should be reported through |metric_|.
646 EXPECT_CALL(*metrics_,
647 ReportKerberosEncryptionTypes(KerberosEncryptionTypes::kLegacy));
648
649 EXPECT_EQ(ERROR_NONE, AcquireTgt());
650}
651
652// AcquireTgt() doesn't record encryption types UMA stats on failure.
653TEST_F(AccountManagerTest, AcquireTgtEnctypesMetricsFailure) {
654 ignore_result(AddAccount());
655 ignore_result(SetConfig());
656
657 // No encryption type should be reported through |metric_|.
658 EXPECT_CALL(*metrics_, ReportKerberosEncryptionTypes(_)).Times(0);
659
660 krb5_->set_acquire_tgt_error(ERROR_UNKNOWN);
661 EXPECT_EQ(ERROR_UNKNOWN, AcquireTgt());
662}
663
664// AcquireTgt() doesn't record encryption types UMA stats if no config is
665// available.
666TEST_F(AccountManagerTest, AcquireTgtEnctypesMetricsNoConfig) {
667 ignore_result(AddAccount());
668
669 // No encryption type should be reported through |metric_|.
670 EXPECT_CALL(*metrics_, ReportKerberosEncryptionTypes(_)).Times(0);
671
672 EXPECT_EQ(ERROR_NONE, AcquireTgt());
673}
674
Lutz Justen6f582982019-05-15 10:24:22 +0200675// RemoveAccount() removes the credential cache file.
676TEST_F(AccountManagerTest, RemoveAccountRemovesCC) {
Lutz Justen04afd272019-06-14 16:31:26 +0200677 ignore_result(AddAccount());
678 ignore_result(AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200679
680 EXPECT_TRUE(base::PathExists(krb5cc_path_));
681 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
682 EXPECT_FALSE(base::PathExists(krb5cc_path_));
683}
684
Lutz Justenc5690502019-05-24 17:00:54 +0200685// RemoveAccount() removes saved passwords.
686TEST_F(AccountManagerTest, RemoveAccountRemovesPassword) {
Lutz Justen04afd272019-06-14 16:31:26 +0200687 ignore_result(AddAccount());
688 ignore_result(manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
689 kDontUseLoginPassword));
Lutz Justenc5690502019-05-24 17:00:54 +0200690
691 EXPECT_TRUE(base::PathExists(password_path_));
692 EXPECT_EQ(ERROR_NONE, manager_->RemoveAccount(kUser));
693 EXPECT_FALSE(base::PathExists(password_path_));
694}
695
Lutz Justen6f582982019-05-15 10:24:22 +0200696// ListAccounts() succeeds and contains the expected data.
697TEST_F(AccountManagerTest, ListAccountsSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200698 ignore_result(manager_->AddAccount(kUser, kManaged));
699 ignore_result(SetConfig());
700 ignore_result(manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
701 kDontUseLoginPassword));
702 SaveLoginPassword(kPassword);
703 ignore_result(manager_->AddAccount(kUser2, kUnmanaged));
704 // Note: kRememberPassword should be ignored here, see below.
705 ignore_result(manager_->AcquireTgt(kUser2, kPassword, kRememberPassword,
706 kUseLoginPassword));
Lutz Justen6f582982019-05-15 10:24:22 +0200707 EXPECT_TRUE(base::PathExists(krb5cc_path_));
708
709 // Set a fake tgt status.
710 constexpr int kRenewalSeconds = 10;
711 constexpr int kValiditySeconds = 90;
Lutz Justend925d712019-06-27 17:34:00 +0200712 krb5_->set_tgt_status(
713 Krb5Interface::TgtStatus(kValiditySeconds, kRenewalSeconds));
Lutz Justen6f582982019-05-15 10:24:22 +0200714
715 // Verify that ListAccounts returns the expected account.
Felipe Andrade89399f02019-11-11 15:52:14 +0100716 std::vector<Account> accounts = manager_->ListAccounts();
Lutz Justen04afd272019-06-14 16:31:26 +0200717 ASSERT_EQ(2u, accounts.size());
718
Lutz Justen6f582982019-05-15 10:24:22 +0200719 EXPECT_EQ(kUser, accounts[0].principal_name());
720 EXPECT_EQ(kKrb5Conf, accounts[0].krb5conf());
721 EXPECT_EQ(kRenewalSeconds, accounts[0].tgt_renewal_seconds());
722 EXPECT_EQ(kValiditySeconds, accounts[0].tgt_validity_seconds());
723 EXPECT_TRUE(accounts[0].is_managed());
Lutz Justenc5690502019-05-24 17:00:54 +0200724 EXPECT_TRUE(accounts[0].password_was_remembered());
Lutz Justen04afd272019-06-14 16:31:26 +0200725
726 EXPECT_EQ(kUser2, accounts[1].principal_name());
727 EXPECT_FALSE(accounts[1].password_was_remembered());
728 EXPECT_TRUE(accounts[1].use_login_password());
Lutz Justen6f582982019-05-15 10:24:22 +0200729}
730
731// ListAccounts() ignores failures in GetTgtStatus() and loading the config.
732TEST_F(AccountManagerTest, ListAccountsIgnoresFailures) {
Lutz Justen04afd272019-06-14 16:31:26 +0200733 ignore_result(AddAccount());
734 ignore_result(SetConfig());
735 ignore_result(AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200736 EXPECT_TRUE(base::PathExists(krb5cc_path_));
737
738 // Make reading the config fail.
739 EXPECT_TRUE(base::SetPosixFilePermissions(krb5conf_path_, 0));
740
741 // Make GetTgtStatus() fail.
742 krb5_->set_get_tgt_status_error(ERROR_UNKNOWN);
743
744 // ListAccounts() should still work, despite the errors.
Felipe Andrade89399f02019-11-11 15:52:14 +0100745 std::vector<Account> accounts = manager_->ListAccounts();
Lutz Justen6f582982019-05-15 10:24:22 +0200746 ASSERT_EQ(1u, accounts.size());
747 EXPECT_EQ(kUser, accounts[0].principal_name());
748
749 // The config should not be set since we made reading the file fail.
750 EXPECT_FALSE(accounts[0].has_krb5conf());
751
752 // tgt_*_seconds should not be set since we made GetTgtStatus() fail.
753 EXPECT_FALSE(accounts[0].has_tgt_renewal_seconds());
754 EXPECT_FALSE(accounts[0].has_tgt_validity_seconds());
755}
756
757// GetKerberosFiles returns empty KerberosFiles if there is no credential cache,
758// even if there is a config.
Felipe Andrade66aaf6b2020-03-24 13:05:57 +0100759TEST_F(AccountManagerTest, GetKerberosFilesSucceedsWithoutCC) {
Lutz Justen04afd272019-06-14 16:31:26 +0200760 ignore_result(AddAccount());
761 ignore_result(SetConfig());
Lutz Justen6f582982019-05-15 10:24:22 +0200762
763 KerberosFiles files;
764 EXPECT_EQ(ERROR_NONE, manager_->GetKerberosFiles(kUser, &files));
765 EXPECT_FALSE(files.has_krb5cc());
766 EXPECT_FALSE(files.has_krb5conf());
767}
768
769// GetKerberosFiles returns the expected KerberosFiles if there is a credential
770// cache.
Felipe Andrade66aaf6b2020-03-24 13:05:57 +0100771TEST_F(AccountManagerTest, GetKerberosFilesSucceedsWithCC) {
Lutz Justen04afd272019-06-14 16:31:26 +0200772 ignore_result(AddAccount());
773 ignore_result(SetConfig());
774 ignore_result(AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200775
776 KerberosFiles files;
777 EXPECT_EQ(ERROR_NONE, manager_->GetKerberosFiles(kUser, &files));
778 EXPECT_FALSE(files.krb5cc().empty());
779 EXPECT_EQ(kKrb5Conf, files.krb5conf());
780}
781
782// Most methods return ERROR_UNKNOWN_PRINCIPAL if called with such a principal.
783TEST_F(AccountManagerTest, MethodsReturnUnknownPrincipal) {
784 KerberosFiles files;
785 EXPECT_EQ(ERROR_UNKNOWN_PRINCIPAL_NAME, manager_->RemoveAccount(kUser));
Lutz Justen04afd272019-06-14 16:31:26 +0200786 EXPECT_EQ(ERROR_UNKNOWN_PRINCIPAL_NAME, SetConfig());
787 EXPECT_EQ(ERROR_UNKNOWN_PRINCIPAL_NAME, AcquireTgt());
Lutz Justen6f582982019-05-15 10:24:22 +0200788 EXPECT_EQ(ERROR_UNKNOWN_PRINCIPAL_NAME,
789 manager_->GetKerberosFiles(kUser, &files));
790}
791
792// Accounts can be saved to disk and loaded from disk.
793TEST_F(AccountManagerTest, SerializationSuccess) {
Lutz Justen04afd272019-06-14 16:31:26 +0200794 ignore_result(manager_->AddAccount(kUser, kManaged));
795 ignore_result(manager_->AcquireTgt(kUser, kPassword, kDontRememberPassword,
796 kUseLoginPassword));
797
798 ignore_result(manager_->AddAccount(kUser2, kUnmanaged));
799 ignore_result(manager_->AcquireTgt(kUser2, kPassword, kDontRememberPassword,
800 kDontUseLoginPassword));
Lutz Justen6f582982019-05-15 10:24:22 +0200801
802 EXPECT_EQ(ERROR_NONE, manager_->SaveAccounts());
Lutz Justen04afd272019-06-14 16:31:26 +0200803 AccountManager other_manager(
804 storage_dir_.GetPath(), kerberos_files_changed_,
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200805 kerberos_ticket_expiring_, std::make_unique<FakeKrb5Interface>(),
Lutz Justen2d857e12019-07-16 15:58:09 +0200806 std::make_unique<password_provider::FakePasswordProvider>(),
807 metrics_.get());
Lutz Justen6f582982019-05-15 10:24:22 +0200808 other_manager.LoadAccounts();
Felipe Andrade89399f02019-11-11 15:52:14 +0100809 std::vector<Account> accounts = other_manager.ListAccounts();
Lutz Justen6f582982019-05-15 10:24:22 +0200810 ASSERT_EQ(2u, accounts.size());
811
812 EXPECT_EQ(kUser, accounts[0].principal_name());
813 EXPECT_EQ(kUser2, accounts[1].principal_name());
814
815 EXPECT_TRUE(accounts[0].is_managed());
816 EXPECT_FALSE(accounts[1].is_managed());
817
Lutz Justen04afd272019-06-14 16:31:26 +0200818 EXPECT_TRUE(accounts[0].use_login_password());
819 EXPECT_FALSE(accounts[1].use_login_password());
820
Lutz Justen6f582982019-05-15 10:24:22 +0200821 // TODO(https://crbug.com/952239): Check additional Account properties.
822}
Lutz Justenb7ef5802019-05-14 14:03:20 +0200823
Lutz Justend925d712019-06-27 17:34:00 +0200824// The StartObservingTickets() method triggers KerberosTicketExpiring for
825// expired signals and starts observing valid tickets.
826TEST_F(AccountManagerTest, StartObservingTickets) {
827 krb5_->set_tgt_status(kValidTgt);
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200828 ignore_result(AddAccount());
829 ignore_result(SetConfig());
830 ignore_result(AcquireTgt());
831 EXPECT_EQ(0, kerberos_ticket_expiring_count_[kUser]);
Lutz Justend925d712019-06-27 17:34:00 +0200832 task_runner_->ClearPendingTasks();
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200833
Lutz Justend925d712019-06-27 17:34:00 +0200834 // Fake an expired ticket. Check that KerberosTicketExpiring is triggered, but
835 // no renewal task is scheduled.
836 krb5_->set_tgt_status(kExpiredTgt);
837 manager_->StartObservingTickets();
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200838 EXPECT_EQ(1, kerberos_ticket_expiring_count_[kUser]);
Lutz Justend925d712019-06-27 17:34:00 +0200839 EXPECT_EQ(0, task_runner_->GetPendingTaskCount());
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200840
Lutz Justend925d712019-06-27 17:34:00 +0200841 // Fake a valid ticket. Check that KerberosTicketExpiring is NOT triggered,
842 // but a renewal task is scheduled.
843 krb5_->set_tgt_status(kValidTgt);
844 EXPECT_EQ(0, task_runner_->GetPendingTaskCount());
845 manager_->StartObservingTickets();
846 EXPECT_EQ(1, task_runner_->GetPendingTaskCount());
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200847 EXPECT_EQ(1, kerberos_ticket_expiring_count_[kUser]);
Lutz Justend925d712019-06-27 17:34:00 +0200848 EXPECT_EQ(0, krb5_->renew_tgt_call_count());
849 task_runner_->FastForwardBy(task_runner_->NextPendingTaskDelay());
850 EXPECT_EQ(1, krb5_->renew_tgt_call_count());
851}
852
853// When a TGT is acquired successfully, automatic renewal is scheduled.
854TEST_F(AccountManagerTest, AcquireTgtSchedulesRenewalOnSuccess) {
855 ignore_result(AddAccount());
856
857 krb5_->set_tgt_status(kValidTgt);
858 EXPECT_EQ(0, task_runner_->GetPendingTaskCount());
859 EXPECT_EQ(ERROR_NONE, AcquireTgt());
860 EXPECT_EQ(1, task_runner_->GetPendingTaskCount());
861}
862
863// When a TGT fails to be acquired, no automatic renewal is scheduled.
864TEST_F(AccountManagerTest, AcquireTgtDoesNotScheduleRenewalOnFailure) {
865 ignore_result(AddAccount());
866
867 krb5_->set_tgt_status(kValidTgt);
868 krb5_->set_acquire_tgt_error(ERROR_UNKNOWN);
869 EXPECT_EQ(0, task_runner_->GetPendingTaskCount());
870 EXPECT_EQ(ERROR_UNKNOWN, AcquireTgt());
871 EXPECT_EQ(0, task_runner_->GetPendingTaskCount());
872}
873
874// A scheduled TGT renewal task calls |krb5_->RenewTgt()|.
875TEST_F(AccountManagerTest, AutoRenewalCallsRenewTgt) {
876 krb5_->set_tgt_status(kValidTgt);
877 ignore_result(AddAccount());
878 ignore_result(AcquireTgt());
879 int initial_acquire_tgt_call_count = krb5_->acquire_tgt_call_count();
880
881 // Set some return value for the RenewTgt() call and fast forward to scheduled
882 // renewal task.
883 const ErrorType expected_error = ERROR_UNKNOWN;
884 krb5_->set_renew_tgt_error(expected_error);
885 RunScheduledRenewalTask();
886
887 EXPECT_EQ(initial_acquire_tgt_call_count, krb5_->acquire_tgt_call_count());
888 EXPECT_EQ(expected_error, manager_->last_renew_tgt_error_for_testing());
889}
890
891// A scheduled TGT renewal task calls |krb5_->AcquireTgt()| using the login
892// password if the call to |krb5_->RenewTgt()| fails and the login password was
893// used for the initial AcquireTgt() call.
894TEST_F(AccountManagerTest, AutoRenewalUsesLoginPasswordIfRenewalFails) {
895 krb5_->set_tgt_status(kValidTgt);
896 ignore_result(AddAccount());
897
898 // Acquire TGT with login password.
899 SaveLoginPassword(kPassword);
900 krb5_->set_expected_password(kPassword);
901 EXPECT_EQ(ERROR_NONE,
902 manager_->AcquireTgt(kUser, std::string(), kDontRememberPassword,
903 kUseLoginPassword));
904 int initial_acquire_tgt_call_count = krb5_->acquire_tgt_call_count();
905
906 krb5_->set_renew_tgt_error(ERROR_UNKNOWN);
907 RunScheduledRenewalTask();
908
909 // The scheduled renewal task should have called AcquireTgt() with the login
910 // password and succeeded.
911 EXPECT_EQ(initial_acquire_tgt_call_count + 1,
912 krb5_->acquire_tgt_call_count());
913 EXPECT_EQ(ERROR_NONE, manager_->last_renew_tgt_error_for_testing());
914}
915
916// A scheduled TGT renewal task calls |krb5_->AcquireTgt()| using the remembered
917// password if the call to |krb5_->RenewTgt()| fails and the password was
918// remembered for the initial AcquireTgt() call.
919TEST_F(AccountManagerTest, AutoRenewalUsesRememberedPasswordIfRenewalFails) {
920 krb5_->set_tgt_status(kValidTgt);
921 ignore_result(AddAccount());
922
923 // Acquire TGT and remember password.
924 krb5_->set_expected_password(kPassword);
925 EXPECT_EQ(ERROR_NONE,
926 manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
927 kDontUseLoginPassword));
928 int initial_acquire_tgt_call_count = krb5_->acquire_tgt_call_count();
929
930 krb5_->set_renew_tgt_error(ERROR_UNKNOWN);
931 RunScheduledRenewalTask();
932
933 // The scheduled renewal task should have called AcquireTgt() with the
934 // remembered password and succeeded.
935 EXPECT_EQ(initial_acquire_tgt_call_count + 1,
936 krb5_->acquire_tgt_call_count());
937 EXPECT_EQ(ERROR_NONE, manager_->last_renew_tgt_error_for_testing());
938}
939
940// A scheduled TGT renewal task does not call |krb5_->AcquireTgt()| using the
941// remembered password if the call to |krb5_->RenewTgt()| succeeds and the
942// password was remembered for the initial AcquireTgt() call (similar for login
943// password, but we don't test that).
944TEST_F(AccountManagerTest, AutoRenewalDoesNotCallAcquireTgtIfRenewalSucceeds) {
945 krb5_->set_tgt_status(kValidTgt);
946 ignore_result(AddAccount());
947
948 // Acquire TGT and remember password.
949 krb5_->set_expected_password(kPassword);
950 EXPECT_EQ(ERROR_NONE,
951 manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
952 kDontUseLoginPassword));
953 int initial_acquire_tgt_call_count = krb5_->acquire_tgt_call_count();
954
955 krb5_->set_renew_tgt_error(ERROR_NONE);
956 RunScheduledRenewalTask();
957
958 // The scheduled renewal task should NOT have called AcquireTgt() again since
959 // |krb5_->RenewTgt()|.
960 EXPECT_EQ(initial_acquire_tgt_call_count, krb5_->acquire_tgt_call_count());
961 EXPECT_EQ(ERROR_NONE, manager_->last_renew_tgt_error_for_testing());
Lutz Justen8eeb4a22019-06-19 17:00:32 +0200962}
963
Lutz Justen33601802019-07-03 22:40:57 +0200964// Verifies that all files written have the expected access permissions.
965// Unfortunately, file ownership can't be tested as the test won't run as
966// kerberosd user nor can it switch to it.
967TEST_F(AccountManagerTest, FilePermissions) {
968 constexpr int kFileMode_rw =
969 base::FILE_PERMISSION_READ_BY_USER | base::FILE_PERMISSION_WRITE_BY_USER;
970 constexpr int kFileMode_rw_r =
971 kFileMode_rw | base::FILE_PERMISSION_READ_BY_GROUP;
972 constexpr int kFileMode_rw_r__r =
973 kFileMode_rw_r | base::FILE_PERMISSION_READ_BY_OTHERS;
974 constexpr int kFileMode_rwxrwx =
975 base::FILE_PERMISSION_USER_MASK | base::FILE_PERMISSION_GROUP_MASK;
976
977 // Wrap the fake krb5 in a jail wrapper to get the file permissions of krb5cc
978 // right. Note that we can't use a Krb5JailWrapper for the whole test since
979 // that would break the counters in FakeKrb5Interface (they would be inc'ed in
980 // another process!).
981 manager_->WrapKrb5ForTesting();
982
983 // Can't set user in this test.
984 Krb5JailWrapper::DisableChangeUserForTesting(true);
985
986 EXPECT_EQ(ERROR_NONE, AddAccount());
987 EXPECT_EQ(ERROR_NONE, SetConfig());
988 EXPECT_EQ(ERROR_NONE,
989 manager_->AcquireTgt(kUser, kPassword, kRememberPassword,
990 kDontUseLoginPassword));
991
992 int mode;
993
994 EXPECT_TRUE(GetPosixFilePermissions(accounts_path_, &mode));
995 EXPECT_EQ(kFileMode_rw, mode);
996
997 EXPECT_TRUE(GetPosixFilePermissions(account_dir_, &mode));
998 EXPECT_EQ(kFileMode_rwxrwx, mode);
999
1000 EXPECT_TRUE(GetPosixFilePermissions(krb5cc_path_, &mode));
1001 EXPECT_EQ(kFileMode_rw_r, mode);
1002
1003 EXPECT_TRUE(GetPosixFilePermissions(krb5conf_path_, &mode));
1004 EXPECT_EQ(kFileMode_rw_r__r, mode);
1005
1006 EXPECT_TRUE(GetPosixFilePermissions(password_path_, &mode));
1007 EXPECT_EQ(kFileMode_rw, mode);
1008}
1009
Lutz Justen2d857e12019-07-16 15:58:09 +02001010// Tests that [Should]ReportDailyUsageStats is called as advertised.
1011TEST_F(AccountManagerTest, ReportDailyUsageStats) {
1012 // ShouldReportDailyUsageStats() should be called by GetKerberosFiles() even
1013 // if there is no account, and if that returns true, ReportDailyUsageStats()
1014 // should be called as well.
1015 EXPECT_CALL(*metrics_, ShouldReportDailyUsageStats()).WillOnce(Return(true));
1016 EXPECT_CALL(*metrics_, ReportDailyUsageStats(0, 0, 0, 0, 0));
1017 KerberosFiles files;
1018 EXPECT_EQ(ERROR_UNKNOWN_PRINCIPAL_NAME,
1019 manager_->GetKerberosFiles(kUser, &files));
1020 Mock::VerifyAndClearExpectations(metrics_.get());
1021
1022 AddAccount();
1023
1024 // ShouldReportDailyUsageStats() should be called by AcquireTgt(), but if that
1025 // returns false, ReportDailyUsageStats() should NOT be called.
1026 EXPECT_CALL(*metrics_, ShouldReportDailyUsageStats()).WillOnce(Return(false));
1027 EXPECT_CALL(*metrics_, ReportDailyUsageStats(_, _, _, _, _)).Times(0);
1028 AcquireTgt();
1029 Mock::VerifyAndClearExpectations(metrics_.get());
1030
1031 // ShouldReportDailyUsageStats() should be called by AcquireTgt(), and if that
1032 // returns true, ReportDailyUsageStats() should be called as well.
1033 EXPECT_CALL(*metrics_, ShouldReportDailyUsageStats()).WillOnce(Return(true));
1034 EXPECT_CALL(*metrics_, ReportDailyUsageStats(_, _, _, _, _));
1035 AcquireTgt();
1036 Mock::VerifyAndClearExpectations(metrics_.get());
1037}
1038
1039TEST_F(AccountManagerTest, AccountStats) {
1040 SaveLoginPassword(kPassword);
1041
1042 EXPECT_EQ(ERROR_NONE, manager_->AddAccount(kUser, kManaged));
1043 EXPECT_EQ(ERROR_NONE, manager_->AddAccount(kUser2, kManaged));
1044 EXPECT_EQ(ERROR_NONE, manager_->AddAccount(kUser3, kUnmanaged));
1045
1046 // Set metrics up so that the stats are reported on the last call.
1047 EXPECT_CALL(*metrics_, ShouldReportDailyUsageStats())
1048 .WillOnce(Return(false))
1049 .WillOnce(Return(false))
1050 .WillOnce(Return(true));
1051
1052 // 3 accounts total, 2 managed, 1 unmanaged, 1 remembering the password, 1
1053 // using the login password.
1054 EXPECT_CALL(*metrics_, ReportDailyUsageStats(3, 2, 1, 1, 1));
1055
1056 EXPECT_EQ(ERROR_NONE,
1057 manager_->AcquireTgt(kUser, kPassword, kDontRememberPassword,
1058 kDontUseLoginPassword));
1059 EXPECT_EQ(ERROR_NONE,
1060 manager_->AcquireTgt(kUser2, kPassword, kRememberPassword,
1061 kDontUseLoginPassword));
1062 EXPECT_EQ(ERROR_NONE,
1063 manager_->AcquireTgt(kUser3, kEmptyPassword, kDontRememberPassword,
1064 kUseLoginPassword));
1065}
1066
Lutz Justenb7ef5802019-05-14 14:03:20 +02001067} // namespace kerberos