|  | // Copyright 2020 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/ash/extensions/extensions_permissions_tracker.h" | 
|  |  | 
|  | #include "base/memory/raw_ptr.h" | 
|  | #include "chrome/browser/browser_process.h" | 
|  | #include "chrome/common/pref_names.h" | 
|  | #include "chrome/test/base/scoped_testing_local_state.h" | 
|  | #include "chrome/test/base/testing_browser_process.h" | 
|  | #include "chrome/test/base/testing_profile.h" | 
|  | #include "chromeos/ash/components/login/login_state/scoped_test_public_session_login_state.h" | 
|  | #include "components/sync_preferences/testing_pref_service_syncable.h" | 
|  | #include "content/public/test/browser_task_environment.h" | 
|  | #include "extensions/browser/pref_names.h" | 
|  | #include "extensions/common/extension_builder.h" | 
|  | #include "extensions/common/permissions/permissions_data.h" | 
|  | #include "testing/gmock/include/gmock/gmock.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | using ::testing::_; | 
|  | using ::testing::Return; | 
|  |  | 
|  | namespace extensions { | 
|  |  | 
|  | namespace { | 
|  | constexpr char kExtensionId1[] = "id1"; | 
|  | constexpr char kExtensionId2[] = "id2"; | 
|  | constexpr char kExtensionId3[] = "id3"; | 
|  | constexpr char kExtensionUrl1[] = "url1"; | 
|  | constexpr char kExtensionUrl2[] = "url2"; | 
|  | constexpr char kExtensionUrl3[] = "url3"; | 
|  | const char* const kSafePermissionsSet1[] = {"accessibilityFeatures.modify", | 
|  | "accessibilityFeatures.read"}; | 
|  |  | 
|  | const char* const kSafePermissionsSet2[] = {"background", "alarms"}; | 
|  |  | 
|  | const char* const kUnsafePermissionsSet1[] = {"debugger", "history", "input"}; | 
|  |  | 
|  | const char* const kUnsafePermissionsSet2[] = {"topSites", "ttsEngine", | 
|  | "webNavigation"}; | 
|  | }  // namespace | 
|  |  | 
|  | class MockExtensionsPermissionsTracker : public ExtensionsPermissionsTracker { | 
|  | public: | 
|  | MockExtensionsPermissionsTracker(ExtensionRegistry* registry, | 
|  | content::BrowserContext* browser_context) | 
|  | : ExtensionsPermissionsTracker(registry, browser_context) { | 
|  | safe_permissions_.insert( | 
|  | kSafePermissionsSet1, | 
|  | kSafePermissionsSet1 + std::size(kSafePermissionsSet1)); | 
|  | safe_permissions_.insert( | 
|  | kSafePermissionsSet2, | 
|  | kSafePermissionsSet2 + std::size(kSafePermissionsSet2)); | 
|  | } | 
|  |  | 
|  | // ExtensionsPermissionsTracker: | 
|  | bool IsSafePerms(const PermissionsData* perms_data) const override { | 
|  | std::set<std::string> perms_strings = | 
|  | perms_data->active_permissions().GetAPIsAsStrings(); | 
|  | for (const auto& perm : perms_strings) { | 
|  | if (safe_permissions_.find(perm) == safe_permissions_.end()) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | private: | 
|  | std::set<std::string> safe_permissions_; | 
|  | }; | 
|  |  | 
|  | class ExtensionsPermissionsTrackerTest : public testing::Test { | 
|  | public: | 
|  | ExtensionsPermissionsTrackerTest() | 
|  | : prefs_(profile_.GetTestingPrefService()), | 
|  | registry_(ExtensionRegistry::Get(&profile_)), | 
|  | testing_local_state_(TestingBrowserProcess::GetGlobal()) {} | 
|  |  | 
|  | ExtensionsPermissionsTrackerTest(const ExtensionsPermissionsTrackerTest&) = | 
|  | delete; | 
|  | ExtensionsPermissionsTrackerTest& operator=( | 
|  | const ExtensionsPermissionsTrackerTest&) = delete; | 
|  |  | 
|  | base::Value::Dict SetupForceList() { | 
|  | base::Value::Dict dict; | 
|  | dict.Set(kExtensionId1, kExtensionUrl1); | 
|  | dict.Set(kExtensionId2, kExtensionUrl2); | 
|  | prefs_->SetManagedPref(pref_names::kInstallForceList, dict.Clone()); | 
|  | return dict; | 
|  | } | 
|  |  | 
|  | void SetupEmptyForceList() { | 
|  | prefs_->SetManagedPref(pref_names::kInstallForceList, base::Value::Dict()); | 
|  | } | 
|  |  | 
|  | void CreateExtensionsPermissionsTracker() { | 
|  | permissions_tracker_ = std::make_unique<MockExtensionsPermissionsTracker>( | 
|  | registry_, &profile_); | 
|  | } | 
|  |  | 
|  | void AddExtensionWithIdAndPermissions( | 
|  | const std::string& extension_id, | 
|  | const std::vector<std::string>& permissions) { | 
|  | auto extension = ExtensionBuilder(extension_id) | 
|  | .SetID(extension_id) | 
|  | .AddPermissions(permissions) | 
|  | .Build(); | 
|  | registry_->AddEnabled(extension); | 
|  |  | 
|  | registry_->TriggerOnLoaded(extension.get()); | 
|  | } | 
|  |  | 
|  | protected: | 
|  | content::BrowserTaskEnvironment task_environment_; | 
|  | TestingProfile profile_; | 
|  | raw_ptr<sync_preferences::TestingPrefServiceSyncable, ExperimentalAsh> prefs_; | 
|  | raw_ptr<ExtensionRegistry, ExperimentalAsh> registry_; | 
|  | ScopedTestingLocalState testing_local_state_; | 
|  | std::unique_ptr<MockExtensionsPermissionsTracker> permissions_tracker_; | 
|  | }; | 
|  |  | 
|  | TEST_F(ExtensionsPermissionsTrackerTest, EmptyForceList) { | 
|  | EXPECT_TRUE(testing_local_state_.Get()->GetBoolean( | 
|  | prefs::kManagedSessionUseFullLoginWarning)); | 
|  |  | 
|  | SetupEmptyForceList(); | 
|  | CreateExtensionsPermissionsTracker(); | 
|  |  | 
|  | EXPECT_FALSE(testing_local_state_.Get()->GetBoolean( | 
|  | prefs::kManagedSessionUseFullLoginWarning)); | 
|  | } | 
|  |  | 
|  | TEST_F(ExtensionsPermissionsTrackerTest, SafeForceListInstalled) { | 
|  | EXPECT_TRUE(testing_local_state_.Get()->GetBoolean( | 
|  | prefs::kManagedSessionUseFullLoginWarning)); | 
|  |  | 
|  | SetupForceList(); | 
|  | CreateExtensionsPermissionsTracker(); | 
|  |  | 
|  | std::vector<std::string> v1( | 
|  | kSafePermissionsSet1, | 
|  | kSafePermissionsSet1 + std::size(kSafePermissionsSet1)); | 
|  | AddExtensionWithIdAndPermissions(kExtensionId1, v1); | 
|  |  | 
|  | std::vector<std::string> v2( | 
|  | kSafePermissionsSet2, | 
|  | kSafePermissionsSet2 + std::size(kSafePermissionsSet2)); | 
|  | AddExtensionWithIdAndPermissions(kExtensionId2, v2); | 
|  |  | 
|  | EXPECT_FALSE(testing_local_state_.Get()->GetBoolean( | 
|  | prefs::kManagedSessionUseFullLoginWarning)); | 
|  | } | 
|  |  | 
|  | TEST_F(ExtensionsPermissionsTrackerTest, UnsafeForceListInstalled) { | 
|  | SetupForceList(); | 
|  | CreateExtensionsPermissionsTracker(); | 
|  |  | 
|  | std::vector<std::string> v1( | 
|  | kUnsafePermissionsSet1, | 
|  | kUnsafePermissionsSet1 + std::size(kUnsafePermissionsSet1)); | 
|  |  | 
|  | std::vector<std::string> v2( | 
|  | kUnsafePermissionsSet2, | 
|  | kUnsafePermissionsSet2 + std::size(kUnsafePermissionsSet2)); | 
|  |  | 
|  | AddExtensionWithIdAndPermissions(kExtensionId1, v1); | 
|  | AddExtensionWithIdAndPermissions(kExtensionId2, v2); | 
|  |  | 
|  | EXPECT_TRUE(testing_local_state_.Get()->GetBoolean( | 
|  | prefs::kManagedSessionUseFullLoginWarning)); | 
|  | } | 
|  |  | 
|  | TEST_F(ExtensionsPermissionsTrackerTest, MixedForceListInstalled) { | 
|  | SetupForceList(); | 
|  | CreateExtensionsPermissionsTracker(); | 
|  |  | 
|  | std::vector<std::string> v1( | 
|  | kUnsafePermissionsSet1, | 
|  | kUnsafePermissionsSet1 + std::size(kUnsafePermissionsSet1)); | 
|  | AddExtensionWithIdAndPermissions(kExtensionId1, v1); | 
|  |  | 
|  | std::vector<std::string> v2( | 
|  | kSafePermissionsSet2, | 
|  | kSafePermissionsSet2 + std::size(kSafePermissionsSet2)); | 
|  | AddExtensionWithIdAndPermissions(kExtensionId2, v2); | 
|  |  | 
|  | EXPECT_TRUE(testing_local_state_.Get()->GetBoolean( | 
|  | prefs::kManagedSessionUseFullLoginWarning)); | 
|  | } | 
|  |  | 
|  | TEST_F(ExtensionsPermissionsTrackerTest, ForceListIncreased) { | 
|  | auto dict = SetupForceList(); | 
|  | CreateExtensionsPermissionsTracker(); | 
|  |  | 
|  | std::vector<std::string> v1( | 
|  | kSafePermissionsSet1, | 
|  | kSafePermissionsSet1 + std::size(kSafePermissionsSet1)); | 
|  | AddExtensionWithIdAndPermissions(kExtensionId1, v1); | 
|  |  | 
|  | std::vector<std::string> v2( | 
|  | kSafePermissionsSet2, | 
|  | kSafePermissionsSet2 + std::size(kSafePermissionsSet2)); | 
|  | AddExtensionWithIdAndPermissions(kExtensionId2, v2); | 
|  |  | 
|  | EXPECT_FALSE(testing_local_state_.Get()->GetBoolean( | 
|  | prefs::kManagedSessionUseFullLoginWarning)); | 
|  |  | 
|  | dict.Set(kExtensionId3, kExtensionUrl3); | 
|  | prefs_->SetManagedPref(pref_names::kInstallForceList, std::move(dict)); | 
|  |  | 
|  | std::vector<std::string> v3( | 
|  | kUnsafePermissionsSet1, | 
|  | kUnsafePermissionsSet1 + std::size(kUnsafePermissionsSet1)); | 
|  | AddExtensionWithIdAndPermissions(kExtensionId3, v3); | 
|  |  | 
|  | EXPECT_TRUE(testing_local_state_.Get()->GetBoolean( | 
|  | prefs::kManagedSessionUseFullLoginWarning)); | 
|  | } | 
|  |  | 
|  | TEST_F(ExtensionsPermissionsTrackerTest, ForceListDecreased) { | 
|  | auto dict = SetupForceList(); | 
|  | CreateExtensionsPermissionsTracker(); | 
|  |  | 
|  | std::vector<std::string> v1( | 
|  | kUnsafePermissionsSet1, | 
|  | kUnsafePermissionsSet1 + std::size(kUnsafePermissionsSet1)); | 
|  | AddExtensionWithIdAndPermissions(kExtensionId1, v1); | 
|  |  | 
|  | std::vector<std::string> v2( | 
|  | kSafePermissionsSet2, | 
|  | kSafePermissionsSet2 + std::size(kSafePermissionsSet2)); | 
|  | AddExtensionWithIdAndPermissions(kExtensionId2, v2); | 
|  |  | 
|  | EXPECT_TRUE(testing_local_state_.Get()->GetBoolean( | 
|  | prefs::kManagedSessionUseFullLoginWarning)); | 
|  |  | 
|  | dict.Remove(kExtensionId1); | 
|  | prefs_->SetManagedPref(pref_names::kInstallForceList, std::move(dict)); | 
|  | EXPECT_FALSE(testing_local_state_.Get()->GetBoolean( | 
|  | prefs::kManagedSessionUseFullLoginWarning)); | 
|  | } | 
|  |  | 
|  | TEST_F(ExtensionsPermissionsTrackerTest, SafePendingExtensions) { | 
|  | auto dict = SetupForceList(); | 
|  | CreateExtensionsPermissionsTracker(); | 
|  |  | 
|  | std::vector<std::string> v1( | 
|  | kSafePermissionsSet1, | 
|  | kSafePermissionsSet1 + std::size(kSafePermissionsSet1)); | 
|  | AddExtensionWithIdAndPermissions(kExtensionId1, v1); | 
|  |  | 
|  | EXPECT_TRUE(testing_local_state_.Get()->GetBoolean( | 
|  | prefs::kManagedSessionUseFullLoginWarning)); | 
|  |  | 
|  | std::vector<std::string> v2( | 
|  | kSafePermissionsSet2, | 
|  | kSafePermissionsSet2 + std::size(kSafePermissionsSet2)); | 
|  | AddExtensionWithIdAndPermissions(kExtensionId2, v2); | 
|  |  | 
|  | EXPECT_FALSE(testing_local_state_.Get()->GetBoolean( | 
|  | prefs::kManagedSessionUseFullLoginWarning)); | 
|  | } | 
|  |  | 
|  | TEST_F(ExtensionsPermissionsTrackerTest, UnsafePendingExtensions) { | 
|  | SetupForceList(); | 
|  | CreateExtensionsPermissionsTracker(); | 
|  |  | 
|  | std::vector<std::string> v1( | 
|  | kSafePermissionsSet1, | 
|  | kSafePermissionsSet1 + std::size(kSafePermissionsSet1)); | 
|  | AddExtensionWithIdAndPermissions(kExtensionId1, v1); | 
|  |  | 
|  | EXPECT_TRUE(testing_local_state_.Get()->GetBoolean( | 
|  | prefs::kManagedSessionUseFullLoginWarning)); | 
|  |  | 
|  | std::vector<std::string> v2( | 
|  | kUnsafePermissionsSet1, | 
|  | kUnsafePermissionsSet1 + std::size(kUnsafePermissionsSet1)); | 
|  | AddExtensionWithIdAndPermissions(kExtensionId2, v2); | 
|  |  | 
|  | EXPECT_TRUE(testing_local_state_.Get()->GetBoolean( | 
|  | prefs::kManagedSessionUseFullLoginWarning)); | 
|  | } | 
|  |  | 
|  | TEST_F(ExtensionsPermissionsTrackerTest, UnsafeForceListChanged) { | 
|  | auto dict = SetupForceList(); | 
|  | CreateExtensionsPermissionsTracker(); | 
|  |  | 
|  | std::vector<std::string> v1( | 
|  | kSafePermissionsSet1, | 
|  | kSafePermissionsSet1 + std::size(kSafePermissionsSet1)); | 
|  | AddExtensionWithIdAndPermissions(kExtensionId1, v1); | 
|  |  | 
|  | std::vector<std::string> v2( | 
|  | kUnsafePermissionsSet1, | 
|  | kUnsafePermissionsSet1 + std::size(kUnsafePermissionsSet1)); | 
|  | AddExtensionWithIdAndPermissions(kExtensionId2, v2); | 
|  |  | 
|  | EXPECT_TRUE(testing_local_state_.Get()->GetBoolean( | 
|  | prefs::kManagedSessionUseFullLoginWarning)); | 
|  |  | 
|  | dict.Remove(kExtensionId1); | 
|  | prefs_->SetManagedPref(pref_names::kInstallForceList, dict.Clone()); | 
|  |  | 
|  | EXPECT_TRUE(testing_local_state_.Get()->GetBoolean( | 
|  | prefs::kManagedSessionUseFullLoginWarning)); | 
|  |  | 
|  | dict.Remove(kExtensionId2); | 
|  | prefs_->SetManagedPref(pref_names::kInstallForceList, dict.Clone()); | 
|  |  | 
|  | EXPECT_FALSE(testing_local_state_.Get()->GetBoolean( | 
|  | prefs::kManagedSessionUseFullLoginWarning)); | 
|  | } | 
|  |  | 
|  | TEST_F(ExtensionsPermissionsTrackerTest, OtherExtensionsLoaded) { | 
|  | SetupForceList(); | 
|  | CreateExtensionsPermissionsTracker(); | 
|  |  | 
|  | std::vector<std::string> v1( | 
|  | kSafePermissionsSet1, | 
|  | kSafePermissionsSet1 + std::size(kSafePermissionsSet1)); | 
|  | AddExtensionWithIdAndPermissions(kExtensionId1, v1); | 
|  |  | 
|  | std::vector<std::string> v2( | 
|  | kSafePermissionsSet1, | 
|  | kSafePermissionsSet1 + std::size(kSafePermissionsSet1)); | 
|  | AddExtensionWithIdAndPermissions(kExtensionId2, v2); | 
|  |  | 
|  | std::vector<std::string> v3( | 
|  | kUnsafePermissionsSet1, | 
|  | kUnsafePermissionsSet1 + std::size(kUnsafePermissionsSet1)); | 
|  | AddExtensionWithIdAndPermissions(kExtensionId3, v3); | 
|  |  | 
|  | EXPECT_FALSE(testing_local_state_.Get()->GetBoolean( | 
|  | prefs::kManagedSessionUseFullLoginWarning)); | 
|  | } | 
|  |  | 
|  | }  // namespace extensions |