chromium/chrome/browser/ash/policy/core/user_cloud_policy_manager_ash_browsertest.cc

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "ash/components/arc/arc_prefs.h"
#include "base/containers/flat_set.h"
#include "base/test/scoped_feature_list.h"
#include "base/values.h"
#include "chrome/browser/ash/login/test/logged_in_user_mixin.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/prefs/session_startup_pref.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/mixin_based_in_process_browser_test.h"
#include "components/invalidation/invalidation_factory.h"
#include "components/policy/proto/policy_common_definitions.pb.h"
#include "components/prefs/pref_service.h"
#include "components/session_manager/core/session_manager.h"
#include "components/signin/public/identity_manager/account_managed_status_finder.h"
#include "components/user_manager/known_user.h"
#include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h"
#include "content/public/test/browser_test.h"

namespace policy {

class UserCloudPolicyManagerTestBase : public MixinBasedInProcessBrowserTest {
 public:
  UserCloudPolicyManagerTestBase(const UserCloudPolicyManagerTestBase&) =
      delete;
  UserCloudPolicyManagerTestBase& operator=(
      const UserCloudPolicyManagerTestBase&) = delete;

 protected:
  UserCloudPolicyManagerTestBase(ash::LoggedInUserMixin::LogInType login_type,
                                 bool user_existed_before) {
    logged_in_user_mixin_ = std::make_unique<ash::LoggedInUserMixin>(
        &mixin_host_, /*test_base=*/this, embedded_test_server(), login_type,
        user_existed_before);

    // Override default tests configuration that prevents effective testing of
    // whether start-up URL policy is properly applied:
    // *   InProcessBrowserTest force about://blank start-up URL via command
    //     line (which trumps policy values).
    set_open_about_blank_on_browser_launch(false);
  }

  ~UserCloudPolicyManagerTestBase() override = default;

  // Sets up fake GAIA for specified user login, and requests login for the user
  // (using LoggedInUserMixin).
  void StartUserLogIn(bool wait_for_active_session) {
    base::flat_set<ash::LoggedInUserMixin::LoginDetails> details{
        ash::LoggedInUserMixin::LoginDetails::kUseAnyScopeToken,
        ash::LoggedInUserMixin::LoginDetails::kNoPolicyForUser};

    if (!wait_for_active_session) {
      details.insert(ash::LoggedInUserMixin::LoginDetails::kDontWaitForSession);
    }
    logged_in_user_mixin_->LogInUser(details);
  }

  user_manager::ProfileRequiresPolicy GetProfileRequiresPolicy() {
    user_manager::KnownUser known_user(g_browser_process->local_state());
    return known_user.GetProfileRequiresPolicy(
        logged_in_user_mixin_->GetAccountId());
  }

  void SetProfileRequiresPolicy(user_manager::ProfileRequiresPolicy value) {
    user_manager::KnownUser known_user(g_browser_process->local_state());
    known_user.SetProfileRequiresPolicy(logged_in_user_mixin_->GetAccountId(),
                                        value);
  }

  std::unique_ptr<ash::LoggedInUserMixin> logged_in_user_mixin_;
};

// Test scenarios for enterprise-managed user signing in for the first time.
class UserCloudPolicyManagerNewManagedUserTest
    : public UserCloudPolicyManagerTestBase {
 protected:
  UserCloudPolicyManagerNewManagedUserTest()
      : UserCloudPolicyManagerTestBase(
            ash::LoggedInUserMixin::LogInType::kManaged,
            /*user_existed_before=*/false) {}
};

// Test scenarios for consumer user with custom domain signing in for the first
// time.
class UserCloudPolicyManagerNewConsumerUserTest
    : public UserCloudPolicyManagerTestBase {
 protected:
  UserCloudPolicyManagerNewConsumerUserTest()
      : UserCloudPolicyManagerTestBase(
            ash::LoggedInUserMixin::LogInType::kConsumerCustomDomain,
            /*user_existed_before=*/false) {}

  void SetUp() override {
    UserCloudPolicyManagerTestBase::SetUp();
    // Recognize example.com as non-enterprise account. We don't use any
    // available public domain such as gmail.com in order to prevent possible
    // leak of verification keys/signatures.
    signin::AccountManagedStatusFinder::SetNonEnterpriseDomainForTesting(
        "example.com");
  }

  void TearDown() override {
    signin::AccountManagedStatusFinder::SetNonEnterpriseDomainForTesting(
        nullptr);
    UserCloudPolicyManagerTestBase::TearDown();
  }
};

// Test scenarios for consumer user with custom domain who already signed in.
class UserCloudPolicyManagerExistingConsumerUserTest
    : public UserCloudPolicyManagerTestBase {
 protected:
  UserCloudPolicyManagerExistingConsumerUserTest()
      : UserCloudPolicyManagerTestBase(
            ash::LoggedInUserMixin::LogInType::kConsumerCustomDomain,
            /*user_existed_before=*/true) {}

  void SetUp() override {
    UserCloudPolicyManagerTestBase::SetUp();
    // Recognize example.com as non-enterprise account. We don't use any
    // available public domain such as gmail.com in order to prevent possible
    // leak of verification keys/signatures.
    signin::AccountManagedStatusFinder::SetNonEnterpriseDomainForTesting(
        "example.com");
  }

  void TearDown() override {
    signin::AccountManagedStatusFinder::SetNonEnterpriseDomainForTesting(
        nullptr);
    UserCloudPolicyManagerTestBase::TearDown();
  }
};

struct FeaturesTestParam {
  std::vector<base::test::FeatureRef> enabled_features;
  std::vector<base::test::FeatureRef> disabled_features;
};

// Test scenarios for child user signing in for the first time.
class UserCloudPolicyManagerNewChildUserTest
    : public UserCloudPolicyManagerTestBase,
      public testing::WithParamInterface<FeaturesTestParam> {
 protected:
  UserCloudPolicyManagerNewChildUserTest()
      : UserCloudPolicyManagerTestBase(
            ash::LoggedInUserMixin::LogInType::kChild,
            /*user_existed_before=*/false) {
    scoped_feature_list_.InitWithFeatures(GetParam().enabled_features,
                                          GetParam().disabled_features);
  }

 private:
  base::test::ScopedFeatureList scoped_feature_list_;
};

INSTANTIATE_TEST_SUITE_P(
    /* no prefix */,
    UserCloudPolicyManagerNewChildUserTest,
    testing::Values(FeaturesTestParam{},
                    FeaturesTestParam{
                        .enabled_features = {
                            invalidation::kInvalidationsWithDirectMessages}}));

IN_PROC_BROWSER_TEST_F(UserCloudPolicyManagerNewManagedUserTest, StartSession) {
  // User hasn't signed in yet, so shouldn't know if the user requires policy.
  EXPECT_EQ(user_manager::ProfileRequiresPolicy::kUnknown,
            GetProfileRequiresPolicy());

  // Set up start-up URLs through a mandatory user policy.
  const char* const kStartupURLs[] = {"chrome://policy", "chrome://about"};
  enterprise_management::StringList* startup_urls_proto =
      logged_in_user_mixin_->GetUserPolicyMixin()
          ->RequestPolicyUpdate()
          ->policy_payload()
          ->mutable_restoreonstartupurls()
          ->mutable_value();
  for (auto* const url : kStartupURLs)
    startup_urls_proto->add_entries(url);
  logged_in_user_mixin_->GetUserPolicyMixin()
      ->RequestPolicyUpdate()
      ->policy_payload()
      ->mutable_restoreonstartup()
      ->set_value(SessionStartupPref::kPrefValueURLs);

  StartUserLogIn(true /*wait_for_active_session*/);

  // Check that the startup pages specified in policy were opened.
  BrowserList* browser_list = BrowserList::GetInstance();
  EXPECT_EQ(1U, browser_list->size());
  Browser* browser = browser_list->get(0);
  ASSERT_TRUE(browser);

  TabStripModel* tabs = browser->tab_strip_model();
  ASSERT_TRUE(tabs);
  const int expected_tab_count = static_cast<int>(std::size(kStartupURLs));
  EXPECT_EQ(expected_tab_count, tabs->count());
  for (int i = 0; i < expected_tab_count && i < tabs->count(); ++i) {
    EXPECT_EQ(GURL(kStartupURLs[i]),
              tabs->GetWebContentsAt(i)->GetVisibleURL());
  }

  // User should be marked as requiring policy.
  EXPECT_EQ(user_manager::ProfileRequiresPolicy::kPolicyRequired,
            GetProfileRequiresPolicy());

  // It is expected that if ArcEnabled policy is not set then it is managed
  // by default and user is not able manually set it.
  EXPECT_TRUE(
      ProfileManager::GetActiveUserProfile()->GetPrefs()->IsManagedPreference(
          arc::prefs::kArcEnabled));
}

IN_PROC_BROWSER_TEST_F(UserCloudPolicyManagerNewManagedUserTest,
                       ErrorLoadingPolicy) {
  StartUserLogIn(false /*wait_for_active_session*/);
  RunUntilBrowserProcessQuits();

  // Session should not have been started.
  EXPECT_FALSE(session_manager::SessionManager::Get()->IsSessionStarted());

  // User should be marked as not knowing if policy is required yet.
  EXPECT_EQ(user_manager::ProfileRequiresPolicy::kUnknown,
            GetProfileRequiresPolicy());
}

IN_PROC_BROWSER_TEST_F(UserCloudPolicyManagerExistingConsumerUserTest,
                       ErrorLoadingPolicyForUnmanagedUser) {
  // User should be marked as not knowing if policy is required yet.
  // Mark user as not needing policy - errors loading policy should be
  // ignored (unlike previous ErrorLoadingPolicy test).
  SetProfileRequiresPolicy(
      user_manager::ProfileRequiresPolicy::kNoPolicyRequired);

  StartUserLogIn(true /*wait_for_active_session*/);

  // User should still be marked as not needing policy
  EXPECT_EQ(user_manager::ProfileRequiresPolicy::kNoPolicyRequired,
            GetProfileRequiresPolicy());
}

IN_PROC_BROWSER_TEST_F(UserCloudPolicyManagerExistingConsumerUserTest,
                       NoPolicyForNonEnterpriseUser) {
  // Recognize example.com as non-enterprise account. We don't use any
  // available public domain such as gmail.com in order to prevent possible
  // leak of verification keys/signatures.
  signin::AccountManagedStatusFinder::SetNonEnterpriseDomainForTesting(
      "example.com");
  ASSERT_FALSE(
      signin::AccountManagedStatusFinder::MayBeEnterpriseUserBasedOnEmail(
          logged_in_user_mixin_->GetAccountId().GetUserEmail()));

  user_manager::KnownUser known_user(g_browser_process->local_state());
  // If a user signs in with a known non-enterprise account there should be no
  // policy.
  EXPECT_EQ(user_manager::ProfileRequiresPolicy::kUnknown,
            GetProfileRequiresPolicy());

  StartUserLogIn(true /*wait_for_active_session*/);

  // User should be marked as not requiring policy.
  EXPECT_EQ(user_manager::ProfileRequiresPolicy::kNoPolicyRequired,
            GetProfileRequiresPolicy());
}

IN_PROC_BROWSER_TEST_P(UserCloudPolicyManagerNewChildUserTest,
                       PolicyForChildUser) {
  // If a user signs in with a known non-enterprise account there should be no
  // policy in case user type is child.
  EXPECT_EQ(user_manager::ProfileRequiresPolicy::kUnknown,
            GetProfileRequiresPolicy());

  logged_in_user_mixin_->GetUserPolicyMixin()
      ->RequestPolicyUpdate()
      ->policy_payload()
      ->Clear();
  StartUserLogIn(true /*wait_for_active_session*/);

  // User of CHILD type should be marked as requiring policy.
  EXPECT_EQ(user_manager::ProfileRequiresPolicy::kPolicyRequired,
            GetProfileRequiresPolicy());

  // It is expected that if ArcEnabled policy is not set then it is not managed
  // by default and user is able manually set it.
  EXPECT_FALSE(
      ProfileManager::GetActiveUserProfile()->GetPrefs()->IsManagedPreference(
          arc::prefs::kArcEnabled));
}

IN_PROC_BROWSER_TEST_P(UserCloudPolicyManagerNewChildUserTest,
                       PolicyForChildUserMissing) {
  // If a user signs in with a known non-enterprise account there should be no
  // policy in case user type is child.
  EXPECT_EQ(user_manager::ProfileRequiresPolicy::kUnknown,
            GetProfileRequiresPolicy());

  StartUserLogIn(false /*wait_for_active_session*/);
  RunUntilBrowserProcessQuits();

  // Session should not have been started.
  EXPECT_FALSE(session_manager::SessionManager::Get()->IsSessionStarted());

  // User should be marked as not knowing if policy is required yet.
  EXPECT_EQ(user_manager::ProfileRequiresPolicy::kUnknown,
            GetProfileRequiresPolicy());
}
}  // namespace policy