| // 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/bind_helpers.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 |