Commit 8c5d538e authored by Owen Min's avatar Owen Min Committed by Commit Bot

Prevent app_controller_mac.mm access lastProfile when EnterpriseStartupDialog is displayed.

Because the dialog must be displayed before the Profile initalization as
the process might load the extensions which might open browser windows.

TEST=Set up a invalid token by setting any non-empty string in policy.
     MachineLevelUserCloudPolicyEnrollmentToken.
     a) Login mac.
     b) Create com.google.Chrome.plist (org.chromium.Chromium.plist for chromium) for the
        following content:
         <?xml version="1.0" encoding="UTF-8"?>
         <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
         <plist version="1.0">
         <dict>
            <key>MachineLevelUserCloudPolicyEnrollmentToken</key>
            <string>invalid-token</string>
         </dict>
         </plist>
     (More details in https://support.google.com/chrome/a/answer/7550274?hl=en)
     Launch Chrome. Instead of the chrome window, there should be an error dialog indicates
     that launching is blocked.
     1) The error dialog could be hidden/shown, lose or gain focus without any issue.
     2) Clicking any option in the menu bar or dock menu shouldn't open any browser window.

Bug: 860540
Change-Id: Ibf4b7c2794a8ad78b9fedb2da67512508d3d7621
Reviewed-on: https://chromium-review.googlesource.com/1145862
Commit-Queue: Owen Min <zmin@chromium.org>
Reviewed-by: default avatarRobert Sesek <rsesek@chromium.org>
Reviewed-by: default avatarJulian Pastarmov <pastarmovj@chromium.org>
Cr-Commit-Position: refs/heads/master@{#580242}
parent 7d8b7c2d
...@@ -246,6 +246,10 @@ bool IsProfileSignedOut(Profile* profile) { ...@@ -246,6 +246,10 @@ bool IsProfileSignedOut(Profile* profile) {
// Given |webContents|, extracts a GURL to be used for Handoff. This may return // Given |webContents|, extracts a GURL to be used for Handoff. This may return
// the empty GURL. // the empty GURL.
- (GURL)handoffURLFromWebContents:(content::WebContents*)webContents; - (GURL)handoffURLFromWebContents:(content::WebContents*)webContents;
// Return false if Chrome startup is paused by dialog and AppController is
// called without any initialized Profile.
- (BOOL)isProfileReady;
@end @end
class AppControllerProfileObserver : public ProfileAttributesStorage::Observer { class AppControllerProfileObserver : public ProfileAttributesStorage::Observer {
...@@ -433,6 +437,8 @@ static base::mac::ScopedObjCClassSwizzler* g_swizzle_imk_input_session; ...@@ -433,6 +437,8 @@ static base::mac::ScopedObjCClassSwizzler* g_swizzle_imk_input_session;
} }
- (void)applicationWillHide:(NSNotification*)notification { - (void)applicationWillHide:(NSNotification*)notification {
if (![self isProfileReady])
return;
apps::ExtensionAppShimHandler::OnChromeWillHide(); apps::ExtensionAppShimHandler::OnChromeWillHide();
} }
...@@ -613,7 +619,7 @@ static base::mac::ScopedObjCClassSwizzler* g_swizzle_imk_input_session; ...@@ -613,7 +619,7 @@ static base::mac::ScopedObjCClassSwizzler* g_swizzle_imk_input_session;
} }
- (void)windowDidResignMain:(NSNotification*)notify { - (void)windowDidResignMain:(NSNotification*)notify {
if (chrome::GetTotalBrowserCount() == 0) { if (chrome::GetTotalBrowserCount() == 0 && [self isProfileReady]) {
[self windowChangedToProfile: [self windowChangedToProfile:
g_browser_process->profile_manager()->GetLastUsedProfile()]; g_browser_process->profile_manager()->GetLastUsedProfile()];
} }
...@@ -1012,7 +1018,7 @@ static base::mac::ScopedObjCClassSwizzler* g_swizzle_imk_input_session; ...@@ -1012,7 +1018,7 @@ static base::mac::ScopedObjCClassSwizzler* g_swizzle_imk_input_session;
// Ignore commands during session restore's browser creation. It uses a // Ignore commands during session restore's browser creation. It uses a
// nested run loop and commands dispatched during this operation cause // nested run loop and commands dispatched during this operation cause
// havoc. // havoc.
if (SessionRestore::IsRestoring(lastProfile) && if (lastProfile && SessionRestore::IsRestoring(lastProfile) &&
base::RunLoop::IsNestedOnCurrentThread()) { base::RunLoop::IsNestedOnCurrentThread()) {
return; return;
} }
...@@ -1322,16 +1328,20 @@ static base::mac::ScopedObjCClassSwizzler* g_swizzle_imk_input_session; ...@@ -1322,16 +1328,20 @@ static base::mac::ScopedObjCClassSwizzler* g_swizzle_imk_input_session;
[app registerServicesMenuSendTypes:types returnTypes:types]; [app registerServicesMenuSendTypes:types returnTypes:types];
} }
// Return null if Chrome is not ready or there is no ProfileManager.
- (Profile*)lastProfile { - (Profile*)lastProfile {
// Return the profile of the last-used Browser, if available. // Return the profile of the last-used Browser, if available.
if (lastProfile_) if (lastProfile_)
return lastProfile_; return lastProfile_;
if (![self isProfileReady])
return nullptr;
// On first launch, use the logic that ChromeBrowserMain uses to determine // On first launch, use the logic that ChromeBrowserMain uses to determine
// the initial profile. // the initial profile.
ProfileManager* profile_manager = g_browser_process->profile_manager(); ProfileManager* profile_manager = g_browser_process->profile_manager();
if (!profile_manager) if (!profile_manager)
return NULL; return nullptr;
return profile_manager->GetProfile( return profile_manager->GetProfile(
GetStartupProfilePath(profile_manager->user_data_dir(), GetStartupProfilePath(profile_manager->user_data_dir(),
...@@ -1341,6 +1351,9 @@ static base::mac::ScopedObjCClassSwizzler* g_swizzle_imk_input_session; ...@@ -1341,6 +1351,9 @@ static base::mac::ScopedObjCClassSwizzler* g_swizzle_imk_input_session;
- (Profile*)safeLastProfileForNewWindows { - (Profile*)safeLastProfileForNewWindows {
Profile* profile = [self lastProfile]; Profile* profile = [self lastProfile];
if (!profile)
return nullptr;
// Guest sessions must always be OffTheRecord. Use that when opening windows. // Guest sessions must always be OffTheRecord. Use that when opening windows.
if (profile->IsGuestSession()) if (profile->IsGuestSession())
return profile->GetOffTheRecordProfile(); return profile->GetOffTheRecordProfile();
...@@ -1705,6 +1718,12 @@ static base::mac::ScopedObjCClassSwizzler* g_swizzle_imk_input_session; ...@@ -1705,6 +1718,12 @@ static base::mac::ScopedObjCClassSwizzler* g_swizzle_imk_input_session;
return webContents->GetVisibleURL(); return webContents->GetVisibleURL();
} }
- (BOOL)isProfileReady {
return !g_browser_process->browser_policy_connector()
->machine_level_user_cloud_policy_controller()
->IsEnterpriseStartupDialogShowing();
}
#pragma mark - HandoffActiveURLObserverBridgeDelegate #pragma mark - HandoffActiveURLObserverBridgeDelegate
- (void)handoffActiveURLChanged:(content::WebContents*)webContents { - (void)handoffActiveURLChanged:(content::WebContents*)webContents {
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "base/test/metrics/histogram_tester.h" #include "base/test/metrics/histogram_tester.h"
#include "base/threading/thread_restrictions.h" #include "base/threading/thread_restrictions.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_browser_main.h" #include "chrome/browser/chrome_browser_main.h"
#include "chrome/browser/chrome_browser_main_extra_parts.h" #include "chrome/browser/chrome_browser_main_extra_parts.h"
...@@ -25,6 +26,7 @@ ...@@ -25,6 +26,7 @@
#include "chrome/browser/policy/chrome_browser_policy_connector.h" #include "chrome/browser/policy/chrome_browser_policy_connector.h"
#include "chrome/browser/policy/machine_level_user_cloud_policy_controller.h" #include "chrome/browser/policy/machine_level_user_cloud_policy_controller.h"
#include "chrome/browser/policy/test/local_policy_test_server.h" #include "chrome/browser/policy/test/local_policy_test_server.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_result_codes.h" #include "chrome/common/chrome_result_codes.h"
#include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/in_process_browser_test.h"
...@@ -42,6 +44,10 @@ ...@@ -42,6 +44,10 @@
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "ui/views/test/widget_test.h" #include "ui/views/test/widget_test.h"
#if defined(OS_MACOSX)
#include "chrome/browser/policy/cloud/machine_level_user_cloud_policy_browsertest_mac_util.h"
#endif
using testing::DoAll; using testing::DoAll;
using testing::Invoke; using testing::Invoke;
using testing::InvokeWithoutArgs; using testing::InvokeWithoutArgs;
...@@ -65,6 +71,10 @@ class MachineLevelUserCloudPolicyControllerObserver ...@@ -65,6 +71,10 @@ class MachineLevelUserCloudPolicyControllerObserver
public: public:
void OnPolicyRegisterFinished(bool succeeded) override { void OnPolicyRegisterFinished(bool succeeded) override {
if (!succeeded) { if (!succeeded) {
EXPECT_EQ(0u, chrome::GetTotalBrowserCount());
#if defined(OS_MACOSX)
PostAppControllerNSNotifications();
#endif
// Close the error dialog. // Close the error dialog.
ASSERT_EQ(1u, views::test::WidgetTest::GetAllWidgets().size()); ASSERT_EQ(1u, views::test::WidgetTest::GetAllWidgets().size());
(*views::test::WidgetTest::GetAllWidgets().begin())->Close(); (*views::test::WidgetTest::GetAllWidgets().begin())->Close();
...@@ -424,6 +434,7 @@ IN_PROC_BROWSER_TEST_P(MachineLevelUserCloudPolicyEnrollmentTest, Test) { ...@@ -424,6 +434,7 @@ IN_PROC_BROWSER_TEST_P(MachineLevelUserCloudPolicyEnrollmentTest, Test) {
: std::string(), : std::string(),
BrowserDMTokenStorage::Get()->RetrieveDMToken()); BrowserDMTokenStorage::Get()->RetrieveDMToken());
// Verify the enrollment result.
MachineLevelUserCloudPolicyEnrollmentResult expected_result; MachineLevelUserCloudPolicyEnrollmentResult expected_result;
if (is_enrollment_token_valid() && storage_enabled()) { if (is_enrollment_token_valid() && storage_enabled()) {
expected_result = MachineLevelUserCloudPolicyEnrollmentResult::kSuccess; expected_result = MachineLevelUserCloudPolicyEnrollmentResult::kSuccess;
...@@ -434,6 +445,8 @@ IN_PROC_BROWSER_TEST_P(MachineLevelUserCloudPolicyEnrollmentTest, Test) { ...@@ -434,6 +445,8 @@ IN_PROC_BROWSER_TEST_P(MachineLevelUserCloudPolicyEnrollmentTest, Test) {
expected_result = expected_result =
MachineLevelUserCloudPolicyEnrollmentResult::kFailedToFetch; MachineLevelUserCloudPolicyEnrollmentResult::kFailedToFetch;
} }
// Verify the metrics.
histogram_tester_.ExpectBucketCount(kEnrollmentResultMetrics, expected_result, histogram_tester_.ExpectBucketCount(kEnrollmentResultMetrics, expected_result,
1); 1);
histogram_tester_.ExpectTotalCount(kEnrollmentResultMetrics, 1); histogram_tester_.ExpectTotalCount(kEnrollmentResultMetrics, 1);
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_POLICY_CLOUD_MACHINE_LEVEL_USER_CLOUD_POLICY_BROWSERTEST_MAC_UTIL_H_
#define CHROME_BROWSER_POLICY_CLOUD_MACHINE_LEVEL_USER_CLOUD_POLICY_BROWSERTEST_MAC_UTIL_H_
namespace policy {
// This is a helper function for MachineLevelUserCloudPolicyEnrollmentTest. It
// sends few system notifications which app_controller_mac.mm listens to make
// sure they're handle properly when the EnterpriseStartupDialog is being
// displayed.
void PostAppControllerNSNotifications();
} // namespace policy
#endif // CHROME_BROWSER_POLICY_CLOUD_MACHINE_LEVEL_USER_CLOUD_POLICY_BROWSERTEST_MAC_UTIL_H_
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/policy/cloud/machine_level_user_cloud_policy_browsertest_mac_util.h"
#import <Cocoa/Cocoa.h>
namespace policy {
void PostAppControllerNSNotifications() {
// Simulate the user clicking a window other than the dialog.
// The Profile is not ready when the dialog is displayed, so it can't be
// accessed.
[[NSNotificationCenter defaultCenter]
postNotificationName:NSWindowDidResignMainNotification
object:nil];
// Simulate the user hiding Chrome via Cmd+h when the dialog is displayed.
// The ExtensionAppShimHandler hasn't been created when the dialog is
// displayed, so it must be skipped.
[[NSNotificationCenter defaultCenter]
postNotificationName:NSApplicationWillHideNotification
object:nil];
}
} // namespace
...@@ -83,7 +83,7 @@ RegisterResult MachineLevelUserCloudPolicyRegisterWatcher:: ...@@ -83,7 +83,7 @@ RegisterResult MachineLevelUserCloudPolicyRegisterWatcher::
} }
bool MachineLevelUserCloudPolicyRegisterWatcher::IsDialogShowing() { bool MachineLevelUserCloudPolicyRegisterWatcher::IsDialogShowing() {
return dialog_ && dialog_->IsShowing(); return (dialog_ && dialog_->IsShowing()) || run_loop_.running();
} }
void MachineLevelUserCloudPolicyRegisterWatcher:: void MachineLevelUserCloudPolicyRegisterWatcher::
......
...@@ -1890,6 +1890,8 @@ test("browser_tests") { ...@@ -1890,6 +1890,8 @@ test("browser_tests") {
"//third_party/ocmock", "//third_party/ocmock",
] ]
sources += [ sources += [
"../browser/policy/cloud/machine_level_user_cloud_policy_browsertest_mac_util.h",
"../browser/policy/cloud/machine_level_user_cloud_policy_browsertest_mac_util.mm",
"../browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper_browsertest.mm", "../browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper_browsertest.mm",
"../browser/spellchecker/spell_check_host_chrome_impl_mac_browsertest.cc", "../browser/spellchecker/spell_check_host_chrome_impl_mac_browsertest.cc",
"../browser/ui/cocoa/applescript/bookmark_applescript_utils_test.h", "../browser/ui/cocoa/applescript/bookmark_applescript_utils_test.h",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment