blob: 7ca8af2b636af33505a33fee052b40ad038a0506 [file] [log] [blame] [edit]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "crash-reporter/connectivity_util.h"
#include <memory>
#include <string>
#include <vector>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/files/scoped_temp_dir.h>
#include <base/memory/scoped_refptr.h>
#include <bindings/cloud_policy.pb.h>
#include <bindings/device_management_backend.pb.h>
#include <dbus/login_manager/dbus-constants.h>
#include <dbus/mock_bus.h>
#include <dbus/mock_object_proxy.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <login_manager/proto_bindings/policy_descriptor.pb.h>
#include <policy/device_policy.h>
#include <session_manager-client-test/session_manager/dbus-proxy-mocks.h>
namespace connectivity_util {
using ::testing::_;
using ::testing::Invoke;
using ::testing::WithArg;
using ::testing::WithArgs;
constexpr char kDeviceGoogleUser[] = "testuser@google.com";
constexpr char kDeviceUserNotAllowed[] = "disallowed_user@gmail.com";
constexpr char kDeviceUserNotAllowed1[] = "randomusergoogle.com.xyz@gmail.com";
constexpr char kDeviceUserNotAllowed2[] = "deviceuser@disallowed_domain.com";
constexpr char kDeviceUserNotAllowed3[] = "randomuser@google.com.xyz@gmail.com";
constexpr char kDeviceUserInAllowList[] = "testuser@managedchrome.com";
constexpr char kUserInAllowedDomain[] = "someuser@managedchrome.com";
constexpr char kAffiliationID[] = "affiliation_id";
class ConnectivityUtilTest : public ::testing::Test {
protected:
void SetUp() override {
session_manager_ =
std::make_unique<org::chromium::SessionManagerInterfaceProxyMock>();
}
// This function creates input request blob required to call
// RetrievePolicyEx() function.
std::vector<uint8_t> CreateExpectedDescriptorBlob(
const login_manager::PolicyAccountType& type, const std::string& user) {
login_manager::PolicyDescriptor descriptor;
descriptor.set_domain(login_manager::POLICY_DOMAIN_CHROME);
descriptor.set_account_id(user);
if (type == login_manager::PolicyAccountType::ACCOUNT_TYPE_USER) {
descriptor.set_account_type(
login_manager::PolicyAccountType::ACCOUNT_TYPE_USER);
} else if (type == login_manager::PolicyAccountType::ACCOUNT_TYPE_DEVICE) {
descriptor.set_account_type(
login_manager::PolicyAccountType::ACCOUNT_TYPE_DEVICE);
} else {
CHECK(false);
}
std::string descriptor_string = descriptor.SerializeAsString();
return std::vector<uint8_t>(descriptor_string.begin(),
descriptor_string.end());
}
// This function creates Policy Fetch Response blob to simulate expected
// response of RetrievePolicyEx() function call.
std::vector<uint8_t> CreatePolicyFetchResponseBlob(
const login_manager::PolicyAccountType& type,
const std::string& affiliation_id,
const std::string& connectivity_policy_val) {
enterprise_management::PolicyData policy_data;
enterprise_management::CloudPolicySettings user_policy_val;
// Add policy required for connectivity fwdumps.
user_policy_val.mutable_subproto1()
->mutable_userfeedbackwithlowleveldebugdataallowed()
->mutable_value()
->add_entries(connectivity_policy_val);
std::string serialized_user_policy = user_policy_val.SerializeAsString();
policy_data.set_policy_value(serialized_user_policy);
if (type == login_manager::PolicyAccountType::ACCOUNT_TYPE_USER) {
auto id = policy_data.add_user_affiliation_ids();
*id = affiliation_id;
} else if (type == login_manager::PolicyAccountType::ACCOUNT_TYPE_DEVICE) {
auto id = policy_data.add_device_affiliation_ids();
*id = affiliation_id;
} else {
CHECK(false);
}
enterprise_management::PolicyFetchResponse response;
CHECK(policy_data.SerializeToString(response.mutable_policy_data()));
auto serialized = response.SerializeAsString();
return std::vector<uint8_t>(serialized.begin(), serialized.end());
}
std::unique_ptr<org::chromium::SessionManagerInterfaceProxyMock>
session_manager_;
};
// Test that connectivity fwdump is allowed for a googler users.
TEST_F(ConnectivityUtilTest, IsConnectivityFwdumpAllowedGooglerUser) {
EXPECT_CALL(
*session_manager_.get(),
RetrievePolicyEx(CreateExpectedDescriptorBlob(
login_manager::PolicyAccountType::ACCOUNT_TYPE_USER,
kDeviceGoogleUser),
_, _, _))
.WillOnce(WithArg<1>(Invoke([this](std::vector<uint8_t>* out_blob) {
*out_blob = CreatePolicyFetchResponseBlob(
login_manager::PolicyAccountType::ACCOUNT_TYPE_USER, kAffiliationID,
"wifi");
return true;
})));
EXPECT_TRUE(
IsConnectivityFwdumpAllowed(session_manager_.get(), kDeviceGoogleUser));
}
// Test connectivity fwdump is allowed if user is in allowlist.
// Test also validates connectivity debug data collection with policy set.
TEST_F(ConnectivityUtilTest, IsConnectivityFwdumpAllowedForAllowedUser) {
EXPECT_CALL(
*session_manager_.get(),
RetrievePolicyEx(CreateExpectedDescriptorBlob(
login_manager::PolicyAccountType::ACCOUNT_TYPE_USER,
kDeviceUserInAllowList),
_, _, _))
.WillOnce(WithArg<1>(Invoke([this](std::vector<uint8_t>* out_blob) {
*out_blob = CreatePolicyFetchResponseBlob(
login_manager::PolicyAccountType::ACCOUNT_TYPE_USER, kAffiliationID,
"wifi");
return true;
})));
EXPECT_TRUE(IsConnectivityFwdumpAllowed(session_manager_.get(),
kDeviceUserInAllowList));
}
// Test connectivity fwdump is allowed if user is in managedchrome domain.
// Test also validates connectivity debug data collection with policy set.
TEST_F(ConnectivityUtilTest, IsConnectivityFwdumpAllowedForAllowedDomain) {
EXPECT_CALL(
*session_manager_.get(),
RetrievePolicyEx(CreateExpectedDescriptorBlob(
login_manager::PolicyAccountType::ACCOUNT_TYPE_USER,
kUserInAllowedDomain),
_, _, _))
.WillOnce(WithArg<1>(Invoke([this](std::vector<uint8_t>* out_blob) {
*out_blob = CreatePolicyFetchResponseBlob(
login_manager::PolicyAccountType::ACCOUNT_TYPE_USER, kAffiliationID,
"wifi");
return true;
})));
EXPECT_TRUE(IsConnectivityFwdumpAllowed(session_manager_.get(),
kUserInAllowedDomain));
}
// Test to ensure that no session manager proxy is correctly handled
// and causes no crashes.
TEST_F(ConnectivityUtilTest, IsConnectivityFwdumpAllowedNoSessionManager) {
// IsConnectivityFwdumpAllowed() exits early and RetrievePolicyEx not
// expected to be called.
EXPECT_CALL(
*session_manager_.get(),
RetrievePolicyEx(CreateExpectedDescriptorBlob(
login_manager::PolicyAccountType::ACCOUNT_TYPE_USER,
kDeviceUserInAllowList),
_, _, _))
.Times(0);
EXPECT_FALSE(IsConnectivityFwdumpAllowed(nullptr, kDeviceGoogleUser));
}
// Test to ensure that connectivity fwdump is not allowed for
// different types of not allowed users.
// Also test that Connectivity policy set for WiFi but User Not allowed.
TEST_F(ConnectivityUtilTest, IsConnectivityFwdumpAllowedUserNotAllowed) {
EXPECT_CALL(
*session_manager_.get(),
RetrievePolicyEx(CreateExpectedDescriptorBlob(
login_manager::PolicyAccountType::ACCOUNT_TYPE_USER,
kDeviceUserInAllowList),
_, _, _))
.WillRepeatedly(WithArg<1>(Invoke([this](std::vector<uint8_t>* out_blob) {
*out_blob = CreatePolicyFetchResponseBlob(
login_manager::PolicyAccountType::ACCOUNT_TYPE_USER, kAffiliationID,
"wifi");
return true;
})));
EXPECT_FALSE(IsConnectivityFwdumpAllowed(session_manager_.get(),
kDeviceUserNotAllowed));
EXPECT_FALSE(IsConnectivityFwdumpAllowed(session_manager_.get(),
kDeviceUserNotAllowed1));
EXPECT_FALSE(IsConnectivityFwdumpAllowed(session_manager_.get(),
kDeviceUserNotAllowed2));
EXPECT_FALSE(IsConnectivityFwdumpAllowed(session_manager_.get(),
kDeviceUserNotAllowed3));
}
// UserFeedbackWithLowLevelDebugDataAllowed policy set for all
// connectivity domains.
TEST_F(ConnectivityUtilTest,
IsConnectivityFwdumpAllowedConnectivityPolicySetForAllDomain) {
EXPECT_CALL(
*session_manager_.get(),
RetrievePolicyEx(CreateExpectedDescriptorBlob(
login_manager::PolicyAccountType::ACCOUNT_TYPE_USER,
kDeviceUserInAllowList),
_, _, _))
.WillOnce(WithArg<1>(Invoke([this](std::vector<uint8_t>* out_blob) {
*out_blob = CreatePolicyFetchResponseBlob(
login_manager::PolicyAccountType::ACCOUNT_TYPE_USER, kAffiliationID,
"all");
return true;
})));
EXPECT_TRUE(IsConnectivityFwdumpAllowed(session_manager_.get(),
kDeviceUserInAllowList));
}
// UserFeedbackWithLowLevelDebugDataAllowed policy empty.
TEST_F(ConnectivityUtilTest,
IsConnectivityFwdumpAllowedConnectivityPolicyEmpty) {
EXPECT_CALL(
*session_manager_.get(),
RetrievePolicyEx(CreateExpectedDescriptorBlob(
login_manager::PolicyAccountType::ACCOUNT_TYPE_USER,
kDeviceUserInAllowList),
_, _, _))
.WillOnce(WithArg<1>(Invoke([this](std::vector<uint8_t>* out_blob) {
*out_blob = CreatePolicyFetchResponseBlob(
login_manager::PolicyAccountType::ACCOUNT_TYPE_USER, kAffiliationID,
"");
return true;
})));
EXPECT_FALSE(IsConnectivityFwdumpAllowed(session_manager_.get(),
kDeviceUserInAllowList));
}
// Connectivity policy not set but user allowed(googler or in allowlist).
TEST_F(ConnectivityUtilTest,
IsConnectivityFwdumpAllowedConnectivityPolicyNotSetButUserAllowed) {
// UserFeedbackWithLowLevelDebugDataAllowed policy set for wifi.
EXPECT_CALL(
*session_manager_.get(),
RetrievePolicyEx(CreateExpectedDescriptorBlob(
login_manager::PolicyAccountType::ACCOUNT_TYPE_USER,
kDeviceGoogleUser),
_, _, _))
.WillOnce(WithArg<1>(Invoke([this](std::vector<uint8_t>* out_blob) {
*out_blob = CreatePolicyFetchResponseBlob(
login_manager::PolicyAccountType::ACCOUNT_TYPE_USER, kAffiliationID,
"");
return true;
})));
EXPECT_FALSE(
IsConnectivityFwdumpAllowed(session_manager_.get(), kDeviceGoogleUser));
}
// Test to ensure the expected crash directory is created.
TEST_F(ConnectivityUtilTest, GetCorrectCrashDirectory) {
Session test_session;
test_session.username = kDeviceGoogleUser;
test_session.userhash = "user_hash";
std::optional<base::FilePath> got_dir =
GetDaemonStoreFbPreprocessordDirectory(test_session);
const char kExpectedDir[] =
"/run/daemon-store/fbpreprocessord/user_hash/raw_dumps";
EXPECT_TRUE(got_dir.has_value());
EXPECT_EQ(kExpectedDir, got_dir->value());
}
// Test to ensure no unexpected value returned when Session is empty.
TEST_F(ConnectivityUtilTest, GetCorrectCrashDirectoryForNoSessions) {
Session test_session;
std::optional<base::FilePath> got_dir =
GetDaemonStoreFbPreprocessordDirectory(test_session);
EXPECT_FALSE(got_dir.has_value());
}
// Tests GetDaemonStoreFbPreprocessordDirectory returns
// not expected directory path.
TEST_F(ConnectivityUtilTest, GetIncorrectCrashDirectory) {
Session test_session;
test_session.username = kDeviceUserInAllowList;
test_session.userhash = "user_hash";
std::optional<base::FilePath> got_dir =
GetDaemonStoreFbPreprocessordDirectory(test_session);
const char kExpectedDir[] =
"/run/daemon-store/fbpreprocessord/user_hash_unexpected";
EXPECT_TRUE(got_dir.has_value());
EXPECT_NE(kExpectedDir, got_dir->value());
}
// Test RetrievePolicyEx dbus call failure which leads to
// connectivity not allowed.
TEST_F(ConnectivityUtilTest,
IsConnectivityFwdumpAllowedRetrievePolicyExDbusFailed) {
EXPECT_CALL(
*session_manager_.get(),
RetrievePolicyEx(CreateExpectedDescriptorBlob(
login_manager::PolicyAccountType::ACCOUNT_TYPE_USER,
kDeviceUserInAllowList),
_, _, _))
.WillOnce(WithArg<2>(Invoke([](brillo::ErrorPtr* error) {
*error = brillo::Error::Create(FROM_HERE, "", "1",
"Dbus failed on RetrivePolicyEx");
return false;
})));
EXPECT_FALSE(IsConnectivityFwdumpAllowed(session_manager_.get(),
kDeviceUserInAllowList));
}
// Test RetrievePrimarySession dbus call failure which leads to
// connectivity not allowed.
TEST_F(ConnectivityUtilTest, PrimarySessionDbusFailed) {
brillo::ErrorPtr error;
EXPECT_CALL(*session_manager_.get(), RetrievePrimarySession)
.WillOnce(WithArg<2>(Invoke([](brillo::ErrorPtr* error) {
*error =
brillo::Error::Create(FROM_HERE, "", "1", "Failed active sessions");
return false;
})));
std::optional<Session> test_session =
GetPrimaryUserSession(session_manager_.get());
EXPECT_FALSE(test_session.has_value());
}
// Tests GetPrimaryUserSession function and ensures that correct
// Session instance is built and returned.
TEST_F(ConnectivityUtilTest, GetPrimaryUserSession) {
EXPECT_CALL(*session_manager_.get(), RetrievePrimarySession)
.WillOnce(WithArgs<0, 1>(
Invoke([](std::string* username, std::string* sanitized) {
*username = kDeviceGoogleUser;
*sanitized = "user_hash";
return true;
})));
std::optional<Session> test_session =
GetPrimaryUserSession(session_manager_.get());
ASSERT_TRUE(test_session.has_value());
EXPECT_EQ(test_session->username, kDeviceGoogleUser);
EXPECT_EQ(test_session->userhash, "user_hash");
}
// Tests GetPrimaryUserSession function to handle case where
// no user session is returned.
TEST_F(ConnectivityUtilTest, GetPrimaryUserSessionNoUserSessions) {
EXPECT_CALL(*session_manager_.get(), RetrievePrimarySession)
.WillOnce(WithArgs<0, 1>(Invoke(
[](std::string* username, std::string* sanitized) { return true; })));
std::optional<Session> test_session =
GetPrimaryUserSession(session_manager_.get());
EXPECT_FALSE(test_session.has_value());
}
} // namespace connectivity_util