#include <memory>
#include <optional>
#include <string>
#include <utility>
#include "base/functional/bind.h"
#include "base/test/test_future.h"
#include "base/values.h"
#include "build/branding_buildflags.h"
#include "chrome/browser/enterprise/connectors/device_trust/common/metrics_utils.h"
#include "chrome/browser/enterprise/connectors/device_trust/device_trust_service.h"
#include "chrome/browser/enterprise/connectors/device_trust/device_trust_service_factory.h"
#include "chrome/browser/enterprise/connectors/device_trust/navigation_throttle.h"
#include "chrome/browser/enterprise/connectors/device_trust/test/device_trust_browsertest_base.h"
#include "chrome/browser/enterprise/connectors/device_trust/test/test_constants.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/mixin_based_in_process_browser_test.h"
#include "components/device_signals/test/signals_contract.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/mock_navigation_handle.h"
#include "testing/gtest/include/gtest/gtest.h"
#if BUILDFLAG(IS_WIN)
#include "chrome/browser/browser_process.h"
#include "chrome/browser/enterprise/connectors/device_trust/device_trust_features.h"
#include "chrome/browser/enterprise/connectors/device_trust/test/device_trust_test_environment_win.h"
#include "chrome/browser/enterprise/connectors/test/test_constants.h"
#include "chrome/browser/policy/chrome_browser_policy_connector.h"
#include "components/enterprise/browser/controller/chrome_browser_cloud_management_controller.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/constants/ash_features.h"
#include "chrome/browser/ash/attestation/mock_tpm_challenge_key.h"
#include "chrome/browser/ash/attestation/tpm_challenge_key.h"
#include "chrome/browser/ash/attestation/tpm_challenge_key_result.h"
#else
#include "chrome/browser/enterprise/connectors/device_trust/key_management/browser/commands/scoped_key_rotation_command_factory.h"
#include "chrome/browser/enterprise/connectors/device_trust/key_management/core/persistence/scoped_key_persistence_delegate_factory.h"
#include "chrome/browser/ui/browser_element_identifiers.h"
#include "chrome/test/interaction/interactive_browser_test.h"
#include "components/device_signals/core/browser/pref_names.h"
#include "components/device_signals/core/common/signals_features.h"
#include "components/enterprise/browser/device_trust/device_trust_key_manager.h"
#include "ui/base/interaction/element_identifier.h"
#endif
NavigationHandle;
namespace enterprise_connectors::test {
namespace {
constexpr char kChallengeV1[] = …;
#if BUILDFLAG(IS_WIN)
constexpr char kFakeNonce[] = "fake nonce";
constexpr int kSuccessCode = 200;
constexpr int kHardFailureCode = 400;
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
DeviceTrustConnectorState CreateManagedDeviceState() {
DeviceTrustConnectorState state;
state.cloud_machine_management_level.is_managed = true;
state.affiliated = true;
return state;
}
#endif
DeviceTrustConnectorState CreateUnmanagedState() { … }
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
class DeviceTrustAshBrowserTest : public test::DeviceTrustBrowserTestBase {
protected:
explicit DeviceTrustAshBrowserTest(
std::optional<DeviceTrustConnectorState> state = std::nullopt)
: DeviceTrustBrowserTestBase(std::move(state)) {
auto mock_challenge_key =
std::make_unique<ash::attestation::MockTpmChallengeKey>();
mock_challenge_key->EnableFake();
ash::attestation::TpmChallengeKeyFactory::SetForTesting(
std::move(mock_challenge_key));
}
void TearDownOnMainThread() override {
ash::attestation::TpmChallengeKeyFactory::Create();
test::DeviceTrustBrowserTestBase::TearDownOnMainThread();
}
};
using DeviceTrustBrowserTest = DeviceTrustAshBrowserTest;
#else
class DeviceTrustDesktopBrowserTest : public test::DeviceTrustBrowserTestBase { … };
DeviceTrustBrowserTest;
#endif
IN_PROC_BROWSER_TEST_F(DeviceTrustBrowserTest, AttestationFullFlowKeyExists) { … }
IN_PROC_BROWSER_TEST_F(DeviceTrustBrowserTest, AttestationFullFlowKeyExistsV1) { … }
IN_PROC_BROWSER_TEST_F(DeviceTrustBrowserTest, AttestationHostNotAllowed) { … }
IN_PROC_BROWSER_TEST_F(DeviceTrustBrowserTest, AttestationPrefEmptyList) { … }
IN_PROC_BROWSER_TEST_F(DeviceTrustBrowserTest,
CreateNavigationThrottleIncognitoMode) { … }
class DeviceTrustDelayedManagementBrowserTest
: public DeviceTrustBrowserTest,
public ::testing::WithParamInterface<DeviceTrustConnectorState> { … };
IN_PROC_BROWSER_TEST_P(DeviceTrustDelayedManagementBrowserTest,
ManagementAddedAfterFirstCreationTry) { … }
INSTANTIATE_TEST_SUITE_P(…);
#if BUILDFLAG(IS_CHROMEOS_ASH)
INSTANTIATE_TEST_SUITE_P(ManagedState,
DeviceTrustDelayedManagementBrowserTest,
testing::Values(CreateManagedDeviceState()));
#endif
IN_PROC_BROWSER_TEST_F(DeviceTrustBrowserTest, SignalsContract) { … }
#if BUILDFLAG(IS_WIN)
using KeyRotationResult = DeviceTrustKeyManager::KeyRotationResult;
class DeviceTrustCreateKeyBrowserTest : public DeviceTrustDesktopBrowserTest {
protected:
DeviceTrustCreateKeyBrowserTest()
: DeviceTrustDesktopBrowserTest(false) {}
};
IN_PROC_BROWSER_TEST_F(DeviceTrustCreateKeyBrowserTest,
AttestationFullFlowKeyCreation) {
TriggerUrlNavigation();
VerifyAttestationFlowSuccessful();
VerifyKeyRotationSuccess(false);
EXPECT_FALSE(device_trust_test_environment_win_->GetWrappedKey().empty());
}
IN_PROC_BROWSER_TEST_F(DeviceTrustCreateKeyBrowserTest,
AttestationFullFlowKeyCreationV1) {
SetChallengeValue(kChallengeV1);
TriggerUrlNavigation();
VerifyAttestationFlowFailure(test::kFailedToParseChallengeJsonResponse);
VerifyKeyRotationSuccess(false);
EXPECT_FALSE(device_trust_test_environment_win_->GetWrappedKey().empty());
}
class DeviceTrustCreateKeyUploadFailedBrowserTest
: public DeviceTrustCreateKeyBrowserTest {
protected:
DeviceTrustCreateKeyUploadFailedBrowserTest()
: DeviceTrustCreateKeyBrowserTest() {}
void SetUpInProcessBrowserTestFixture() override {
DeviceTrustCreateKeyBrowserTest::SetUpInProcessBrowserTestFixture();
device_trust_test_environment_win_->SetUploadResult(kHardFailureCode);
}
};
IN_PROC_BROWSER_TEST_F(DeviceTrustCreateKeyUploadFailedBrowserTest,
DISABLED_AttestationFullFlowSucceedOnThirdAttempt) {
ASSERT_FALSE(device_trust_test_environment_win_->KeyExists());
TriggerUrlNavigation();
VerifyAttestationFlowSuccessful(DTAttestationResult::kSuccessNoSignature);
ASSERT_FALSE(device_trust_test_environment_win_->KeyExists());
ResetState();
TriggerUrlNavigation();
VerifyAttestationFlowSuccessful(DTAttestationResult::kSuccessNoSignature);
ASSERT_FALSE(device_trust_test_environment_win_->KeyExists());
device_trust_test_environment_win_->SetUploadResult(kSuccessCode);
ResetState();
TriggerUrlNavigation();
VerifyAttestationFlowSuccessful();
ASSERT_TRUE(device_trust_test_environment_win_->KeyExists());
}
class DeviceTrustKeyRotationBrowserTest : public DeviceTrustDesktopBrowserTest {
protected:
DeviceTrustKeyRotationBrowserTest() {
scoped_feature_list_.InitWithFeatureState(kDTCKeyRotationEnabled, true);
}
};
IN_PROC_BROWSER_TEST_F(DeviceTrustKeyRotationBrowserTest,
RemoteCommandKeyRotationSuccess) {
std::vector<uint8_t> current_key_pair =
device_trust_test_environment_win_->GetWrappedKey();
ASSERT_FALSE(current_key_pair.empty());
auto* key_manager = g_browser_process->browser_policy_connector()
->chrome_browser_cloud_management_controller()
->GetDeviceTrustKeyManager();
base::test::TestFuture<KeyRotationResult> future_result;
key_manager->RotateKey(kFakeNonce, future_result.GetCallback());
ASSERT_EQ(future_result.Get(), KeyRotationResult::SUCCESS);
ASSERT_TRUE(device_trust_test_environment_win_->KeyExists());
EXPECT_NE(device_trust_test_environment_win_->GetWrappedKey(),
current_key_pair);
}
#if BUILDFLAG(IS_WIN)
#define MAYBE_RemoteCommandKeyRotationFailure …
#else
#define MAYBE_RemoteCommandKeyRotationFailure …
#endif
IN_PROC_BROWSER_TEST_F(DeviceTrustKeyRotationBrowserTest,
MAYBE_RemoteCommandKeyRotationFailure) {
std::vector<uint8_t> current_key_pair =
device_trust_test_environment_win_->GetWrappedKey();
ASSERT_FALSE(current_key_pair.empty());
device_trust_test_environment_win_->SetUploadResult(kHardFailureCode);
auto* key_manager = g_browser_process->browser_policy_connector()
->chrome_browser_cloud_management_controller()
->GetDeviceTrustKeyManager();
base::test::TestFuture<KeyRotationResult> future_result;
key_manager->RotateKey(kFakeNonce, future_result.GetCallback());
ASSERT_EQ(future_result.Get(), KeyRotationResult::FAILURE);
ASSERT_TRUE(device_trust_test_environment_win_->KeyExists());
EXPECT_EQ(device_trust_test_environment_win_->GetWrappedKey(),
current_key_pair);
}
#endif
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
class DeviceTrustBrowserTestWithConsent
: public InteractiveBrowserTestT<DeviceTrustBrowserTest>,
public testing::WithParamInterface<
testing::tuple<bool, bool, bool, bool, bool, bool>> { … };
IN_PROC_BROWSER_TEST_P(DeviceTrustBrowserTestWithConsent,
ConsentDialogWithPolicyAndAttestation) { … }
INSTANTIATE_TEST_SUITE_P(…);
INSTANTIATE_TEST_SUITE_P(…);
INSTANTIATE_TEST_SUITE_P(…);
INSTANTIATE_TEST_SUITE_P(…);
class DeviceTrustBrowserTestWithPermanentConsent
: public DeviceTrustBrowserTestWithConsent { … };
IN_PROC_BROWSER_TEST_P(DeviceTrustBrowserTestWithPermanentConsent,
ConsentDialogWithPolicyAndAttestation) { … }
INSTANTIATE_TEST_SUITE_P(…);
INSTANTIATE_TEST_SUITE_P(…);
INSTANTIATE_TEST_SUITE_P(…);
INSTANTIATE_TEST_SUITE_P(…);
class DeviceTrustPolicyLevelBrowserTest
: public DeviceTrustBrowserTest,
public testing::WithParamInterface<
testing::tuple<bool, bool, bool>> { … };
IN_PROC_BROWSER_TEST_P(DeviceTrustPolicyLevelBrowserTest,
AttestationPolicyLevelTest) { … }
INSTANTIATE_TEST_SUITE_P(…);
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
class DeviceTrustBrowserTestForUnmanagedDevices
: public DeviceTrustBrowserTest,
public testing::WithParamInterface<
testing::tuple<bool, bool, bool>> {
protected:
DeviceTrustBrowserTestForUnmanagedDevices()
: DeviceTrustBrowserTest(DeviceTrustConnectorState({
.affiliated = false,
.cloud_user_management_level = DeviceTrustManagementLevel({
.is_managed = testing::get<0>(GetParam()),
.is_inline_policy_enabled = testing::get<1>(GetParam()),
}),
})) {
scoped_feature_list_.InitWithFeatureState(
ash::features::kUnmanagedDeviceDeviceTrustConnectorEnabled,
is_unmanaged_device_feature_enabled());
}
bool is_user_managed() { return testing::get<0>(GetParam()); }
bool is_user_inline_flow_enabled() { return testing::get<1>(GetParam()); }
bool is_unmanaged_device_feature_enabled() {
return testing::get<2>(GetParam());
}
};
IN_PROC_BROWSER_TEST_P(DeviceTrustBrowserTestForUnmanagedDevices,
AttestationFullFlow) {
TriggerUrlNavigation();
if (!is_unmanaged_device_feature_enabled() || !is_user_managed() ||
!is_user_inline_flow_enabled()) {
VerifyNoInlineFlowOccurred();
return;
}
VerifyAttestationFlowSuccessful();
}
INSTANTIATE_TEST_SUITE_P(
ManagedUser,
DeviceTrustBrowserTestForUnmanagedDevices,
testing::Combine(
testing::Values(true),
testing::Bool(),
testing::Values(true)));
INSTANTIATE_TEST_SUITE_P(
UnmanagedUser,
DeviceTrustBrowserTestForUnmanagedDevices,
testing::Combine(
testing::Values(false),
testing::Values(false),
testing::Values(true)));
INSTANTIATE_TEST_SUITE_P(
FeatureFlag,
DeviceTrustBrowserTestForUnmanagedDevices,
testing::Combine(
testing::Values(true),
testing::Values(true),
testing::Values(true)));
class DeviceTrustBrowserTestSignalsContractForUnmanagedDevices
: public DeviceTrustBrowserTest {
protected:
DeviceTrustBrowserTestSignalsContractForUnmanagedDevices()
: DeviceTrustBrowserTest(DeviceTrustConnectorState({
.affiliated = false,
.cloud_user_management_level = DeviceTrustManagementLevel({
.is_managed = true,
.is_inline_policy_enabled = true,
}),
})) {
scoped_feature_list_.InitWithFeatureState(
ash::features::kUnmanagedDeviceDeviceTrustConnectorEnabled, true);
}
};
IN_PROC_BROWSER_TEST_F(DeviceTrustBrowserTestSignalsContractForUnmanagedDevices,
SignalsContract) {
auto* device_trust_service =
DeviceTrustServiceFactory::GetForProfile(browser()->profile());
ASSERT_TRUE(device_trust_service);
base::test::TestFuture<base::Value::Dict> future;
device_trust_service->GetSignals(future.GetCallback());
ASSERT_TRUE(future.Wait()) << "Timed out while collecting signals.";
const base::Value::Dict& signals_dict = future.Get();
const auto signals_contract_map =
device_signals::test::GetSignalsContractForUnmanagedDevices();
ASSERT_FALSE(signals_contract_map.empty());
for (const auto& signals_contract_entry : signals_contract_map) {
EXPECT_TRUE(signals_contract_entry.second.Run(signals_dict))
<< "Signals contract validation failed for: "
<< signals_contract_entry.first;
}
}
#endif
}