chromium/chrome/browser/media/webrtc/capture_policy_utils_browsertest.cc

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

#include "chrome/browser/media/webrtc/capture_policy_utils.h"

#include <string>
#include <vector>

#include "base/test/test_future.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"

#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "base/test/test_future.h"
#include "base/values.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/media/webrtc/webrtc_browsertest_base.h"
#include "chrome/browser/policy/policy_test_utils.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/policy/core/browser/browser_policy_connector.h"
#include "components/policy/core/common/policy_map.h"
#include "components/policy/core/common/policy_pref_names.h"
#include "components/policy/core/common/policy_types.h"
#include "components/policy/policy_constants.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "url/origin.h"
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chromeos/lacros/lacros_service.h"
#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)

namespace {
constexpr char kValidIsolatedAppId1[] =
    "isolated-app://pt2jysa7yu326m2cbu5mce4rrajvguagronrsqwn5dhbaris6eaaaaic";
}  // namespace

#if BUILDFLAG(IS_CHROMEOS_ASH)
namespace {

constexpr char kValidIsolatedAppId2[] =
    "isolated-app://aerugqztij5biqquuk3mfwpsaibuegaqcitgfchwuosuofdjabzqaaic";

struct TestParam {
  std::string allow_list_policy_name;
  std::vector<std::string> allow_listed_origins;
  std::string testing_url;
  bool expected_is_get_all_screens_media_allowed;
};

struct NoRefreshTestParam {
  std::string allow_list_policy_name;
  std::vector<std::string> original_allowlisted_origins;
  std::vector<std::string> updated_allowlisted_origins;
  std::vector<std::string> expected_allowed_origins;
  std::vector<std::string> expected_forbidden_origins;
};

}  // namespace

class SelectAllScreensTestBase : public policy::PolicyTest {
 public:
  explicit SelectAllScreensTestBase(const std::string& allow_list_policy_name)
      : allow_list_policy_name_(allow_list_policy_name) {}
  ~SelectAllScreensTestBase() override = default;

  SelectAllScreensTestBase(const SelectAllScreensTestBase&) = delete;
  SelectAllScreensTestBase& operator=(const SelectAllScreensTestBase&) = delete;

  void SetAllowedOriginsPolicy(
      const std::vector<std::string>& allow_listed_origins) {
    policy::PolicyMap policies;
    base::Value::List allowed_origins;
    for (const auto& allowed_origin : allow_listed_origins) {
      allowed_origins.Append(base::Value(allowed_origin));
    }
    PolicyTest::SetPolicy(&policies, allow_list_policy_name_.c_str(),
                          base::Value(std::move(allowed_origins)));
    provider_.UpdateChromePolicy(policies);
  }

  void SetUpInProcessBrowserTestFixture() override {
    provider_.SetDefaultReturns(
        true /* is_initialization_complete_return */,
        true /* is_first_policy_load_complete_return */);
    SetAllowedOriginsPolicy(GetAllowedOrigins());
    policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
  }

  virtual std::vector<std::string> GetAllowedOrigins() const = 0;

 private:
  std::string allow_list_policy_name_;
};

class SelectAllScreensTest : public SelectAllScreensTestBase,
                             public testing::WithParamInterface<TestParam> {
 public:
  SelectAllScreensTest()
      : SelectAllScreensTestBase(GetParam().allow_list_policy_name) {}
  ~SelectAllScreensTest() override = default;

  SelectAllScreensTest(const SelectAllScreensTest&) = delete;
  SelectAllScreensTest& operator=(const SelectAllScreensTest&) = delete;

  std::vector<std::string> GetAllowedOrigins() const override {
    return GetParam().allow_listed_origins;
  }
};

IN_PROC_BROWSER_TEST_P(SelectAllScreensTest, SelectAllScreensTestOrigins) {
  Browser* current_browser = browser();
  TabStripModel* current_tab_strip_model = current_browser->tab_strip_model();
  content::WebContents* current_web_contents =
      current_tab_strip_model->GetWebContentsAt(0);

  base::test::TestFuture<bool> future;
  capture_policy::CheckGetAllScreensMediaAllowed(
      current_web_contents->GetBrowserContext(), GURL(GetParam().testing_url),
      future.GetCallback());
  ASSERT_TRUE(future.Wait());
  EXPECT_EQ(GetParam().expected_is_get_all_screens_media_allowed,
            future.Get<bool>());
}

INSTANTIATE_TEST_SUITE_P(
    DeprecatedPolicySelectAllScreensTestWithParams,
    SelectAllScreensTest,
    testing::Values(
        TestParam({
            .allow_list_policy_name =
                policy::key::kGetDisplayMediaSetSelectAllScreensAllowedForUrls,
            .allow_listed_origins = {""},
            .testing_url = "",
            .expected_is_get_all_screens_media_allowed = false,
        }),
        TestParam({
            .allow_list_policy_name =
                policy::key::kGetDisplayMediaSetSelectAllScreensAllowedForUrls,
            .allow_listed_origins = {},
            .testing_url = "https://www.chromium.org",
            .expected_is_get_all_screens_media_allowed = false,
        }),
        TestParam({
            .allow_list_policy_name =
                policy::key::kGetDisplayMediaSetSelectAllScreensAllowedForUrls,
            .allow_listed_origins = {},
            .testing_url = "",
            .expected_is_get_all_screens_media_allowed = false,
        }),
        TestParam({
            .allow_list_policy_name =
                policy::key::kGetDisplayMediaSetSelectAllScreensAllowedForUrls,
            .allow_listed_origins = {"https://www.chromium.org"},
            .testing_url = "https://www.chromium.org",
            .expected_is_get_all_screens_media_allowed = true,
        }),
        TestParam({
            .allow_list_policy_name =
                policy::key::kGetDisplayMediaSetSelectAllScreensAllowedForUrls,
            .allow_listed_origins = {"[*.]chromium.org"},
            .testing_url = "https://sub.chromium.org",
            .expected_is_get_all_screens_media_allowed = true,
        }),
        TestParam({
            .allow_list_policy_name =
                policy::key::kGetDisplayMediaSetSelectAllScreensAllowedForUrls,
            .allow_listed_origins = {"[*.]chrome.org", "[*.]chromium.com"},
            .testing_url = "https://www.chromium.org",
            .expected_is_get_all_screens_media_allowed = false,
        }),
        TestParam({
            .allow_list_policy_name =
                policy::key::kGetDisplayMediaSetSelectAllScreensAllowedForUrls,
            .allow_listed_origins = {"[*.]chrome.org", "[*.]chromium.org"},
            .testing_url = "https://www.chromium.org",
            .expected_is_get_all_screens_media_allowed = true,
        })));

INSTANTIATE_TEST_SUITE_P(
    SelectAllScreensTestWithParams,
    SelectAllScreensTest,
    testing::Values(TestParam({
                        .allow_list_policy_name =
                            policy::key::kMultiScreenCaptureAllowedForUrls,
                        .allow_listed_origins = {""},
                        .testing_url = "",
                        .expected_is_get_all_screens_media_allowed = false,
                    }),
                    TestParam({
                        .allow_list_policy_name =
                            policy::key::kMultiScreenCaptureAllowedForUrls,
                        .allow_listed_origins = {},
                        .testing_url = kValidIsolatedAppId1,
                        .expected_is_get_all_screens_media_allowed = false,
                    }),
                    TestParam({
                        .allow_list_policy_name =
                            policy::key::kMultiScreenCaptureAllowedForUrls,
                        .allow_listed_origins = {},
                        .testing_url = "",
                        .expected_is_get_all_screens_media_allowed = false,
                    }),
                    TestParam({
                        .allow_list_policy_name =
                            policy::key::kMultiScreenCaptureAllowedForUrls,
                        .allow_listed_origins = {"isolated-app://*"},
                        .testing_url = kValidIsolatedAppId1,
                        .expected_is_get_all_screens_media_allowed = false,
                    }),
                    TestParam({
                        .allow_list_policy_name =
                            policy::key::kMultiScreenCaptureAllowedForUrls,
                        .allow_listed_origins = {"*"},
                        .testing_url = kValidIsolatedAppId1,
                        .expected_is_get_all_screens_media_allowed = false,
                    }),
                    TestParam({
                        .allow_list_policy_name =
                            policy::key::kMultiScreenCaptureAllowedForUrls,
                        .allow_listed_origins = {kValidIsolatedAppId1},
                        .testing_url = kValidIsolatedAppId1,
                        .expected_is_get_all_screens_media_allowed = true,
                    })));

class SelectAllScreensDynamicRefreshTest
    : public SelectAllScreensTestBase,
      public testing::WithParamInterface<NoRefreshTestParam> {
 public:
  SelectAllScreensDynamicRefreshTest()
      : SelectAllScreensTestBase(GetParam().allow_list_policy_name) {}
  ~SelectAllScreensDynamicRefreshTest() override = default;

  explicit SelectAllScreensDynamicRefreshTest(const SelectAllScreensTest&) =
      delete;
  SelectAllScreensDynamicRefreshTest& operator=(const SelectAllScreensTest&) =
      delete;

  std::vector<std::string> GetAllowedOrigins() const override {
    return GetParam().original_allowlisted_origins;
  }

  void CheckExpectedAllowlistedAndForbiddenOrigins() {
    content::WebContents* current_web_contents =
        browser()->tab_strip_model()->GetActiveWebContents();
    DCHECK(current_web_contents);
    for (const auto& expected_allowed_origin :
         GetParam().expected_allowed_origins) {
      base::test::TestFuture<bool> future;
      capture_policy::CheckGetAllScreensMediaAllowed(
          current_web_contents->GetBrowserContext(),
          GURL(expected_allowed_origin), future.GetCallback());
      ASSERT_TRUE(future.Wait());
      EXPECT_TRUE(future.Get<bool>());
    }

    for (const auto& expected_forbidden_origin :
         GetParam().expected_forbidden_origins) {
      base::test::TestFuture<bool> future;
      capture_policy::CheckGetAllScreensMediaAllowed(
          current_web_contents->GetBrowserContext(),
          GURL(expected_forbidden_origin), future.GetCallback());
      ASSERT_TRUE(future.Wait());
      EXPECT_FALSE(future.Get<bool>());
    }
  }
};

// This test checks that dynamic refresh (i.e. no origins can be added or
// removed after user login) is not happening.
IN_PROC_BROWSER_TEST_P(
    SelectAllScreensDynamicRefreshTest,
    SelectAllScreensEnabledWithMultipleAllowedOriginsNoDynamicRefresh) {
  CheckExpectedAllowlistedAndForbiddenOrigins();

  SetAllowedOriginsPolicy(GetParam().updated_allowlisted_origins);
  base::RunLoop().RunUntilIdle();
  CheckExpectedAllowlistedAndForbiddenOrigins();
}

INSTANTIATE_TEST_SUITE_P(
    DeprecatedPolicySelectAllScreensDynamicRefreshTestWithParams,
    SelectAllScreensDynamicRefreshTest,
    testing::Values(
        NoRefreshTestParam({
            .allow_list_policy_name =
                policy::key::kGetDisplayMediaSetSelectAllScreensAllowedForUrls,
            .original_allowlisted_origins = {"https://www.chromium.org"},
            .updated_allowlisted_origins = {},
            .expected_allowed_origins = {"https://www.chromium.org"},
            .expected_forbidden_origins = {"https://www.chromium.com"},
        }),
        NoRefreshTestParam({
            .allow_list_policy_name =
                policy::key::kGetDisplayMediaSetSelectAllScreensAllowedForUrls,
            .original_allowlisted_origins = {},
            .updated_allowlisted_origins = {"https://www.chromium.org"},
            .expected_allowed_origins = {},
            .expected_forbidden_origins = {},
        })));

INSTANTIATE_TEST_SUITE_P(
    SelectAllScreensDynamicRefreshTestWithParams,
    SelectAllScreensDynamicRefreshTest,
    testing::Values(NoRefreshTestParam({
                        .allow_list_policy_name =
                            policy::key::kMultiScreenCaptureAllowedForUrls,
                        .original_allowlisted_origins = {kValidIsolatedAppId1},
                        .updated_allowlisted_origins = {kValidIsolatedAppId1,
                                                        kValidIsolatedAppId2},
                        .expected_allowed_origins = {kValidIsolatedAppId1},
                        .expected_forbidden_origins = {kValidIsolatedAppId2},
                    }),
                    NoRefreshTestParam({
                        .allow_list_policy_name =
                            policy::key::kMultiScreenCaptureAllowedForUrls,
                        .original_allowlisted_origins = {},
                        .updated_allowlisted_origins = {kValidIsolatedAppId1,
                                                        kValidIsolatedAppId2},
                        .expected_allowed_origins = {},
                        .expected_forbidden_origins = {kValidIsolatedAppId1,
                                                       kValidIsolatedAppId2},
                    })));
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

using CaptureUtilsBrowserTest = InProcessBrowserTest;

IN_PROC_BROWSER_TEST_F(CaptureUtilsBrowserTest, MultiCaptureServiceExists) {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
  if (chromeos::LacrosService::Get()
          ->GetInterfaceVersion<crosapi::mojom::MultiCaptureService>() <
      static_cast<int>(crosapi::mojom::MultiCaptureService::MethodMinVersions::
                           kIsMultiCaptureAllowedMinVersion)) {
    GTEST_SKIP();
  }
#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)

  EXPECT_TRUE(capture_policy::GetMultiCaptureService());
}

IN_PROC_BROWSER_TEST_F(CaptureUtilsBrowserTest,
                       NoPolicySetMultiCaptureServiceMaybeExists) {
  Browser* current_browser = browser();
  TabStripModel* current_tab_strip_model = current_browser->tab_strip_model();
  content::WebContents* current_web_contents =
      current_tab_strip_model->GetWebContentsAt(0);

  base::test::TestFuture<bool> future;
  capture_policy::CheckGetAllScreensMediaAllowed(
      current_web_contents->GetBrowserContext(), GURL(kValidIsolatedAppId1),
      future.GetCallback());
  ASSERT_TRUE(future.Wait());
  EXPECT_FALSE(future.Get<bool>());
}