chromium/chrome/browser/ash/extensions/device_local_account_management_policy_provider_unittest.cc

// Copyright 2013 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/device_local_account_management_policy_provider.h"

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

#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/values.h"
#include "chromeos/ash/components/login/login_state/scoped_test_public_session_login_state.h"
#include "extensions/common/extension.h"
#include "extensions/common/manifest.h"
#include "extensions/common/manifest_constants.h"
#include "testing/gtest/include/gtest/gtest.h"

using extensions::mojom::ManifestLocation;

namespace chromeos {

namespace {

scoped_refptr<const extensions::Extension> CreateExtensionFromValues(
    const std::string& id,
    ManifestLocation location,
    base::Value::Dict& values,
    int flags) {
  values.Set(extensions::manifest_keys::kName, "test");
  values.Set(extensions::manifest_keys::kVersion, "0.1");
  values.Set(extensions::manifest_keys::kManifestVersion, 2);
  std::string error;
  return extensions::Extension::Create(base::FilePath(), location, values,
                                       flags, id, &error);
}

scoped_refptr<const extensions::Extension> CreateRegularExtension(
    const std::string& id) {
  base::Value::Dict values;
  return CreateExtensionFromValues(id, ManifestLocation::kInternal, values,
                                   extensions::Extension::NO_FLAGS);
}

scoped_refptr<const extensions::Extension> CreateExternalComponentExtension() {
  base::Value::Dict values;
  return CreateExtensionFromValues(std::string(),
                                   ManifestLocation::kExternalComponent, values,
                                   extensions::Extension::NO_FLAGS);
}

scoped_refptr<const extensions::Extension> CreateComponentExtension() {
  base::Value::Dict values;
  return CreateExtensionFromValues(std::string(), ManifestLocation::kComponent,
                                   values, extensions::Extension::NO_FLAGS);
}

scoped_refptr<const extensions::Extension> CreatePlatformAppWithExtraValues(
    const base::Value::Dict& extra_values,
    ManifestLocation location,
    int flags) {
  base::Value::Dict values;
  values.SetByDottedPath("app.background.page", "background.html");
  values.Merge(extra_values.Clone());
  return CreateExtensionFromValues(std::string(), location, values, flags);
}

scoped_refptr<const extensions::Extension> CreatePlatformApp() {
  base::Value::Dict values;
  return CreatePlatformAppWithExtraValues(values, ManifestLocation::kInternal,
                                          extensions::Extension::NO_FLAGS);
}

}  // namespace

TEST(DeviceLocalAccountManagementPolicyProviderTest, PublicSession) {
  DeviceLocalAccountManagementPolicyProvider provider(
      policy::DeviceLocalAccountType::kPublicSession);
  // Set the login state to a public session.
  ash::ScopedTestPublicSessionLoginState login_state;

  // Verify that if an extension's location has been whitelisted for use in
  // public sessions, the extension can be installed.
  scoped_refptr<const extensions::Extension> extension =
      CreateExternalComponentExtension();
  ASSERT_TRUE(extension.get());
  std::u16string error;
  EXPECT_TRUE(provider.UserMayLoad(extension.get(), &error));
  EXPECT_EQ(std::u16string(), error);
  error.clear();

  extension = CreateComponentExtension();
  ASSERT_TRUE(extension.get());
  EXPECT_TRUE(provider.UserMayLoad(extension.get(), &error));
  EXPECT_EQ(std::u16string(), error);
  error.clear();

  // Verify that if neither the location, type nor the ID of an extension have
  // been whitelisted for use in public sessions, the extension cannot be
  // installed.
  extension = CreateRegularExtension(std::string());
  ASSERT_TRUE(extension.get());
  EXPECT_FALSE(provider.UserMayLoad(extension.get(), &error));
  EXPECT_NE(std::u16string(), error);
  error.clear();

  // Verify that a minimal platform app can be installed from location
  // EXTERNAL_POLICY.
  {
    base::Value::Dict values;
    extension = CreatePlatformAppWithExtraValues(
        values, ManifestLocation::kExternalPolicy,
        extensions::Extension::NO_FLAGS);
    ASSERT_TRUE(extension);

    EXPECT_TRUE(provider.UserMayLoad(extension.get(), &error));
    EXPECT_EQ(std::u16string(), error);
    error.clear();
  }

  // Verify that a minimal platform app can be installed from location
  // EXTERNAL_POLICY_DOWNLOAD.
  {
    base::Value::Dict values;
    extension = CreatePlatformAppWithExtraValues(
        values, ManifestLocation::kExternalPolicyDownload,
        extensions::Extension::NO_FLAGS);
    ASSERT_TRUE(extension);

    EXPECT_TRUE(provider.UserMayLoad(extension.get(), &error));
    EXPECT_EQ(std::u16string(), error);
    error.clear();
  }

  // Verify that a minimal platform app cannot be installed from location
  // UNPACKED.
  {
    base::Value::Dict values;
    extension = CreatePlatformAppWithExtraValues(
        values, ManifestLocation::kUnpacked, extensions::Extension::NO_FLAGS);
    ASSERT_TRUE(extension);

    EXPECT_FALSE(provider.UserMayLoad(extension.get(), &error));
    EXPECT_NE(std::u16string(), error);
    error.clear();
  }

  // Verify that a platform app with all safe manifest entries can be installed.
  {
    base::Value::Dict values;
    values.Set(extensions::manifest_keys::kDescription, "something");
    values.Set(extensions::manifest_keys::kShortName, "something else");
    base::Value::List permissions;
    permissions.Append("alarms");
    permissions.Append("background");
    values.Set(extensions::manifest_keys::kPermissions, std::move(permissions));
    base::Value::List optional_permissions;
    optional_permissions.Append("alarms");
    optional_permissions.Append("background");
    values.Set(extensions::manifest_keys::kOptionalPermissions,
               std::move(optional_permissions));
    extension = CreatePlatformAppWithExtraValues(
        values, ManifestLocation::kExternalPolicy,
        extensions::Extension::NO_FLAGS);
    ASSERT_TRUE(extension);

    EXPECT_TRUE(provider.UserMayLoad(extension.get(), &error));
    EXPECT_EQ(std::u16string(), error);
    error.clear();
  }

  // Verify that a platform app with a safe manifest entry under "app" can be
  // installed.
  {
    base::Value::Dict values;
    values.SetByDottedPath("app.content_security_policy", "something2");
    extension = CreatePlatformAppWithExtraValues(
        values, ManifestLocation::kExternalPolicy,
        extensions::Extension::NO_FLAGS);
    ASSERT_TRUE(extension);

    EXPECT_TRUE(provider.UserMayLoad(extension.get(), &error));
    EXPECT_EQ(std::u16string(), error);
    error.clear();
  }

  // Verify that a hosted app with a safe manifest entry under "app" can be
  // installed.
  {
    base::Value::Dict values;
    values.Set(extensions::manifest_keys::kApp, base::Value::Dict());
    values.SetByDottedPath(extensions::manifest_keys::kWebURLs,
                           base::Value::List());
    values.SetByDottedPath("app.content_security_policy", "something2");
    extension = CreateExtensionFromValues(
        std::string(), ManifestLocation::kExternalPolicy, values,
        extensions::Extension::NO_FLAGS);
    ASSERT_TRUE(extension);

    EXPECT_TRUE(provider.UserMayLoad(extension.get(), &error));
    EXPECT_EQ(std::u16string(), error);
    error.clear();
  }

  // Verify that a platform app with a url_handlers manifest entry and which is
  // installed through the web store can be installed.
  {
    base::Value::List matches;
    matches.Append("https://example.com/*");
    base::Value::Dict values;
    values.SetByDottedPath("url_handlers.example_com.matches",
                           std::move(matches));
    values.SetByDottedPath("url_handlers.example_com.title", "example title");

    extension = CreatePlatformAppWithExtraValues(
        values, ManifestLocation::kExternalPolicy,
        extensions::Extension::FROM_WEBSTORE);
    ASSERT_TRUE(extension);

    EXPECT_TRUE(provider.UserMayLoad(extension.get(), &error));
    EXPECT_EQ(std::u16string(), error);
    error.clear();
  }

  // Verify that a platform app with remote URL permissions can be installed.
  {
    base::Value::List permissions;
    permissions.Append("https://example.com/");
    permissions.Append("http://example.com/");
    permissions.Append("ftp://example.com/");
    base::Value::Dict values;
    values.Set(extensions::manifest_keys::kPermissions, std::move(permissions));

    extension = CreatePlatformAppWithExtraValues(
        values, ManifestLocation::kExternalPolicy,
        extensions::Extension::NO_FLAGS);
    ASSERT_TRUE(extension);

    EXPECT_TRUE(provider.UserMayLoad(extension.get(), &error));
    EXPECT_EQ(std::u16string(), error);
    error.clear();
  }

  // Verify that a platform app with socket dictionary permission can be
  // installed.
  {
    base::Value::Dict socket;
    base::Value::List tcp_list;
    tcp_list.Append("tcp-connect");
    socket.Set("socket", std::move(tcp_list));
    base::Value::List permissions;
    permissions.Append(std::move(socket));
    base::Value::Dict values;
    values.Set(extensions::manifest_keys::kPermissions, std::move(permissions));

    extension = CreatePlatformAppWithExtraValues(
        values, ManifestLocation::kExternalPolicy,
        extensions::Extension::NO_FLAGS);
    ASSERT_TRUE(extension);

    EXPECT_TRUE(provider.UserMayLoad(extension.get(), &error));
    EXPECT_EQ(std::u16string(), error);
    error.clear();
  }

  // Verify that an extension can be installed.
  {
    base::Value::Dict values;
    extension = CreateExtensionFromValues(
        std::string(), ManifestLocation::kExternalPolicy, values,
        extensions::Extension::NO_FLAGS);
    ASSERT_TRUE(extension);

    EXPECT_TRUE(provider.UserMayLoad(extension.get(), &error));
    EXPECT_EQ(std::u16string(), error);
    error.clear();
  }

  // Verify that a shared_module can be installed.
  {
    base::Value::Dict values;
    values.SetByDottedPath("export.whitelist", base::Value::List());  // nocheck
    extension = CreateExtensionFromValues(
        std::string(), ManifestLocation::kExternalPolicy, values,
        extensions::Extension::NO_FLAGS);
    ASSERT_TRUE(extension);

    EXPECT_TRUE(provider.UserMayLoad(extension.get(), &error));
    EXPECT_EQ(std::u16string(), error);
    error.clear();
  }

  // Verify that a theme can be installed.
  {
    base::Value::Dict values;
    values.Set("theme", base::Value::Dict());
    extension = CreateExtensionFromValues(
        std::string(), ManifestLocation::kExternalPolicy, values,
        extensions::Extension::NO_FLAGS);
    ASSERT_TRUE(extension);

    EXPECT_TRUE(provider.UserMayLoad(extension.get(), &error));
    EXPECT_EQ(std::u16string(), error);
    error.clear();
  }
}

TEST(DeviceLocalAccountManagementPolicyProviderTest, KioskAppSessions) {
  static constexpr policy::DeviceLocalAccountType kTypes[] = {
      policy::DeviceLocalAccountType::kKioskApp,
      policy::DeviceLocalAccountType::kWebKioskApp,
  };

  for (auto type : kTypes) {
    LOG(INFO) << "Testing device local account type = "<< static_cast<int>(type);
    DeviceLocalAccountManagementPolicyProvider provider(type);

    // Verify that a platform app can be installed.
    scoped_refptr<const extensions::Extension> extension = CreatePlatformApp();
    ASSERT_TRUE(extension.get());
    std::u16string error;
    EXPECT_TRUE(provider.UserMayLoad(extension.get(), &error));
    EXPECT_EQ(std::u16string(), error);
    error.clear();

    // Verify that an extension whose location has been whitelisted for use in
    // other types of device-local accounts cannot be installed in a single-app
    // kiosk session.
    extension = CreateExternalComponentExtension();
    ASSERT_TRUE(extension.get());
    EXPECT_TRUE(provider.UserMayLoad(extension.get(), &error));
    EXPECT_EQ(std::u16string(), error);
    error.clear();

    extension = CreateComponentExtension();
    ASSERT_TRUE(extension.get());
    EXPECT_TRUE(provider.UserMayLoad(extension.get(), &error));
    EXPECT_EQ(std::u16string(), error);
    error.clear();
  }
}

}  // namespace chromeos