Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(54)

Unified Diff: chrome/browser/chromeos/policy/device_local_account_browsertest.cc

Issue 24261010: Allow explicitly whitelisted apps/extensions in public sessions (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Comments addressed. Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/policy/device_local_account_browsertest.cc
diff --git a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
index c125281f4547b33a63715d117fe8efc9f0af7643..891f5107e95d68d56e0bb619f4a1ecaa85dc5865 100644
--- a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
@@ -4,9 +4,11 @@
#include <map>
#include <string>
+#include <utility>
#include "base/basictypes.h"
#include "base/bind.h"
+#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/file_util.h"
@@ -17,6 +19,7 @@
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
@@ -33,6 +36,8 @@
#include "chrome/browser/chromeos/policy/device_local_account.h"
#include "chrome/browser/chromeos/policy/device_policy_builder.h"
#include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/policy/cloud/cloud_policy_constants.h"
#include "chrome/browser/policy/cloud/policy_builder.h"
@@ -52,12 +57,14 @@
#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension.h"
#include "chromeos/chromeos_switches.h"
#include "chromeos/dbus/cryptohome_client.h"
#include "chromeos/dbus/dbus_method_call_status.h"
#include "chromeos/dbus/fake_cryptohome_client.h"
#include "chromeos/dbus/fake_session_manager_client.h"
#include "chromeos/dbus/session_manager_client.h"
+#include "content/public/browser/notification_details.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "content/public/test/browser_test_utils.h"
@@ -65,7 +72,10 @@
#include "crypto/rsa_private_key.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
+#include "net/http/http_status_code.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
#include "ui/base/l10n/l10n_util.h"
@@ -91,6 +101,160 @@ const char* kStartupURLs[] = {
};
const char kExistentTermsOfServicePath[] = "chromeos/enterprise/tos.txt";
const char kNonexistentTermsOfServicePath[] = "chromeos/enterprise/tos404.txt";
+const char kRelativeUpdateURL[] = "/service/update2/crx";
+const char kUpdateManifestHeader[] =
+ "<?xml version='1.0' encoding='UTF-8'?>\n"
+ "<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>\n";
+const char kUpdateManifestTemplate[] =
+ " <app appid='%s'>\n"
+ " <updatecheck codebase='%s' version='%s' />\n"
+ " </app>\n";
+const char kUpdateManifestFooter[] =
+ "</gupdate>\n";
+const char kHostedAppID[] = "kbmnembihfiondgfjekmnmcbddelicoi";
+const char kHostedAppCRXPath[] = "extensions/hosted_app.crx";
+const char kHostedAppVersion[] = "0.1";
+const char kGoodExtensionID[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
+const char kGoodExtensionPath[] = "extensions/good.crx";
+const char kGoodExtensionVersion[] = "1.0";
+
+// Helper that serves extension update manifests to Chrome. The helper registers
+// itself with the |test_server|, serving update manifests for all extensions in
+// |extension_map| at |relative_update_url|.
+// The CRX files for these extensions must be served by the same |test_server|.
+// For each extension, the |extension_map| should contain the path to the CRX
+// file (relative to the directory from which the |test_server| serves files)
+// and its version.
+class TestingUpdateManifestProvider {
+ public:
+ typedef std::map<std::string, std::pair<std::string, std::string> >
+ ExtensionMap;
+
+ TestingUpdateManifestProvider(
+ net::test_server::EmbeddedTestServer* test_server,
+ const std::string& relative_update_url,
+ const ExtensionMap& extension_map);
+ ~TestingUpdateManifestProvider();
+
+ scoped_ptr<net::test_server::HttpResponse> HandleRequest(
+ const net::test_server::HttpRequest& request);
+
+ private:
+ net::test_server::EmbeddedTestServer* test_server_; // Not owned.
+ const std::string relative_update_url_;
+ const ExtensionMap extension_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestingUpdateManifestProvider);
+};
+
+class ExtensionInstallSuccessObserver
+ : public content::WindowedNotificationObserver {
+ public:
+ explicit ExtensionInstallSuccessObserver(const std::string& id);
+ ~ExtensionInstallSuccessObserver();
+
+ private:
+ bool CheckNotification();
+
+ const std::string id_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionInstallSuccessObserver);
+};
+
+class ExtensionInstallFailureObserver
+ : public content::WindowedNotificationObserver {
+ public:
+ explicit ExtensionInstallFailureObserver(const std::string& id);
+ ~ExtensionInstallFailureObserver();
+
+ private:
+ bool CheckNotification();
+
+ const string16 id_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionInstallFailureObserver);
+};
+
+ExtensionInstallSuccessObserver::ExtensionInstallSuccessObserver(
+ const std::string& id)
+ : content::WindowedNotificationObserver(
+ chrome::NOTIFICATION_EXTENSION_INSTALLED,
+ base::Bind(&ExtensionInstallSuccessObserver::CheckNotification,
+ base::Unretained(this))),
+ id_(id) {
+}
+
+ExtensionInstallSuccessObserver::~ExtensionInstallSuccessObserver() {
+}
+
+bool ExtensionInstallSuccessObserver::CheckNotification() {
+ return content::Details<const extensions::InstalledExtensionInfo>(
+ details())->extension->id() == id_;
+}
+
+ExtensionInstallFailureObserver::ExtensionInstallFailureObserver(
+ const std::string& id)
+ : content::WindowedNotificationObserver(
+ chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
+ base::Bind(&ExtensionInstallFailureObserver::CheckNotification,
+ base::Unretained(this))),
+ id_(UTF8ToUTF16(id)) {
+}
+
+ExtensionInstallFailureObserver::~ExtensionInstallFailureObserver() {
+}
+
+bool ExtensionInstallFailureObserver::CheckNotification() {
+ return content::Details<const string16>(details())->find(id_) !=
+ string16::npos;
+}
+
+TestingUpdateManifestProvider::TestingUpdateManifestProvider(
Mattias Nissler (ping if slow) 2013/09/25 12:04:08 Definition order doesn't match declaration order.
bartfab (slow) 2013/09/26 12:39:13 Done.
+ net::test_server::EmbeddedTestServer* test_server,
+ const std::string& relative_update_url,
+ const ExtensionMap& extension_map)
Mattias Nissler (ping if slow) 2013/09/25 12:04:08 Instead of passing in the map, can we just make an
bartfab (slow) 2013/09/26 12:39:13 Done.
+ : test_server_(test_server),
+ relative_update_url_(relative_update_url),
+ extension_map_(extension_map) {
+ test_server_->RegisterRequestHandler(
Mattias Nissler (ping if slow) 2013/09/25 12:04:08 I'd just leave this to the user.
bartfab (slow) 2013/09/26 12:39:13 Done.
+ base::Bind(&TestingUpdateManifestProvider::HandleRequest,
+ base::Unretained(this)));
+}
+
+TestingUpdateManifestProvider::~TestingUpdateManifestProvider() {
+}
+
+scoped_ptr<net::test_server::HttpResponse>
+ TestingUpdateManifestProvider::HandleRequest(
+ const net::test_server::HttpRequest& request) {
+ if (request.relative_url.find(relative_update_url_) != 0)
+ return scoped_ptr<net::test_server::HttpResponse>();
+
+ std::string content = kUpdateManifestHeader;
+ size_t id_pos = 0;
+ while ((id_pos = request.relative_url.find("id%3D", id_pos)) !=
+ std::string::npos) {
+ id_pos += 5;
+ const std::string id = request.relative_url.substr(id_pos, 32);
+ id_pos += 32;
+ ExtensionMap::const_iterator entry = extension_map_.find(id);
+ if (entry != extension_map_.end()) {
+ content += base::StringPrintf(
+ kUpdateManifestTemplate,
+ id.c_str(),
+ test_server_->GetURL(std::string("/") + entry->second.first)
+ .spec().c_str(),
+ entry->second.second.c_str());
+ }
+ }
+ content += kUpdateManifestFooter;
+ scoped_ptr<net::test_server::BasicHttpResponse>
+ http_response(new net::test_server::BasicHttpResponse);
+ http_response->set_code(net::HTTP_OK);
+ http_response->set_content(content);
+ http_response->set_content_type("text/xml");
+ return http_response.PassAs<net::test_server::HttpResponse>();
+}
} // namespace
@@ -421,6 +585,86 @@ IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, FullscreenDisallowed) {
EXPECT_FALSE(browser_window->IsFullscreen());
}
+IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExtensionWhitelist) {
+ // Make it possible to force-install a hosted app and an extension.
+ TestingUpdateManifestProvider::ExtensionMap extension_map;
+ extension_map[kHostedAppID] =
+ std::pair<std::string, std::string>(kHostedAppCRXPath,
+ kHostedAppVersion);
+ extension_map[kGoodExtensionID] =
+ std::pair<std::string, std::string>(kGoodExtensionPath,
+ kGoodExtensionVersion);
+ TestingUpdateManifestProvider testing_update_manifest_provider(
+ embedded_test_server(),
+ kRelativeUpdateURL,
+ extension_map);
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
+ // Specify policy to force-install the hosted app and the extension.
+ em::StringList* forcelist = device_local_account_policy_.payload()
+ .mutable_extensioninstallforcelist()->mutable_value();
+ forcelist->add_entries(base::StringPrintf(
+ "%s;%s",
+ kHostedAppID,
+ embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str()));
+ forcelist->add_entries(base::StringPrintf(
+ "%s;%s",
+ kGoodExtensionID,
+ embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str()));
+
+ UploadAndInstallDeviceLocalAccountPolicy();
+ AddPublicSessionToDevicePolicy(kAccountId1);
+
+ // This observes the display name becoming available as this indicates
+ // device-local account policy is fully loaded, which is a prerequisite for
+ // successful login.
+ content::WindowedNotificationObserver(
+ chrome::NOTIFICATION_USER_LIST_CHANGED,
+ base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
+
+ // Wait for the login UI to be ready.
+ chromeos::LoginDisplayHostImpl* host =
+ reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
+ chromeos::LoginDisplayHostImpl::default_host());
+ ASSERT_TRUE(host);
+ chromeos::OobeUI* oobe_ui = host->GetOobeUI();
+ ASSERT_TRUE(oobe_ui);
+ base::RunLoop run_loop;
+ const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop.QuitClosure());
+ if (!oobe_ui_ready)
+ run_loop.Run();
+
+ // Ensure that the browser stays alive, even though no windows are opened
+ // during session start.
+ chrome::StartKeepAlive();
+
+ // Start listening for app/extension installation results.
+ ExtensionInstallSuccessObserver hosted_app_observer(kHostedAppID);
+ ExtensionInstallFailureObserver extension_observer(kGoodExtensionID);
+
+ // Start login into the device-local account.
+ host->StartSignInScreen();
+ chromeos::ExistingUserController* controller =
+ chromeos::ExistingUserController::current_controller();
+ ASSERT_TRUE(controller);
+ controller->LoginAsPublicAccount(user_id_1_);
+
+ // Wait for the hosted app installation to succeed and the extension
+ // installation to fail.
+ hosted_app_observer.Wait();
+ extension_observer.Wait();
+
+ // Verify that the hosted app was installed.
+ Profile* profile = ProfileManager::GetDefaultProfile();
+ ASSERT_TRUE(profile);
+ ExtensionService* extension_service =
+ extensions::ExtensionSystem::Get(profile)->extension_service();
+ EXPECT_TRUE(extension_service->GetExtensionById(kHostedAppID, true));
+
+ // Verify that the extension was not installed.
+ EXPECT_FALSE(extension_service->GetExtensionById(kGoodExtensionID, true));
+}
+
class TermsOfServiceTest : public DeviceLocalAccountTest,
public testing::WithParamInterface<bool> {
};

Powered by Google App Engine
This is Rietveld 408576698