blob: 7f470d95ff6619574866254bb38610561b359dad [file] [log] [blame]
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "system-proxy/kerberos_client.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <utility>
#include <base/bind.h>
#include <base/callback_helpers.h>
#include <base/files/file_util.h>
#include <base/files/scoped_file.h>
#include <base/memory/weak_ptr.h>
#include <base/strings/stringprintf.h>
#include <base/task/single_thread_task_executor.h>
#include <brillo/dbus/async_event_sequencer.h>
#include <brillo/dbus/dbus_object.h>
#include <brillo/message_loops/base_message_loop.h>
#include <dbus/kerberos/dbus-constants.h>
#include <dbus/object_path.h>
#include <dbus/message.h>
#include <dbus/mock_bus.h>
#include <dbus/mock_object_proxy.h>
#include <kerberos/proto_bindings/kerberos_service.pb.h>
using testing::_;
using testing::Return;
namespace system_proxy {
namespace {
constexpr char kKrb5ConfFile[] = "/tmp/krb5.conf";
constexpr char kCCacheFile[] = "/tmp/ccache";
constexpr char kPrincipalName[] = "user@TEST-REALM";
const char kKrb5Settings[] =
"[libdefaults]\n"
"\tdns_canonicalize_hostname = false\n"
"\trdns = false\n"
"\tdefault_realm = TEST-REALM\n";
std::string GetUpdatedConfig(const std::string& updated_config) {
return base::StringPrintf("%s%s", kKrb5Settings, updated_config.c_str());
}
} // namespace
// Implementation of KerberosClient that fakes dbus calls to kerberosd.
class FakeKerberosClient : public KerberosClient {
public:
explicit FakeKerberosClient(scoped_refptr<dbus::Bus> bus)
: KerberosClient(bus) {}
FakeKerberosClient(const FakeKerberosClient&) = delete;
FakeKerberosClient& operator=(const FakeKerberosClient&) = delete;
~FakeKerberosClient() override = default;
void SetFakeGetFilesResponse(const std::string& krb5_conf_data,
const std::string& ccache_data) {
krb5_conf_data_ = krb5_conf_data;
ccache_file_data_ = ccache_data;
}
protected:
void GetFiles() override {
auto dbus_response = dbus::Response::CreateEmpty();
dbus::MessageWriter writer(dbus_response.get());
kerberos::GetKerberosFilesResponse response;
kerberos::KerberosFiles files;
files.set_krb5conf(krb5_conf_data_);
files.set_krb5cc(ccache_file_data_);
*response.mutable_files() = files;
writer.AppendProtoAsArrayOfBytes(response);
OnGetFilesResponse(dbus_response.get());
}
private:
// Values returned by the kerberosd service.
std::string krb5_conf_data_;
std::string ccache_file_data_;
};
class KerberosClientTest : public ::testing::Test {
public:
KerberosClientTest() {
mock_kerberos_proxy_ = base::MakeRefCounted<dbus::MockObjectProxy>(
bus_.get(), kerberos::kKerberosServiceName,
dbus::ObjectPath(kerberos::kKerberosServicePath));
EXPECT_CALL(*bus_, GetObjectProxy(kerberos::kKerberosServiceName, _))
.WillRepeatedly(Return(mock_kerberos_proxy_.get()));
kerberos_client_.reset(new FakeKerberosClient(bus_));
krb5_conf_file_path_ = base::FilePath(kKrb5ConfFile);
ccache_file_path_ = base::FilePath(kCCacheFile);
brillo_loop_.SetAsCurrent();
}
KerberosClientTest(const KerberosClientTest&) = delete;
KerberosClientTest& operator=(const KerberosClientTest&) = delete;
~KerberosClientTest() override {
// Clean-up
kerberos_client_->DeleteFiles();
}
protected:
std::unique_ptr<FakeKerberosClient> kerberos_client_;
base::FilePath krb5_conf_file_path_;
base::FilePath ccache_file_path_;
scoped_refptr<dbus::MockBus> bus_ = new dbus::MockBus(dbus::Bus::Options());
scoped_refptr<dbus::MockObjectProxy> mock_kerberos_proxy_;
base::SingleThreadTaskExecutor task_executor_{base::MessagePumpType::IO};
brillo::BaseMessageLoop brillo_loop_{task_executor_.task_runner()};
};
// Test that the kerberos files are written and deleted correctly.
TEST_F(KerberosClientTest, KerberosEnabled) {
base::DeleteFile(base::FilePath(kKrb5ConfFile));
base::DeleteFile(base::FilePath(kCCacheFile));
std::string actual_krb5config;
std::string actual_ccache;
EXPECT_FALSE(
base::ReadFileToString(krb5_conf_file_path_, &actual_krb5config));
EXPECT_FALSE(base::ReadFileToString(ccache_file_path_, &actual_ccache));
kerberos_client_->SetFakeGetFilesResponse("fake conf", "fake ccache");
kerberos_client_->SetKerberosEnabled(true);
kerberos_client_->SetPrincipalName(kPrincipalName);
ASSERT_TRUE(base::ReadFileToString(krb5_conf_file_path_, &actual_krb5config));
ASSERT_TRUE(base::ReadFileToString(ccache_file_path_, &actual_ccache));
EXPECT_EQ(GetUpdatedConfig("fake conf"), actual_krb5config);
EXPECT_EQ("fake ccache", actual_ccache);
kerberos_client_->SetKerberosEnabled(false);
EXPECT_FALSE(
base::ReadFileToString(krb5_conf_file_path_, &actual_krb5config));
EXPECT_FALSE(base::ReadFileToString(ccache_file_path_, &actual_ccache));
}
// Test that the kerberos files are requested again when the
TEST_F(KerberosClientTest, SignalHandling) {
std::string actual_krb5config;
std::string actual_ccache;
kerberos_client_->SetFakeGetFilesResponse("fake conf 1", "fake ccache 1");
kerberos_client_->SetKerberosEnabled(true);
kerberos_client_->SetPrincipalName(kPrincipalName);
ASSERT_TRUE(base::ReadFileToString(krb5_conf_file_path_, &actual_krb5config));
ASSERT_TRUE(base::ReadFileToString(ccache_file_path_, &actual_ccache));
EXPECT_EQ(GetUpdatedConfig("fake conf 1"), actual_krb5config);
EXPECT_EQ("fake ccache 1", actual_ccache);
kerberos_client_->SetFakeGetFilesResponse("fake conf 2", "fake ccache 2");
dbus::Signal signal_to_send(kerberos::kKerberosInterface,
kerberos::kKerberosFilesChangedSignal);
kerberos_client_->OnKerberosFilesChanged(&signal_to_send);
ASSERT_TRUE(base::ReadFileToString(krb5_conf_file_path_, &actual_krb5config));
ASSERT_TRUE(base::ReadFileToString(ccache_file_path_, &actual_ccache));
EXPECT_EQ(GetUpdatedConfig("fake conf 2"), actual_krb5config);
EXPECT_EQ("fake ccache 2", actual_ccache);
}
} // namespace system_proxy