Update inline_signin_ui to work in incognito mode
- Added a new reason for the signin that requests only the login process to
be executed and then takes the result from gaia and sends them through a new
message added to the inline_login.js. This code path avoids all cals that try
to perform operations on profiles
- This new mode is used by GCPW to gather the necessary login information
Bug: 887444
Change-Id: I84c62408b16c46a40360d7fc703b482d399cd76b
Reviewed-on: https://chromium-review.googlesource.com/c/1286755
Commit-Queue: Tien Mai <tienmai@chromium.org>
Reviewed-by: Achuith Bhandarkar <achuith@chromium.org>
Reviewed-by: Greg Thompson <grt@chromium.org>
Reviewed-by: Mihai Sardarescu <msarda@chromium.org>
Reviewed-by: Tommy Martino <tmartino@chromium.org>
Reviewed-by: Scott Violet <sky@chromium.org>
Reviewed-by: Roger Tawa <rogerta@chromium.org>
Reviewed-by: Jesse Doherty <jwd@chromium.org>
Reviewed-by: Peter Kasting <pkasting@chromium.org>
Reviewed-by: Michael Giuffrida <michaelpg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#607573}
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index d383a0b..d4800ed 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -1263,7 +1263,7 @@
</else>
</if>
</if>
- <!-- Chroium launch blocking dialog. -->
+ <!-- Chromium launch blocking dialog. -->
<if expr="not is_android and not chromeos">
<message name="IDS_ENTERPRISE_STARTUP_CLOUD_POLICY_ENROLLMENT_TOOLTIP" desc="The information message of Chromium launch blocking dialog for machine level user cloud policy enrollment.">
Launching Chromium...
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index bcc144d..aae54346 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -3,6 +3,7 @@
"+cc/paint",
"+chrome/app",
"+chrome/chrome_watcher",
+ "+chrome/credential_provider/common",
"+chrome/grit",
"+chrome/install_static",
"+chrome/installer/util",
diff --git a/chrome/browser/resources/inline_login/inline_login.js b/chrome/browser/resources/inline_login/inline_login.js
index 76af8b5..aa56cf0 100644
--- a/chrome/browser/resources/inline_login/inline_login.js
+++ b/chrome/browser/resources/inline_login/inline_login.js
@@ -93,6 +93,18 @@
}
/**
+ * Sends a message 'lstFetchResults'. This is a specific message sent when
+ * the inline signin is loaded with reason REASON_FETCH_LST_ONLY. Handlers of
+ * this message would expect a single argument a base::Dictionary value that
+ * contains the values fetched from the gaia sign in endpoint.
+ * @param {string} arg The string representation of the json data returned by
+ * the sign in dialog after it has finished the sign in process.
+ */
+ function sendLSTFetchResults(arg) {
+ chrome.send('lstFetchResults', [arg]);
+ }
+
+ /**
* Invoked when failed to get oauth2 refresh token.
*/
function handleOAuth2TokenFailure() {
@@ -138,6 +150,7 @@
return {
closeDialog: closeDialog,
+ sendLSTFetchResults: sendLSTFetchResults,
getAuthExtHost: getAuthExtHost,
handleOAuth2TokenFailure: handleOAuth2TokenFailure,
initialize: initialize,
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index a7e9cee..617ed0e 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2110,6 +2110,10 @@
sources += [
"network_profile_bubble.cc",
"network_profile_bubble.h",
+ "startup/credential_provider_signin_dialog_win.cc",
+ "startup/credential_provider_signin_dialog_win.h",
+ "startup/credential_provider_signin_info_fetcher_win.cc",
+ "startup/credential_provider_signin_info_fetcher_win.h",
"startup/default_browser_prompt_win.cc",
"views/certificate_viewer_win.cc",
"views/chrome_cleaner_dialog_win.cc",
@@ -2172,6 +2176,7 @@
"//ui/views/controls/webview",
]
deps += [
+ "//chrome/credential_provider/common:common_constants",
"//components/search_engines",
"//third_party/iaccessible2",
"//third_party/isimpledom",
diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc
index 39061bc..7abfd399 100644
--- a/chrome/browser/ui/browser_navigator.cc
+++ b/chrome/browser/ui/browser_navigator.cc
@@ -20,6 +20,7 @@
#include "chrome/browser/prerender/prerender_manager_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/chrome_navigation_ui_data.h"
+#include "chrome/browser/signin/signin_promo.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/browser/task_manager/web_contents_tags.h"
#include "chrome/browser/ui/browser.h"
@@ -84,7 +85,7 @@
// those types of Browser.
bool WindowCanOpenTabs(Browser* browser) {
return browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP) ||
- browser->tab_strip_model()->empty();
+ browser->tab_strip_model()->empty();
}
// Finds an existing Browser compatible with |profile|, making a new one if no
@@ -117,7 +118,7 @@
// If incognito is forced, we punt.
PrefService* prefs = profile->GetPrefs();
if (prefs && IncognitoModePrefs::GetAvailability(prefs) ==
- IncognitoModePrefs::FORCED) {
+ IncognitoModePrefs::FORCED) {
return false;
}
@@ -408,11 +409,8 @@
create_params.initially_hidden = true;
#if defined(USE_AURA)
- if (params.browser->window() &&
- params.browser->window()->GetNativeWindow()) {
- create_params.context =
- params.browser->window()->GetNativeWindow();
- }
+ if (params.browser->window() && params.browser->window()->GetNativeWindow())
+ create_params.context = params.browser->window()->GetNativeWindow();
#endif
std::unique_ptr<WebContents> target_contents =
@@ -443,7 +441,7 @@
prerender::PrerenderManager* prerender_manager =
prerender::PrerenderManagerFactory::GetForBrowserContext(profile);
return prerender_manager &&
- prerender_manager->MaybeUsePrerenderedPage(url, params);
+ prerender_manager->MaybeUsePrerenderedPage(url, params);
}
} // namespace
@@ -459,8 +457,9 @@
#if BUILDFLAG(ENABLE_EXTENSIONS)
const extensions::Extension* extension =
- extensions::ExtensionRegistry::Get(params->initiating_profile)->
- enabled_extensions().GetExtensionOrAppByURL(params->url);
+ extensions::ExtensionRegistry::Get(params->initiating_profile)
+ ->enabled_extensions()
+ .GetExtensionOrAppByURL(params->url);
// Platform apps cannot navigate. Block the request.
if (extension && extension->is_platform_app())
params->url = GURL(chrome::kExtensionInvalidRequestURL);
@@ -697,6 +696,49 @@
params->navigated_or_inserted_contents = contents_to_navigate_or_insert;
}
+bool IsHostAllowedInIncognito(const GURL& url) {
+ std::string scheme = url.scheme();
+ base::StringPiece host = url.host_piece();
+ if (scheme == chrome::kChromeSearchScheme) {
+ return host != chrome::kChromeUIThumbnailHost &&
+ host != chrome::kChromeUIThumbnailHost2 &&
+ host != chrome::kChromeUIThumbnailListHost &&
+ host != chrome::kChromeUISuggestionsHost;
+ }
+
+ if (scheme != content::kChromeUIScheme)
+ return true;
+
+ if (host == chrome::kChromeUIChromeSigninHost) {
+#if defined(OS_WIN)
+ // Allow incognito mode for the chrome-signin url if we only want to
+ // retrieve the login scope token without touching any profiles. This
+ // option is only available on Windows for use with Google Credential
+ // Provider for Windows.
+ return signin::GetSigninReasonForPromoURL(url) ==
+ signin_metrics::Reason::REASON_FETCH_LST_ONLY;
+#else
+ return false;
+#endif // defined(OS_WIN)
+ }
+
+ // Most URLs are allowed in incognito; the following are exceptions.
+ // chrome://extensions is on the list because it redirects to
+ // chrome://settings.
+ return host != chrome::kChromeUIAppLauncherPageHost &&
+ host != chrome::kChromeUISettingsHost &&
+ host != chrome::kChromeUIHelpHost &&
+ host != chrome::kChromeUIHistoryHost &&
+ host != chrome::kChromeUIExtensionsHost &&
+ host != chrome::kChromeUIBookmarksHost &&
+ host != chrome::kChromeUIUberHost &&
+ host != chrome::kChromeUIThumbnailHost &&
+ host != chrome::kChromeUIThumbnailHost2 &&
+ host != chrome::kChromeUIThumbnailListHost &&
+ host != chrome::kChromeUISuggestionsHost &&
+ host != chrome::kChromeUIDevicesHost;
+}
+
bool IsURLAllowedInIncognito(const GURL& url,
content::BrowserContext* browser_context) {
if (url.scheme() == content::kViewSourceScheme) {
@@ -708,35 +750,11 @@
stripped_spec.erase(0, strlen(content::kViewSourceScheme) + 1);
GURL stripped_url(stripped_spec);
return stripped_url.is_valid() &&
- IsURLAllowedInIncognito(stripped_url, browser_context);
- }
- // Most URLs are allowed in incognito; the following are exceptions.
- // chrome://extensions is on the list because it redirects to
- // chrome://settings.
- if (url.scheme() == content::kChromeUIScheme &&
- (url.host_piece() == chrome::kChromeUIAppLauncherPageHost ||
- url.host_piece() == chrome::kChromeUISettingsHost ||
- url.host_piece() == chrome::kChromeUIHelpHost ||
- url.host_piece() == chrome::kChromeUIHistoryHost ||
- url.host_piece() == chrome::kChromeUIExtensionsHost ||
- url.host_piece() == chrome::kChromeUIBookmarksHost ||
- url.host_piece() == chrome::kChromeUIChromeSigninHost ||
- url.host_piece() == chrome::kChromeUIUberHost ||
- url.host_piece() == chrome::kChromeUIThumbnailHost ||
- url.host_piece() == chrome::kChromeUIThumbnailHost2 ||
- url.host_piece() == chrome::kChromeUIThumbnailListHost ||
- url.host_piece() == chrome::kChromeUISuggestionsHost ||
- url.host_piece() == chrome::kChromeUIDevicesHost)) {
- return false;
+ IsURLAllowedInIncognito(stripped_url, browser_context);
}
- if (url.scheme() == chrome::kChromeSearchScheme &&
- (url.host_piece() == chrome::kChromeUIThumbnailHost ||
- url.host_piece() == chrome::kChromeUIThumbnailHost2 ||
- url.host_piece() == chrome::kChromeUIThumbnailListHost ||
- url.host_piece() == chrome::kChromeUISuggestionsHost)) {
+ if (!IsHostAllowedInIncognito(url))
return false;
- }
GURL rewritten_url = url;
bool reverse_on_redirect = false;
diff --git a/chrome/browser/ui/startup/credential_provider_signin_dialog_win.cc b/chrome/browser/ui/startup/credential_provider_signin_dialog_win.cc
new file mode 100644
index 0000000..a94b0b0
--- /dev/null
+++ b/chrome/browser/ui/startup/credential_provider_signin_dialog_win.cc
@@ -0,0 +1,300 @@
+// 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/ui/startup/credential_provider_signin_dialog_win.h"
+#include "chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.h"
+
+#include "base/command_line.h"
+#include "base/json/json_writer.h"
+#include "base/strings/string16.h"
+#include "chrome/browser/signin/signin_promo.h"
+#include "chrome/browser/ui/browser_dialogs.h"
+#include "chrome/browser/ui/webui/chrome_web_contents_handler.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
+#include "components/keep_alive_registry/keep_alive_types.h"
+#include "components/keep_alive_registry/scoped_keep_alive.h"
+#include "components/signin/core/browser/signin_metrics.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/browser/web_ui_message_handler.h"
+#include "ui/views/controls/webview/web_dialog_view.h"
+#include "ui/views/widget/widget.h"
+#include "ui/web_dialogs/web_dialog_delegate.h"
+
+namespace {
+
+// This message must match the one sent in inline_login.js: sendLSTFetchResults.
+constexpr char kLSTFetchResultsMessage[] = "lstFetchResults";
+
+void HandleAllGcpwInfoFetched(
+ std::unique_ptr<ScopedKeepAlive> keep_alive,
+ std::unique_ptr<CredentialProviderSigninInfoFetcher> fetcher,
+ base::Value signin_result,
+ base::Value fetch_result) {
+ DCHECK(signin_result.is_dict());
+ DCHECK(fetch_result.is_dict());
+ if (!signin_result.DictEmpty() && !fetch_result.DictEmpty()) {
+ std::string json_result;
+ signin_result.MergeDictionary(&fetch_result);
+ if (base::JSONWriter::Write(signin_result, &json_result) &&
+ !json_result.empty()) {
+ // TODO(crbug.com/887444) output to the correct pipe the JSON result of
+ // the user sign in.
+ }
+ }
+
+ // Release the fetcher and mark it for eventual delete. It is not immediately
+ // deleted here in case it still wants to do further processing after
+ // returning from this callback
+ base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, fetcher.release());
+
+ // Release the keep_alive implicitly and allow the dialog to die.
+}
+
+void HandleSigninCompleteForGcpwLogin(
+ std::unique_ptr<ScopedKeepAlive> keep_alive,
+ base::Value signin_result,
+ const std::string& access_token,
+ const std::string& refresh_token,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
+ DCHECK(signin_result.is_dict());
+ DCHECK_EQ(signin_result.DictEmpty(),
+ access_token.empty() && refresh_token.empty());
+ if (!signin_result.DictEmpty()) {
+ // Create the fetcher and pass it to the callback so that it can be
+ // deleted once it is finished.
+ auto fetcher = std::make_unique<CredentialProviderSigninInfoFetcher>(
+ refresh_token, url_loader_factory);
+ fetcher->SetCompletionCallbackAndStart(
+ access_token,
+ base::BindOnce(&HandleAllGcpwInfoFetched, std::move(keep_alive),
+ std::move(fetcher), std::move(signin_result)));
+ }
+
+ // If the function has not pass ownership of the keep alive yet at this point
+ // this means there was some error reading the sign in result or the result
+ // was empty. In this case, return from the method which will implicitly
+ // release the keep_alive which will close and release everything.
+}
+
+class CredentialProviderWebUIMessageHandler
+ : public content::WebUIMessageHandler {
+ public:
+ explicit CredentialProviderWebUIMessageHandler(
+ HandleGcpwSigninCompleteResult signin_callback)
+ : signin_callback_(std::move(signin_callback)) {}
+
+ // content::WebUIMessageHandler:
+ void RegisterMessages() override {
+ web_ui()->RegisterMessageCallback(
+ kLSTFetchResultsMessage,
+ base::BindRepeating(
+ &CredentialProviderWebUIMessageHandler::OnSigninComplete,
+ base::Unretained(this)));
+ }
+
+ private:
+ base::Value ParseArgs(const base::ListValue* args,
+ std::string* out_access_token,
+ std::string* out_refresh_token) {
+ const base::Value* dict_result = nullptr;
+ if (!args || args->empty() || !args->Get(0, &dict_result) ||
+ !dict_result->is_dict()) {
+ return base::Value(base::Value::Type::DICTIONARY);
+ }
+
+ const base::Value* email = dict_result->FindKeyOfType(
+ credential_provider::kKeyEmail, base::Value::Type::STRING);
+ const base::Value* password = dict_result->FindKeyOfType(
+ credential_provider::kKeyPassword, base::Value::Type::STRING);
+ const base::Value* id = dict_result->FindKeyOfType(
+ credential_provider::kKeyId, base::Value::Type::STRING);
+ const base::Value* access_token = dict_result->FindKeyOfType(
+ credential_provider::kKeyAccessToken, base::Value::Type::STRING);
+ const base::Value* refresh_token = dict_result->FindKeyOfType(
+ credential_provider::kKeyRefreshToken, base::Value::Type::STRING);
+
+ if (!email || email->GetString().empty() || !password ||
+ password->GetString().empty() || !id || id->GetString().empty() ||
+ !access_token || access_token->GetString().empty() || !refresh_token ||
+ refresh_token->GetString().empty()) {
+ return base::Value(base::Value::Type::DICTIONARY);
+ }
+
+ *out_access_token = access_token->GetString();
+ *out_refresh_token = refresh_token->GetString();
+ return dict_result->Clone();
+ }
+
+ void OnSigninComplete(const base::ListValue* args) {
+ std::string access_token;
+ std::string refresh_token;
+ base::Value signin_result = ParseArgs(args, &access_token, &refresh_token);
+
+ content::WebContents* contents = web_ui()->GetWebContents();
+ content::StoragePartition* partition =
+ content::BrowserContext::GetStoragePartitionForSite(
+ contents->GetBrowserContext(), signin::GetSigninPartitionURL());
+
+ // Regardless of the results of ParseArgs, |signin_callback_| will always
+ // be called to allow it to release any additional references it may hold
+ // (like the keep_alive in HandleSigninCompleteForGCPWLogin) or perform
+ // possible error handling.
+ std::move(signin_callback_)
+ .Run(std::move(signin_result), access_token, refresh_token,
+ partition->GetURLLoaderFactoryForBrowserProcess());
+ }
+
+ HandleGcpwSigninCompleteResult signin_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(CredentialProviderWebUIMessageHandler);
+};
+
+} // namespace
+
+// Delegate to control a views::WebDialogView for purposes of showing a gaia
+// sign in page for purposes of the credential provider.
+class CredentialProviderWebDialogDelegate : public ui::WebDialogDelegate {
+ public:
+ // |reauth_email| is used to pre fill in the sign in dialog with the user's
+ // e-mail during a reauthorize sign in. This type of sign in is used to update
+ // the user's password.
+ CredentialProviderWebDialogDelegate(
+ const std::string& reauth_email,
+ HandleGcpwSigninCompleteResult signin_callback)
+ : reauth_email_(reauth_email),
+ signin_callback_(std::move(signin_callback)) {}
+
+ GURL GetDialogContentURL() const override {
+ signin_metrics::AccessPoint access_point =
+ signin_metrics::AccessPoint::ACCESS_POINT_MACHINE_LOGON;
+ signin_metrics::Reason reason =
+ signin_metrics::Reason::REASON_FETCH_LST_ONLY;
+ return reauth_email_.empty()
+ ? signin::GetPromoURLForDialog(access_point, reason, false)
+ : signin::GetReauthURLWithEmailForDialog(access_point, reason,
+ reauth_email_);
+ }
+
+ ui::ModalType GetDialogModalType() const override {
+ return ui::MODAL_TYPE_SYSTEM;
+ }
+
+ base::string16 GetDialogTitle() const override { return base::string16(); }
+
+ base::string16 GetAccessibleDialogTitle() const override {
+ return base::string16();
+ }
+
+ std::string GetDialogName() const override {
+ // Return an empty window name; otherwise chrome will try to persist the
+ // window's position and DCHECK.
+ return std::string();
+ }
+
+ void GetWebUIMessageHandlers(
+ std::vector<content::WebUIMessageHandler*>* handlers) const override {
+ // The WebDialogUI will own and delete this message handler.
+ handlers->push_back(
+ new CredentialProviderWebUIMessageHandler(std::move(signin_callback_)));
+ }
+
+ void GetDialogSize(gfx::Size* size) const override {
+ // TODO(crbug.com/901947): Figure out exactly what size the dialog should
+ // be.
+ size->SetSize(448, 610);
+ }
+
+ void GetMinimumDialogSize(gfx::Size* size) const override {
+ GetDialogSize(size);
+ }
+
+ std::string GetDialogArgs() const override { return std::string(); }
+
+ void OnDialogClosed(const std::string& json_retval) override {
+ // Class owns itself and thus needs to be deleted eventually after the
+ // closed call back has been signalled since it will no longer be accessed
+ // by the WebDialogView.
+ base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
+ }
+
+ void OnCloseContents(content::WebContents* source,
+ bool* out_close_dialog) override {}
+
+ bool HandleContextMenu(const content::ContextMenuParams& params) override {
+ return true;
+ }
+
+ bool ShouldShowDialogTitle() const override { return false; }
+
+ protected:
+ // E-mail used to pre-fill the e-mail field when a reauth signin is required.
+ std::string reauth_email_;
+
+ // Callback that will be called when a valid sign in has been completed
+ // through the dialog.
+ mutable HandleGcpwSigninCompleteResult signin_callback_;
+};
+
+bool ValidateSigninCompleteResult(const std::string& access_token,
+ const std::string& refresh_token,
+ const base::Value& signin_result) {
+ return !access_token.empty() && !refresh_token.empty() &&
+ signin_result.is_dict();
+}
+
+void StartGCPWSignin(const base::CommandLine& command_line,
+ content::BrowserContext* context) {
+ // This keep_alive is created since there is no browser created when
+ // --gcpw-logon is specified. Since there is no browser there is no holder of
+ // a ScopedKeepAlive present that will ensure Chrome kills itself when the
+ // last keep alive is released. So instead, keep the keep alive across the
+ // callbacks that will be sent during the signin process. Once the full fetch
+ // of the information necesssary for the GCPW is finished (or there is a
+ // failure) release the keep alive so that Chrome can shutdown.
+
+ ShowCredentialProviderSigninDialog(
+ command_line, context,
+ base::BindOnce(&HandleSigninCompleteForGcpwLogin,
+ std::make_unique<ScopedKeepAlive>(
+ KeepAliveOrigin::CREDENTIAL_PROVIDER_SIGNIN_DIALOG,
+ KeepAliveRestartOption::DISABLED)));
+}
+
+views::WebDialogView* ShowCredentialProviderSigninDialog(
+ const base::CommandLine& command_line,
+ content::BrowserContext* context,
+ HandleGcpwSigninCompleteResult signin_complete_handler) {
+ DCHECK(signin_complete_handler);
+
+ // Open a frameless window whose entire surface displays a gaia sign in web
+ // page.
+ std::string reauth_email =
+ command_line.GetSwitchValueASCII(credential_provider::kGcpwSigninSwitch);
+
+ // Delegate to handle the result of the sign in request. This will
+ // delete itself eventually when it receives the OnDialogClosed call.
+ auto delegate = std::make_unique<CredentialProviderWebDialogDelegate>(
+ reauth_email, std::move(signin_complete_handler));
+
+ // The web dialog view that will contain the web ui for the login screen.
+ // This view will be automatically deleted by the widget that owns it when it
+ // is closed.
+ auto view = std::make_unique<views::WebDialogView>(
+ context, delegate.release(), new ChromeWebContentsHandler);
+ views::Widget::InitParams init_params(
+ views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+ views::WebDialogView* web_view = view.release();
+ init_params.name = "GCPW"; // Used for debugging only.
+ init_params.delegate = web_view;
+
+ // This widget will automatically delete itself and its WebDialogView when the
+ // dialog window is closed.
+ views::Widget* widget = new views::Widget;
+ widget->Init(init_params);
+ widget->Show();
+
+ return web_view;
+}
diff --git a/chrome/browser/ui/startup/credential_provider_signin_dialog_win.h b/chrome/browser/ui/startup/credential_provider_signin_dialog_win.h
new file mode 100644
index 0000000..7dd099c
--- /dev/null
+++ b/chrome/browser/ui/startup/credential_provider_signin_dialog_win.h
@@ -0,0 +1,60 @@
+// 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_UI_STARTUP_CREDENTIAL_PROVIDER_SIGNIN_DIALOG_WIN_H_
+#define CHROME_BROWSER_UI_STARTUP_CREDENTIAL_PROVIDER_SIGNIN_DIALOG_WIN_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/memory/scoped_refptr.h"
+
+namespace base {
+class CommandLine;
+class Value;
+} // namespace base
+
+namespace content {
+class BrowserContext;
+} // namespace content
+
+namespace network {
+class SharedURLLoaderFactory;
+} // namespace network
+
+namespace views {
+class WebDialogView;
+} // namespace views
+
+// Callback signalled by the dialog when the Gaia sign in flow compltes.
+// Parameters are:
+// 1. A base::Value that is of type DICTIONARY. An empty dictionary signals an
+// error during the signin process
+// 2. The signed in user's access token.
+// 3. The signed in user's refresh token.
+// 4. A URL loader that will be used by various OAuth fetchers.
+using HandleGcpwSigninCompleteResult =
+ base::OnceCallback<void(base::Value,
+ const std::string&,
+ const std::string&,
+ scoped_refptr<network::SharedURLLoaderFactory>)>;
+
+// Starts the Google Credential Provider for Windows (GCPW) Sign in flow. First
+// the function shows a frameless Google account sign in page allowing the user
+// to choose an account to logon to Windows. Once the signin is complete, the
+// flow will automatically start requesting additional information required by
+// GCPW to complete Windows logon.
+void StartGCPWSignin(const base::CommandLine& command_line,
+ content::BrowserContext* context);
+
+// This function displays a dialog window with a Gaia signin page. Once
+// the Gaia signin flow is finished, the callback given by
+// |signin_complete_handler| will be called with the results of the signin.
+// The return value is only valid during the lifetime of the dialog.
+views::WebDialogView* ShowCredentialProviderSigninDialog(
+ const base::CommandLine& command_line,
+ content::BrowserContext* context,
+ HandleGcpwSigninCompleteResult signin_complete_handler);
+
+#endif // CHROME_BROWSER_UI_STARTUP_CREDENTIAL_PROVIDER_SIGNIN_DIALOG_WIN_H_
diff --git a/chrome/browser/ui/startup/credential_provider_signin_dialog_win_browsertest.cc b/chrome/browser/ui/startup/credential_provider_signin_dialog_win_browsertest.cc
new file mode 100644
index 0000000..e44876f
--- /dev/null
+++ b/chrome/browser/ui/startup/credential_provider_signin_dialog_win_browsertest.cc
@@ -0,0 +1,344 @@
+// 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 "base/bind.h"
+#include "base/command_line.h"
+#include "base/json/json_reader.h"
+#include "base/test/test_switches.cc"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/startup/credential_provider_signin_dialog_win.h"
+#include "chrome/browser/ui/startup/credential_provider_signin_dialog_win_test_data.h"
+#include "chrome/browser/ui/test/test_browser_dialog.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
+#include "chrome/test/base/interactive_test_utils.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/test_utils.h"
+#include "ui/views/controls/webview/web_dialog_view.h"
+#include "ui/views/test/widget_test.h"
+
+#define TEST_TASK_FUNC_NAME_FOR_THREAD_RUNNER(Func) Run##Func##Test
+
+class CredentialProviderSigninDialogWinIntegrationTest;
+
+class SigninDialogLoadingStoppedObserver : public content::WebContentsObserver {
+ public:
+ SigninDialogLoadingStoppedObserver(content::WebContents* web_contents,
+ base::OnceClosure idle_closure)
+ : content::WebContentsObserver(web_contents),
+ idle_closure_(std::move(idle_closure)) {}
+
+ void DidStopLoading() override {
+ if (idle_closure_)
+ std::move(idle_closure_).Run();
+ }
+
+ base::OnceClosure idle_closure_;
+};
+
+class CredentialProviderSigninDialogWinBaseTest : public InProcessBrowserTest {
+ protected:
+ CredentialProviderSigninDialogWinBaseTest();
+
+ content::WebContents* web_contents() { return web_contents_; }
+ virtual void WaitForDialogToLoad();
+
+ content::WebContents* web_contents_ = nullptr;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CredentialProviderSigninDialogWinBaseTest);
+};
+
+CredentialProviderSigninDialogWinBaseTest::
+ CredentialProviderSigninDialogWinBaseTest()
+ : InProcessBrowserTest() {}
+
+void CredentialProviderSigninDialogWinBaseTest::WaitForDialogToLoad() {
+ EXPECT_TRUE(web_contents());
+
+ base::RunLoop run_loop;
+ SigninDialogLoadingStoppedObserver observer(web_contents(),
+ run_loop.QuitWhenIdleClosure());
+ run_loop.Run();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CredentialProviderSigninDialogWinDialogTest tests the dialog portion of the
+// credential provider sign in without checking whether the fetch of additional
+// information was successful.
+
+class CredentialProviderSigninDialogWinDialogTest
+ : public CredentialProviderSigninDialogWinBaseTest {
+ protected:
+ CredentialProviderSigninDialogWinDialogTest();
+
+ void SendSigninCompleteMessage(const base::Value& value);
+ void SendValidSigninCompleteMessage();
+ void WaitForSigninCompleteMessage();
+
+ void ShowSigninDialog();
+
+ // A HandleGCPWSiginCompleteResult callback to check that the signin dialog
+ // has correctly received and procesed the sign in complete message.
+ void HandleSignInComplete(
+ base::Value signin_result,
+ const std::string& access_token,
+ const std::string& refresh_token,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader);
+ bool signin_complete_called_ = false;
+
+ std::string result_access_token_;
+ std::string result_refresh_token_;
+ base::Value result_value_;
+ CredentialProviderSigninDialogTestDataStorage test_data_storage_;
+
+ private:
+ base::OnceClosure signin_complete_closure_;
+
+ DISALLOW_COPY_AND_ASSIGN(CredentialProviderSigninDialogWinDialogTest);
+};
+
+CredentialProviderSigninDialogWinDialogTest::
+ CredentialProviderSigninDialogWinDialogTest()
+ : CredentialProviderSigninDialogWinBaseTest() {}
+
+void CredentialProviderSigninDialogWinDialogTest::SendSigninCompleteMessage(
+ const base::Value& value) {
+ std::string json_string;
+ EXPECT_TRUE(base::JSONWriter::Write(value, &json_string));
+
+ std::string login_complete_message =
+ "chrome.send('lstFetchResults', [" + json_string + "]);";
+ content::RenderFrameHost* root = web_contents()->GetMainFrame();
+ content::ExecuteScriptAsync(root, login_complete_message);
+ WaitForSigninCompleteMessage();
+}
+
+void CredentialProviderSigninDialogWinDialogTest::
+ SendValidSigninCompleteMessage() {
+ SendSigninCompleteMessage(test_data_storage_.MakeValidSignInResponseValue());
+}
+
+void CredentialProviderSigninDialogWinDialogTest::
+ WaitForSigninCompleteMessage() {
+ // Run until the dialog has received the signin complete message.
+ base::RunLoop run_loop;
+ signin_complete_closure_ = run_loop.QuitWhenIdleClosure();
+ run_loop.Run();
+}
+
+void CredentialProviderSigninDialogWinDialogTest::ShowSigninDialog() {
+ views::WebDialogView* web_view = ShowCredentialProviderSigninDialog(
+ base::CommandLine(base::CommandLine::NoProgram::NO_PROGRAM),
+ browser()->profile(),
+ base::BindOnce(
+ &CredentialProviderSigninDialogWinDialogTest::HandleSignInComplete,
+ base::Unretained(this)));
+
+ web_contents_ = web_view->web_contents();
+}
+
+void CredentialProviderSigninDialogWinDialogTest::HandleSignInComplete(
+ base::Value signin_result,
+ const std::string& access_token,
+ const std::string& refresh_token,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader) {
+ result_access_token_ = access_token;
+ result_refresh_token_ = refresh_token;
+ EXPECT_FALSE(signin_complete_called_);
+ signin_complete_called_ = true;
+ result_value_ = std::move(signin_result);
+
+ if (signin_complete_closure_)
+ std::move(signin_complete_closure_).Run();
+}
+
+IN_PROC_BROWSER_TEST_F(CredentialProviderSigninDialogWinDialogTest,
+ SendEmptySigninComplete) {
+ ShowSigninDialog();
+ WaitForDialogToLoad();
+ SendSigninCompleteMessage(test_data_storage_.MakeSignInResponseValue());
+ EXPECT_TRUE(signin_complete_called_);
+ EXPECT_TRUE(result_value_.is_dict());
+ EXPECT_TRUE(result_value_.DictEmpty());
+ EXPECT_TRUE(result_access_token_.empty());
+ EXPECT_TRUE(result_refresh_token_.empty());
+}
+
+IN_PROC_BROWSER_TEST_F(CredentialProviderSigninDialogWinDialogTest,
+ SendInvalidSigninCompleteNoId) {
+ ShowSigninDialog();
+ WaitForDialogToLoad();
+ SendSigninCompleteMessage(test_data_storage_.MakeSignInResponseValue(
+ std::string(), test_data_storage_.GetSuccessPassword(),
+ test_data_storage_.GetSuccessEmail(),
+ test_data_storage_.GetSuccessAccessToken(),
+ test_data_storage_.GetSuccessRefreshToken()));
+ EXPECT_TRUE(signin_complete_called_);
+ EXPECT_TRUE(result_value_.is_dict());
+ EXPECT_TRUE(result_value_.DictEmpty());
+ EXPECT_TRUE(result_access_token_.empty());
+ EXPECT_TRUE(result_refresh_token_.empty());
+}
+
+IN_PROC_BROWSER_TEST_F(CredentialProviderSigninDialogWinDialogTest,
+ SendInvalidSigninCompleteNoPassword) {
+ ShowSigninDialog();
+ WaitForDialogToLoad();
+ SendSigninCompleteMessage(test_data_storage_.MakeSignInResponseValue(
+ test_data_storage_.GetSuccessId(), std::string(),
+ test_data_storage_.GetSuccessEmail(),
+ test_data_storage_.GetSuccessAccessToken(),
+ test_data_storage_.GetSuccessRefreshToken()));
+ EXPECT_TRUE(signin_complete_called_);
+ EXPECT_TRUE(result_value_.is_dict());
+ EXPECT_TRUE(result_value_.DictEmpty());
+ EXPECT_TRUE(result_access_token_.empty());
+ EXPECT_TRUE(result_refresh_token_.empty());
+}
+
+IN_PROC_BROWSER_TEST_F(CredentialProviderSigninDialogWinDialogTest,
+ SendInvalidSigninCompleteNoEmail) {
+ ShowSigninDialog();
+ WaitForDialogToLoad();
+ SendSigninCompleteMessage(test_data_storage_.MakeSignInResponseValue(
+ test_data_storage_.GetSuccessId(),
+ test_data_storage_.GetSuccessPassword(), std::string(),
+ test_data_storage_.GetSuccessAccessToken(),
+ test_data_storage_.GetSuccessRefreshToken()));
+ EXPECT_TRUE(signin_complete_called_);
+ EXPECT_TRUE(result_value_.is_dict());
+ EXPECT_TRUE(result_value_.DictEmpty());
+ EXPECT_TRUE(result_access_token_.empty());
+ EXPECT_TRUE(result_refresh_token_.empty());
+}
+
+IN_PROC_BROWSER_TEST_F(CredentialProviderSigninDialogWinDialogTest,
+ SendInvalidSigninCompleteNoAccessToken) {
+ ShowSigninDialog();
+ WaitForDialogToLoad();
+ SendSigninCompleteMessage(test_data_storage_.MakeSignInResponseValue(
+ test_data_storage_.GetSuccessId(),
+ test_data_storage_.GetSuccessPassword(),
+ test_data_storage_.GetSuccessEmail(), std::string(),
+ test_data_storage_.GetSuccessRefreshToken()));
+ EXPECT_TRUE(signin_complete_called_);
+ EXPECT_TRUE(result_value_.is_dict());
+ EXPECT_TRUE(result_value_.DictEmpty());
+ EXPECT_TRUE(result_access_token_.empty());
+ EXPECT_TRUE(result_refresh_token_.empty());
+}
+
+IN_PROC_BROWSER_TEST_F(CredentialProviderSigninDialogWinDialogTest,
+ SendInvalidSigninCompleteNoRefreshToken) {
+ ShowSigninDialog();
+ WaitForDialogToLoad();
+ SendSigninCompleteMessage(test_data_storage_.MakeSignInResponseValue(
+ test_data_storage_.GetSuccessId(),
+ test_data_storage_.GetSuccessPassword(),
+ test_data_storage_.GetSuccessEmail(),
+ test_data_storage_.GetSuccessAccessToken(), std::string()));
+ EXPECT_TRUE(signin_complete_called_);
+ EXPECT_TRUE(result_value_.is_dict());
+ EXPECT_TRUE(result_value_.DictEmpty());
+ EXPECT_TRUE(result_access_token_.empty());
+ EXPECT_TRUE(result_refresh_token_.empty());
+}
+
+IN_PROC_BROWSER_TEST_F(CredentialProviderSigninDialogWinDialogTest,
+ SuccessfulLoginMessage) {
+ ShowSigninDialog();
+ WaitForDialogToLoad();
+ SendValidSigninCompleteMessage();
+ EXPECT_TRUE(signin_complete_called_);
+ EXPECT_TRUE(result_value_.is_dict());
+ EXPECT_FALSE(result_value_.DictEmpty());
+ const base::DictionaryValue* result_dict;
+ EXPECT_TRUE(result_value_.GetAsDictionary(&result_dict));
+ std::string id_in_dict;
+ EXPECT_TRUE(result_dict->GetString("id", &id_in_dict));
+ std::string email_in_dict;
+ EXPECT_TRUE(result_dict->GetString("email", &email_in_dict));
+ std::string password_in_dict;
+ EXPECT_TRUE(result_dict->GetString("password", &password_in_dict));
+
+ EXPECT_EQ(id_in_dict, test_data_storage_.GetSuccessId());
+ EXPECT_EQ(email_in_dict, test_data_storage_.GetSuccessEmail());
+ EXPECT_EQ(password_in_dict, test_data_storage_.GetSuccessPassword());
+ EXPECT_EQ(result_access_token_, test_data_storage_.GetSuccessAccessToken());
+ EXPECT_EQ(result_refresh_token_, test_data_storage_.GetSuccessRefreshToken());
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CredentialProviderSigninDialogWinIntegrationTest is used for testing the
+// integration of the dialog into Chrome, This test mainly verifies correct
+// start up state if we provide the --gcpw-signin switch.
+
+class CredentialProviderSigninDialogWinIntegrationTest
+ : public CredentialProviderSigninDialogWinBaseTest {
+ protected:
+ CredentialProviderSigninDialogWinIntegrationTest();
+
+ // InProcessBrowserTest:
+ void SetUpCommandLine(base::CommandLine* command_line) override;
+
+ // CredentialProviderSigninDialogWinBaseTest:
+ void WaitForDialogToLoad() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CredentialProviderSigninDialogWinIntegrationTest);
+};
+
+CredentialProviderSigninDialogWinIntegrationTest::
+ CredentialProviderSigninDialogWinIntegrationTest()
+ : CredentialProviderSigninDialogWinBaseTest() {}
+
+void CredentialProviderSigninDialogWinIntegrationTest::SetUpCommandLine(
+ base::CommandLine* command_line) {
+ command_line->AppendSwitch(::credential_provider::kGcpwSigninSwitch);
+}
+
+void CredentialProviderSigninDialogWinIntegrationTest::WaitForDialogToLoad() {
+ // The browser has already been created by the time this start starts and
+ // web_contents_ is not yet available. In this run case there should only
+ // be one widget available and that widget should contain the web contents
+ // needed for the test.
+ EXPECT_FALSE(web_contents_);
+ views::Widget::Widgets all_widgets = views::test::WidgetTest::GetAllWidgets();
+ EXPECT_EQ(all_widgets.size(), 1ull);
+ views::WebDialogView* web_dialog = static_cast<views::WebDialogView*>(
+ (*all_widgets.begin())->GetContentsView());
+ web_contents_ = web_dialog->web_contents();
+ EXPECT_TRUE(web_contents_);
+
+ CredentialProviderSigninDialogWinBaseTest::WaitForDialogToLoad();
+
+ // When running with --gcpw-signin, browser creation is completely bypassed
+ // only a dialog for the signin should be created directly. In a normal
+ // browser test, there is always a browser created so make sure that is not
+ // the case for our tests.
+ EXPECT_FALSE(browser());
+}
+
+IN_PROC_BROWSER_TEST_F(CredentialProviderSigninDialogWinIntegrationTest,
+ ShowDialogOnlyTest) {
+ WaitForDialogToLoad();
+ EXPECT_EQ(Profile::ProfileType::INCOGNITO_PROFILE,
+ ((Profile*)(web_contents_->GetBrowserContext()))->GetProfileType());
+ views::Widget::Widgets all_widgets = views::test::WidgetTest::GetAllWidgets();
+ (*all_widgets.begin())->Close();
+ RunUntilBrowserProcessQuits();
+}
+
+IN_PROC_BROWSER_TEST_F(CredentialProviderSigninDialogWinIntegrationTest,
+ EscapeClosesDialogTest) {
+ WaitForDialogToLoad();
+ views::Widget::Widgets all_widgets = views::test::WidgetTest::GetAllWidgets();
+ ui::KeyEvent escape_key_event(ui::EventType::ET_KEY_PRESSED,
+ ui::KeyboardCode::VKEY_ESCAPE,
+ ui::DomCode::ESCAPE, 0);
+ (*all_widgets.begin())->OnKeyEvent(&escape_key_event);
+ RunUntilBrowserProcessQuits();
+}
diff --git a/chrome/browser/ui/startup/credential_provider_signin_dialog_win_test_data.cc b/chrome/browser/ui/startup/credential_provider_signin_dialog_win_test_data.cc
new file mode 100644
index 0000000..22215b6
--- /dev/null
+++ b/chrome/browser/ui/startup/credential_provider_signin_dialog_win_test_data.cc
@@ -0,0 +1,60 @@
+// 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/ui/startup/credential_provider_signin_dialog_win_test_data.h"
+
+#include <string>
+
+CredentialProviderSigninDialogTestDataStorage::
+ CredentialProviderSigninDialogTestDataStorage()
+ : expected_success_signin_result_(base::Value::Type::DICTIONARY),
+ expected_success_fetch_result_(base::Value::Type::DICTIONARY) {
+ expected_success_signin_result_.SetKey("id", base::Value("gaia_user_id"));
+ expected_success_signin_result_.SetKey("password", base::Value("password"));
+ expected_success_signin_result_.SetKey("email", base::Value("foo@xyz.com"));
+ expected_success_signin_result_.SetKey("access_token",
+ base::Value("access_token"));
+ expected_success_signin_result_.SetKey("refresh_token",
+ base::Value("refresh_token"));
+ expected_success_fetch_result_.SetKey("token_handle",
+ base::Value("token_handle"));
+ expected_success_fetch_result_.SetKey("mdm_id_token",
+ base::Value("mdm_token"));
+ expected_success_fetch_result_.SetKey("full_name", base::Value("Foo Bar"));
+
+ expected_success_full_result_ = expected_success_signin_result_.Clone();
+ expected_success_full_result_.MergeDictionary(
+ &expected_success_fetch_result_);
+}
+
+// static
+base::Value
+CredentialProviderSigninDialogTestDataStorage::MakeSignInResponseValue(
+ const std::string& id,
+ const std::string& password,
+ const std::string& email,
+ const std::string& access_token,
+ const std::string& refresh_token) {
+ base::Value args(base::Value::Type::DICTIONARY);
+ if (!email.empty())
+ args.SetKey("email", base::Value(email));
+ if (!password.empty())
+ args.SetKey("password", base::Value(password));
+ if (!id.empty())
+ args.SetKey("id", base::Value(id));
+ if (!refresh_token.empty())
+ args.SetKey("refresh_token", base::Value(refresh_token));
+ if (!access_token.empty())
+ args.SetKey("access_token", base::Value(access_token));
+
+ return args;
+}
+
+base::Value
+CredentialProviderSigninDialogTestDataStorage::MakeValidSignInResponseValue()
+ const {
+ return MakeSignInResponseValue(GetSuccessId(), GetSuccessPassword(),
+ GetSuccessEmail(), GetSuccessAccessToken(),
+ GetSuccessRefreshToken());
+}
diff --git a/chrome/browser/ui/startup/credential_provider_signin_dialog_win_test_data.h b/chrome/browser/ui/startup/credential_provider_signin_dialog_win_test_data.h
new file mode 100644
index 0000000..ed1d4bc
--- /dev/null
+++ b/chrome/browser/ui/startup/credential_provider_signin_dialog_win_test_data.h
@@ -0,0 +1,88 @@
+// 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_UI_STARTUP_CREDENTIAL_PROVIDER_SIGNIN_DIALOG_WIN_TEST_DATA_H_
+#define CHROME_BROWSER_UI_STARTUP_CREDENTIAL_PROVIDER_SIGNIN_DIALOG_WIN_TEST_DATA_H_
+
+#include <string>
+
+#include "base/values.h"
+
+// Class used to store common test data used to validate the functioning of the
+// credential provider sign in dialog. This class stores the expected login
+// complte information that the dialog is supposed to received from the gaia
+// sign in as well as the expected values for any additional token / info
+// fetches needed to complete the sign in using the credential provider.
+// On a successful sign in result, we expect the final json result to match
+// the json result generated from the internal expected_success_result_
+// value.
+class CredentialProviderSigninDialogTestDataStorage {
+ public:
+ CredentialProviderSigninDialogTestDataStorage();
+
+ static base::Value MakeSignInResponseValue(
+ const std::string& id = std::string(),
+ const std::string& password = std::string(),
+ const std::string& email = std::string(),
+ const std::string& access_token = std::string(),
+ const std::string& refresh_token = std::string());
+ base::Value MakeValidSignInResponseValue() const;
+
+ std::string GetSuccessId() const {
+ return expected_success_signin_result_.FindKey("id")->GetString();
+ }
+ std::string GetSuccessPassword() const {
+ return expected_success_signin_result_.FindKey("password")->GetString();
+ }
+ std::string GetSuccessEmail() const {
+ return expected_success_signin_result_.FindKey("email")->GetString();
+ }
+ std::string GetSuccessAccessToken() const {
+ return expected_success_signin_result_.FindKey("access_token")->GetString();
+ }
+ std::string GetSuccessRefreshToken() const {
+ return expected_success_signin_result_.FindKey("refresh_token")
+ ->GetString();
+ }
+ std::string GetSuccessTokenHandle() const {
+ return expected_success_fetch_result_.FindKey("token_handle")->GetString();
+ }
+ std::string GetSuccessMdmIdToken() const {
+ return expected_success_fetch_result_.FindKey("mdm_id_token")->GetString();
+ }
+ std::string GetSuccessFullName() const {
+ return expected_success_fetch_result_.FindKey("full_name")->GetString();
+ }
+
+ const base::Value& expected_signin_result() const {
+ return expected_success_signin_result_;
+ }
+
+ const base::Value& expected_success_fetch_result() const {
+ return expected_success_fetch_result_;
+ }
+
+ const base::Value& expected_full_result() const {
+ return expected_success_full_result_;
+ }
+
+ bool EqualsSuccessfulSigninResult(const base::Value& result_value) const {
+ return EqualsEncodedValue(expected_signin_result(), result_value);
+ }
+ bool EqualsSccessfulFetchResult(const base::Value& result_value) const {
+ return EqualsEncodedValue(expected_success_fetch_result(), result_value);
+ }
+
+ private:
+ bool EqualsEncodedValue(const base::Value& success_value,
+ const base::Value& result_value) const {
+ return result_value == success_value;
+ }
+
+ base::Value expected_success_signin_result_;
+ base::Value expected_success_fetch_result_;
+ base::Value expected_success_full_result_;
+};
+
+#endif // CHROME_BROWSER_UI_STARTUP_CREDENTIAL_PROVIDER_SIGNIN_DIALOG_WIN_TEST_DATA_H_
diff --git a/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.cc b/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.cc
new file mode 100644
index 0000000..f472311
--- /dev/null
+++ b/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.cc
@@ -0,0 +1,129 @@
+// 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 <utility>
+#include <vector>
+
+#include "chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.h"
+
+#include "base/logging.h"
+#include "base/syslog_logging.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
+#include "google_apis/gaia/gaia_oauth_client.h"
+#include "google_apis/gaia/gaia_urls.h"
+#include "google_apis/gaia/oauth2_access_token_fetcher.h"
+#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
+#include "google_apis/google_api_keys.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+
+CredentialProviderSigninInfoFetcher::CredentialProviderSigninInfoFetcher(
+ const std::string& refresh_token,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+ : scoped_access_token_fetcher_(
+ std::make_unique<OAuth2AccessTokenFetcherImpl>(this,
+ url_loader_factory,
+ refresh_token)),
+ user_info_fetcher_(
+ std::make_unique<gaia::GaiaOAuthClient>(url_loader_factory)),
+ token_handle_fetcher_(
+ std::make_unique<gaia::GaiaOAuthClient>(url_loader_factory)) {}
+
+CredentialProviderSigninInfoFetcher::~CredentialProviderSigninInfoFetcher() =
+ default;
+
+void CredentialProviderSigninInfoFetcher::SetCompletionCallbackAndStart(
+ const std::string& access_token,
+ FetchCompletionCallback completion_callback) {
+ DCHECK(!completion_callback.is_null());
+ completion_callback_ = std::move(completion_callback);
+ GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
+
+ // Scopes needed to fetch the full name of the user as well as an id token
+ // used for MDM registration.
+ std::vector<std::string> access_scopes{"email", "profile", "openid"};
+
+ scoped_access_token_fetcher_->Start(gaia_urls->oauth2_chrome_client_id(),
+ gaia_urls->oauth2_chrome_client_secret(),
+ access_scopes);
+ token_handle_fetcher_->GetTokenInfo(access_token, 0, this);
+}
+
+void CredentialProviderSigninInfoFetcher::OnGetTokenInfoResponse(
+ std::unique_ptr<base::DictionaryValue> token_info) {
+ DCHECK(token_handle_.empty());
+ bool has_error = !token_info->GetString("token_handle", &token_handle_) ||
+ token_handle_.empty();
+ WriteResultsIfFinished(has_error);
+}
+
+void CredentialProviderSigninInfoFetcher::OnGetUserInfoResponse(
+ std::unique_ptr<base::DictionaryValue> user_info) {
+ DCHECK(!mdm_id_token_.empty());
+ DCHECK(full_name_.empty());
+ bool has_error =
+ !user_info->GetString("name", &full_name_) || full_name_.empty();
+ WriteResultsIfFinished(has_error);
+}
+
+void CredentialProviderSigninInfoFetcher::OnOAuthError() {
+ WriteResultsIfFinished(true);
+}
+
+void CredentialProviderSigninInfoFetcher::OnNetworkError(int response_code) {
+ SYSLOG(ERROR) << "Network error occured while fetching token handle: "
+ << response_code;
+ WriteResultsIfFinished(true);
+}
+
+void CredentialProviderSigninInfoFetcher::OnGetTokenSuccess(
+ const TokenResponse& token_response) {
+ DCHECK(mdm_id_token_.empty());
+ DCHECK(full_name_.empty());
+ mdm_id_token_ = token_response.id_token;
+
+ if (mdm_id_token_.empty() || token_response.access_token.empty()) {
+ WriteResultsIfFinished(true);
+ return;
+ }
+
+ // Once a valid access token is given for fetching the user's full name, fire
+ // off a request to get the user's info.
+ RequestUserInfoFromAccessToken(token_response.access_token);
+}
+
+void CredentialProviderSigninInfoFetcher::OnGetTokenFailure(
+ const GoogleServiceAuthError& error) {
+ WriteResultsIfFinished(true);
+}
+
+void CredentialProviderSigninInfoFetcher::RequestUserInfoFromAccessToken(
+ const std::string& access_token) {
+ user_info_fetcher_->GetUserInfo(access_token, 0, this);
+}
+
+void CredentialProviderSigninInfoFetcher::WriteResultsIfFinished(
+ bool has_error) {
+ DCHECK(completion_callback_);
+
+ if (!has_error &&
+ (mdm_id_token_.empty() || full_name_.empty() || token_handle_.empty())) {
+ return;
+ }
+
+ base::Value fetch_result(base::Value::Type::DICTIONARY);
+ if (!has_error) {
+ fetch_result.SetKey(credential_provider::kKeyMdmIdToken,
+ base::Value(mdm_id_token_));
+ fetch_result.SetKey(credential_provider::kKeyFullname,
+ base::Value(full_name_));
+ fetch_result.SetKey(credential_provider::kKeyTokenHandle,
+ base::Value(token_handle_));
+ }
+
+ std::move(completion_callback_).Run(std::move(fetch_result));
+
+ scoped_access_token_fetcher_.reset();
+ user_info_fetcher_.reset();
+ token_handle_fetcher_.reset();
+}
diff --git a/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.h b/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.h
new file mode 100644
index 0000000..7253bcd
--- /dev/null
+++ b/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.h
@@ -0,0 +1,81 @@
+// 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_UI_STARTUP_CREDENTIAL_PROVIDER_SIGNIN_INFO_FETCHER_WIN_H_
+#define CHROME_BROWSER_UI_STARTUP_CREDENTIAL_PROVIDER_SIGNIN_INFO_FETCHER_WIN_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/values.h"
+#include "google_apis/gaia/gaia_oauth_client.h"
+#include "google_apis/gaia/oauth2_access_token_fetcher.h"
+
+namespace network {
+class SharedURLLoaderFactory;
+} // namespace network
+
+// Helper class used to query additional information needed to sign in or
+// create a new user through the Google Credential Provider for Windows. The
+// additional information needed is:
+// - User's full name.
+// - ID token used for Mobile Device Management (MDM) registration.
+// - A token handle for the user's refresh token.
+// A separate OAuth request is required for each piece of information and
+// each result arrives asynchronously so to gather all the results until they
+// have all been fetched or there is an error. Once one of the two conditions
+// are met notify the callback of the results.
+class CredentialProviderSigninInfoFetcher
+ : public gaia::GaiaOAuthClient::Delegate,
+ public OAuth2AccessTokenConsumer {
+ public:
+ // Callback signalled when the fetch of all necessary information for the GCPW
+ // is finished successfully or with an error.
+ // The single argument should always be a dictionary value and will be empty
+ // if there was an error during the fetch.
+ using FetchCompletionCallback = base::OnceCallback<void(base::Value)>;
+
+ CredentialProviderSigninInfoFetcher(
+ const std::string& refresh_token,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
+ ~CredentialProviderSigninInfoFetcher() override;
+
+ void SetCompletionCallbackAndStart(
+ const std::string& access_token,
+ FetchCompletionCallback completion_callback);
+
+ // gaia::GaiaOAuthClient::Delegate:
+ void OnGetTokenInfoResponse(
+ std::unique_ptr<base::DictionaryValue> token_info) override;
+ void OnGetUserInfoResponse(
+ std::unique_ptr<base::DictionaryValue> user_info) override;
+ void OnOAuthError() override;
+ void OnNetworkError(int response_code) override;
+
+ // OAuth2AccessTokenConsumer:
+ void OnGetTokenSuccess(const TokenResponse& token_response) override;
+ void OnGetTokenFailure(const GoogleServiceAuthError& error) override;
+
+ protected:
+ void RequestUserInfoFromAccessToken(const std::string& access_token);
+ void WriteResultsIfFinished(bool has_error);
+
+ // This callback is triggered once all fetch requests have completed
+ // successfully or there was an error in one of the fetch requests.
+ FetchCompletionCallback completion_callback_;
+
+ std::string token_handle_;
+ std::string full_name_;
+ std::string mdm_id_token_;
+
+ std::unique_ptr<OAuth2AccessTokenFetcher> scoped_access_token_fetcher_;
+ std::unique_ptr<gaia::GaiaOAuthClient> user_info_fetcher_;
+ std::unique_ptr<gaia::GaiaOAuthClient> token_handle_fetcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(CredentialProviderSigninInfoFetcher);
+};
+
+#endif // CHROME_BROWSER_UI_STARTUP_CREDENTIAL_PROVIDER_SIGNIN_INFO_FETCHER_WIN_H_
diff --git a/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win_unittest.cc b/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win_unittest.cc
new file mode 100644
index 0000000..0a4f2893
--- /dev/null
+++ b/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win_unittest.cc
@@ -0,0 +1,231 @@
+// 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/ui/startup/credential_provider_signin_info_fetcher_win.h"
+#include "chrome/browser/ui/startup/credential_provider_signin_dialog_win_test_data.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/json/json_reader.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "google_apis/gaia/gaia_urls.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "services/network/test/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+constexpr char kAccessTokenValue[] = "test_access_token_value";
+constexpr char kRefreshTokenValue[] = "test_refresh_token_value";
+constexpr char kInvalidTokenInfoResponse[] =
+ "{"
+ " \"error\": \"invalid_token\""
+ "}";
+constexpr char kInvalidUserInfoResponse[] =
+ "{"
+ " \"error\": \"invalid_token\""
+ "}";
+constexpr char kInvalidAccessTokenFetchResponse[] =
+ "{"
+ " \"error\": \"invalid_token\""
+ "}";
+} // namespace
+
+// Provides base functionality for the AccessTokenFetcher Tests below. The
+// FakeURLFetcherFactory allows us to override the response data and payload for
+// specified URLs. We use this to stub out network calls made by the
+// AccessTokenFetcher. This fixture also creates an IO MessageLoop, if
+// necessary, for use by the AccessTokenFetcher.
+class CredentialProviderFetcherTest : public ::testing::Test {
+ protected:
+ CredentialProviderFetcherTest();
+ ~CredentialProviderFetcherTest() override;
+
+ void OnFetchComplete(base::OnceClosure done_closure,
+ base::Value fetch_result);
+
+ void SetFakeResponses(const std::string& access_token_fetch_data,
+ net::HttpStatusCode access_token_fetch_code,
+ int access_token_net_error,
+ const std::string& user_info_data,
+ net::HttpStatusCode user_info_code,
+ int user_info_net_error,
+ const std::string& token_info_data,
+ net::HttpStatusCode token_info_code,
+ int token_info_net_error);
+
+ scoped_refptr<network::SharedURLLoaderFactory> shared_factory() {
+ return shared_factory_;
+ }
+
+ void RunFetcher();
+
+ // Used for result verification
+ base::Value fetch_result_;
+ CredentialProviderSigninDialogTestDataStorage test_data_storage_;
+
+ std::string valid_token_info_response_;
+ std::string valid_user_info_response_;
+ std::string valid_access_token_fetch_response_;
+
+ private:
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+ network::TestURLLoaderFactory test_url_loader_factory_;
+ scoped_refptr<network::SharedURLLoaderFactory> shared_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(CredentialProviderFetcherTest);
+};
+
+CredentialProviderFetcherTest::CredentialProviderFetcherTest()
+ : shared_factory_(
+ base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+ &test_url_loader_factory_)) {
+ valid_token_info_response_ =
+ "{"
+ " \"audience\": \"blah.apps.googleusercontent.blah.com\","
+ " \"used_id\": \"1234567890\","
+ " \"scope\": \"all the things\","
+ " \"expires_in\": 1800,"
+ " \"token_type\": \"Bearer\","
+ " \"token_handle\": \"" +
+ test_data_storage_.GetSuccessTokenHandle() +
+ "\""
+ "}";
+ valid_user_info_response_ =
+ "{"
+ " \"name\": \"" +
+ test_data_storage_.GetSuccessFullName() +
+ "\""
+ "}";
+ valid_access_token_fetch_response_ =
+ "{"
+ " \"access_token\": \"123456789\","
+ " \"id_token\": \"" +
+ test_data_storage_.GetSuccessMdmIdToken() +
+ "\","
+ " \"expires_in\": 1800"
+ "}";
+}
+
+CredentialProviderFetcherTest::~CredentialProviderFetcherTest() = default;
+
+void CredentialProviderFetcherTest::OnFetchComplete(
+ base::OnceClosure done_closure,
+ base::Value fetch_result) {
+ EXPECT_TRUE(fetch_result.is_dict());
+ fetch_result_ = std::move(fetch_result);
+
+ std::move(done_closure).Run();
+}
+
+void CredentialProviderFetcherTest::SetFakeResponses(
+ const std::string& access_token_fetch_data,
+ net::HttpStatusCode access_token_fetch_code,
+ int access_token_net_error,
+ const std::string& user_info_data,
+ net::HttpStatusCode user_info_code,
+ int user_info_net_error,
+ const std::string& token_info_data,
+ net::HttpStatusCode token_info_code,
+ int token_info_net_error) {
+ test_url_loader_factory_.AddResponse(
+ GaiaUrls::GetInstance()->oauth2_token_info_url(),
+ network::CreateResourceResponseHead(token_info_code), token_info_data,
+ network::URLLoaderCompletionStatus(token_info_net_error));
+
+ test_url_loader_factory_.AddResponse(
+ GaiaUrls::GetInstance()->oauth_user_info_url(),
+ network::CreateResourceResponseHead(user_info_code), user_info_data,
+ network::URLLoaderCompletionStatus(user_info_net_error));
+
+ test_url_loader_factory_.AddResponse(
+ GaiaUrls::GetInstance()->oauth2_token_url(),
+ network::CreateResourceResponseHead(access_token_fetch_code),
+ access_token_fetch_data,
+ network::URLLoaderCompletionStatus(access_token_net_error));
+}
+
+void CredentialProviderFetcherTest::RunFetcher() {
+ base::RunLoop run_loop;
+ auto fetcher_callback =
+ base::BindOnce(&CredentialProviderFetcherTest::OnFetchComplete,
+ base::Unretained(this), run_loop.QuitClosure());
+
+ CredentialProviderSigninInfoFetcher fetcher(kRefreshTokenValue,
+ shared_factory());
+ fetcher.SetCompletionCallbackAndStart(kAccessTokenValue,
+ std::move(fetcher_callback));
+ run_loop.Run();
+}
+
+TEST_F(CredentialProviderFetcherTest, ValidFetchResult) {
+ SetFakeResponses(valid_access_token_fetch_response_, net::HTTP_OK, net::OK,
+ valid_user_info_response_, net::HTTP_OK, net::OK,
+ valid_token_info_response_, net::HTTP_OK, net::OK);
+
+ RunFetcher();
+ EXPECT_FALSE(fetch_result_.DictEmpty());
+ EXPECT_TRUE(test_data_storage_.EqualsSccessfulFetchResult(fetch_result_));
+}
+
+TEST_F(CredentialProviderFetcherTest,
+ ValidFetchResultWithNetworkErrorOnTokenFetch) {
+ SetFakeResponses(valid_access_token_fetch_response_, net::HTTP_BAD_REQUEST,
+ net::ERR_FAILED, valid_user_info_response_, net::HTTP_OK,
+ net::OK, valid_token_info_response_, net::HTTP_OK, net::OK);
+
+ RunFetcher();
+ EXPECT_TRUE(fetch_result_.DictEmpty());
+}
+
+TEST_F(CredentialProviderFetcherTest,
+ ValidFetchResultWithNetworkErrorOnUserInfoFetch) {
+ SetFakeResponses(valid_access_token_fetch_response_, net::HTTP_OK, net::OK,
+ valid_user_info_response_, net::HTTP_BAD_REQUEST,
+ net::ERR_FAILED, valid_token_info_response_, net::HTTP_OK,
+ net::OK);
+
+ RunFetcher();
+ EXPECT_TRUE(fetch_result_.DictEmpty());
+}
+
+TEST_F(CredentialProviderFetcherTest, InvalidAccessTokenFetch) {
+ SetFakeResponses(kInvalidAccessTokenFetchResponse, net::HTTP_OK, net::OK,
+ valid_user_info_response_, net::HTTP_OK, net::OK,
+ valid_token_info_response_, net::HTTP_OK, net::OK);
+
+ RunFetcher();
+ EXPECT_TRUE(fetch_result_.DictEmpty());
+}
+
+TEST_F(CredentialProviderFetcherTest, InvalidUserInfoFetch) {
+ SetFakeResponses(valid_access_token_fetch_response_, net::HTTP_OK, net::OK,
+ kInvalidUserInfoResponse, net::HTTP_OK, net::OK,
+ valid_token_info_response_, net::HTTP_OK, net::OK);
+
+ RunFetcher();
+ EXPECT_TRUE(fetch_result_.DictEmpty());
+}
+
+TEST_F(CredentialProviderFetcherTest, InvalidTokenInfoFetch) {
+ SetFakeResponses(valid_access_token_fetch_response_, net::HTTP_OK, net::OK,
+ valid_user_info_response_, net::HTTP_OK, net::OK,
+ kInvalidTokenInfoResponse, net::HTTP_OK, net::OK);
+
+ RunFetcher();
+ EXPECT_TRUE(fetch_result_.DictEmpty());
+}
+
+TEST_F(CredentialProviderFetcherTest, InvalidFetchResult) {
+ SetFakeResponses(kInvalidAccessTokenFetchResponse, net::HTTP_OK, net::OK,
+ kInvalidUserInfoResponse, net::HTTP_OK, net::OK,
+ kInvalidTokenInfoResponse, net::HTTP_OK, net::OK);
+
+ RunFetcher();
+ EXPECT_TRUE(fetch_result_.DictEmpty());
+}
diff --git a/chrome/browser/ui/startup/startup_browser_creator.cc b/chrome/browser/ui/startup/startup_browser_creator.cc
index 2e13111..2ac28dc 100644
--- a/chrome/browser/ui/startup/startup_browser_creator.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator.cc
@@ -93,6 +93,7 @@
#include "chrome/browser/metrics/jumplist_metrics_win.h"
#include "chrome/browser/notifications/win/notification_launch_id.h"
#include "chrome/browser/ui/webui/settings/reset_settings_handler.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
#endif
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
@@ -329,6 +330,12 @@
<< "browser session.";
}
+#if defined(OS_WIN)
+ // Continue with the incognito profile if this is a credential provider logon.
+ if (command_line.HasSwitch(credential_provider::kGcpwSigninSwitch))
+ profile = profile->GetOffTheRecordProfile();
+#endif
+
// Note: This check should have been done in ProcessCmdLineImpl()
// before calling this function. However chromeos/login/login_utils.cc
// calls this function directly (see comments there) so it has to be checked
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index 5da96407..63914ac 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -77,6 +77,8 @@
#endif // defined(GOOGLE_CHROME_BUILD)
#include "chrome/browser/notifications/notification_platform_bridge_win.h"
#include "chrome/browser/shell_integration_win.h"
+#include "chrome/browser/ui/startup/credential_provider_signin_dialog_win.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
#endif // defined(OS_WIN)
#if BUILDFLAG(ENABLE_RLZ)
@@ -109,16 +111,18 @@
LM_SHORTCUT_TASKBAR = 8, // Launched from the taskbar.
LM_USER_EXPERIMENT = 9, // Launched after acceptance of a user experiment.
LM_OTHER_OS = 10, // Result bucket for OSes with no coverage here.
- LM_MAC_UNDOCKED_DISK_LAUNCH = 11, // Undocked launch from disk.
- LM_MAC_DOCKED_DISK_LAUNCH = 12, // Docked launch from disk.
- LM_MAC_UNDOCKED_DMG_LAUNCH = 13, // Undocked launch from a dmg.
- LM_MAC_DOCKED_DMG_LAUNCH = 14, // Docked launch from a dmg.
- LM_MAC_DOCK_STATUS_ERROR = 15, // Error determining dock status.
- LM_MAC_DMG_STATUS_ERROR = 16, // Error determining dmg status.
- LM_MAC_DOCK_DMG_STATUS_ERROR = 17, // Error determining dock and dmg status.
- LM_WIN_PLATFORM_NOTIFICATION = 18, // Launched from toast notification
- // activation on Windows.
- LM_SHORTCUT_START_MENU = 19, // A Windows Start Menu shortcut.
+ LM_MAC_UNDOCKED_DISK_LAUNCH = 11, // Undocked launch from disk.
+ LM_MAC_DOCKED_DISK_LAUNCH = 12, // Docked launch from disk.
+ LM_MAC_UNDOCKED_DMG_LAUNCH = 13, // Undocked launch from a dmg.
+ LM_MAC_DOCKED_DMG_LAUNCH = 14, // Docked launch from a dmg.
+ LM_MAC_DOCK_STATUS_ERROR = 15, // Error determining dock status.
+ LM_MAC_DMG_STATUS_ERROR = 16, // Error determining dmg status.
+ LM_MAC_DOCK_DMG_STATUS_ERROR = 17, // Error determining dock and dmg status.
+ LM_WIN_PLATFORM_NOTIFICATION = 18, // Launched from toast notification
+ // activation on Windows.
+ LM_SHORTCUT_START_MENU = 19, // A Windows Start Menu shortcut.
+ LM_CREDENTIAL_PROVIDER_SIGNIN = 20, // Started as a logon stub for the Google
+ // Credential Provider for Windows.
};
// Returns a LaunchMode value if one can be determined with low overhead, or
@@ -319,6 +323,17 @@
}
return false;
}
+ // If being started for credential provider logon purpose, only show the
+ // signin page.
+ if (command_line_.HasSwitch(credential_provider::kGcpwSigninSwitch)) {
+ DCHECK_EQ(Profile::ProfileType::INCOGNITO_PROFILE,
+ profile_->GetProfileType());
+ // NOTE: All launch urls are ignored when running with --gcpw-logon since
+ // this mode only loads Google's sign in page.
+ StartGCPWSignin(command_line_, profile_);
+ RecordLaunchModeHistogram(LM_CREDENTIAL_PROVIDER_SIGNIN);
+ return true;
+ }
#endif // defined(OS_WIN)
if (command_line_.HasSwitch(switches::kAppId)) {
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
index 9071078f..6858dffb 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
@@ -22,6 +22,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
+#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/password_manager/password_store_factory.h"
#include "chrome/browser/profiles/profile.h"
@@ -74,6 +75,12 @@
#include "net/base/url_util.h"
#include "ui/base/l10n/l10n_util.h"
+#if defined(OS_WIN)
+
+#include "chrome/credential_provider/common/gcp_strings.h"
+
+#endif // defined(OS_WIN)
+
namespace {
void LogHistogramValue(signin_metrics::AccessPointAction action) {
@@ -218,6 +225,33 @@
browser = handler_->GetDesktopBrowser();
}
+ signin_metrics::AccessPoint access_point =
+ signin::GetAccessPointForPromoURL(current_url_);
+ signin_metrics::Reason reason =
+ signin::GetSigninReasonForPromoURL(current_url_);
+ if (reason == signin_metrics::Reason::REASON_FETCH_LST_ONLY) {
+// Constants are only available on Windows for the Google Credential
+// Provider for Windows. Other platforms will just close the dialog here.
+#if defined(OS_WIN)
+ std::string json_retval;
+ base::Value args(base::Value::Type::DICTIONARY);
+ args.SetKey(credential_provider::kKeyEmail, base::Value(email_));
+ args.SetKey(credential_provider::kKeyPassword, base::Value(password_));
+ args.SetKey(credential_provider::kKeyId, base::Value(gaia_id_));
+ args.SetKey(credential_provider::kKeyRefreshToken,
+ base::Value(result.refresh_token));
+ args.SetKey(credential_provider::kKeyAccessToken,
+ base::Value(result.access_token));
+
+ handler_->SendLSTFetchResultsMessage(args);
+#else
+ if (handler_)
+ handler_->CloseDialogFromJavascript();
+#endif // defined(OS_WIN)
+ base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
+ return;
+ }
+
AboutSigninInternals* about_signin_internals =
AboutSigninInternalsFactory::GetForProfile(profile_);
about_signin_internals->OnRefreshTokenReceived("Successful");
@@ -227,11 +261,6 @@
AccountTrackerServiceFactory::GetForProfile(profile_)
->SeedAccountInfo(gaia_id_, email_);
- signin_metrics::AccessPoint access_point =
- signin::GetAccessPointForPromoURL(current_url_);
- signin_metrics::Reason reason =
- signin::GetSigninReasonForPromoURL(current_url_);
-
SigninManager* signin_manager = SigninManagerFactory::GetForProfile(profile_);
std::string primary_email =
signin_manager->GetAuthenticatedAccountInfo().email;
@@ -399,9 +428,13 @@
if (handler_)
handler_->HandleLoginError(error.ToString(), base::string16());
- AboutSigninInternals* about_signin_internals =
- AboutSigninInternalsFactory::GetForProfile(profile_);
- about_signin_internals->OnRefreshTokenReceived("Failure");
+ signin_metrics::Reason reason =
+ signin::GetSigninReasonForPromoURL(current_url_);
+ if (reason != signin_metrics::Reason::REASON_FETCH_LST_ONLY) {
+ AboutSigninInternals* about_signin_internals =
+ AboutSigninInternalsFactory::GetForProfile(profile_);
+ about_signin_internals->OnRefreshTokenReceived("Failure");
+ }
base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
}
@@ -518,16 +551,18 @@
// the current profile is the system profile. In this case, use the email to
// find the right profile to reauthenticate. Otherwise the profile can be
// taken from web_ui().
+ signin_metrics::Reason reason =
+ signin::GetSigninReasonForPromoURL(current_url);
+
Profile* profile = Profile::FromWebUI(web_ui());
- if (IsSystemProfile(profile)) {
+ if (reason != signin_metrics::Reason::REASON_FETCH_LST_ONLY &&
+ IsSystemProfile(profile)) {
ProfileManager* manager = g_browser_process->profile_manager();
base::FilePath path = profiles::GetPathOfProfileWithEmail(manager, email);
if (path.empty()) {
path = UserManager::GetSigninProfilePath();
}
if (!path.empty()) {
- signin_metrics::Reason reason =
- signin::GetSigninReasonForPromoURL(current_url);
// If we are only reauthenticating a profile in the user manager (and not
// unlocking it), load the profile and finish the login.
if (reason == signin_metrics::Reason::REASON_REAUTHENTICATION) {
@@ -659,7 +694,8 @@
}
std::string error_msg;
- bool can_offer = CanOfferSignin(profile, can_offer_for, params.gaia_id,
+ bool can_offer = reason == signin_metrics::Reason::REASON_FETCH_LST_ONLY ||
+ CanOfferSignin(profile, can_offer_for, params.gaia_id,
params.email, &error_msg);
if (!can_offer) {
if (params.handler) {
@@ -671,7 +707,8 @@
AboutSigninInternals* about_signin_internals =
AboutSigninInternalsFactory::GetForProfile(profile);
- about_signin_internals->OnAuthenticationResultReceived("Successful");
+ if (about_signin_internals)
+ about_signin_internals->OnAuthenticationResultReceived("Successful");
std::string signin_scoped_device_id =
GetSigninScopedDeviceIdForProfile(profile);
@@ -690,13 +727,23 @@
// If opened from user manager to unlock a profile, make sure the user manager
// is closed and that the profile is marked as unlocked.
- if (!params.is_force_sign_in_with_usermanager) {
+ if (reason != signin_metrics::Reason::REASON_FETCH_LST_ONLY &&
+ !params.is_force_sign_in_with_usermanager) {
UnlockProfileAndHideLoginUI(params.profile_path, params.handler);
}
}
void InlineLoginHandlerImpl::HandleLoginError(const std::string& error_msg,
const base::string16& email) {
+ content::WebContents* contents = web_ui()->GetWebContents();
+ const GURL& current_url = contents->GetURL();
+ signin_metrics::Reason reason =
+ signin::GetSigninReasonForPromoURL(current_url);
+
+ if (reason == signin_metrics::Reason::REASON_FETCH_LST_ONLY) {
+ SendLSTFetchResultsMessage(base::Value(base::Value::Type::DICTIONARY));
+ return;
+ }
SyncStarterCallback(OneClickSigninSyncStarter::SYNC_SETUP_FAILURE);
Browser* browser = GetDesktopBrowser();
Profile* profile = Profile::FromWebUI(web_ui());
@@ -711,6 +758,12 @@
}
}
+void InlineLoginHandlerImpl::SendLSTFetchResultsMessage(
+ const base::Value& arg) {
+ if (IsJavascriptAllowed())
+ CallJavascriptFunction("inline.login.sendLSTFetchResults", arg);
+}
+
Browser* InlineLoginHandlerImpl::GetDesktopBrowser() {
Browser* browser = chrome::FindBrowserWithWebContents(
web_ui()->GetWebContents());
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_impl.h b/chrome/browser/ui/webui/signin/inline_login_handler_impl.h
index 8234ded..d1f2979 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_impl.h
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_impl.h
@@ -47,6 +47,13 @@
void HandleLoginError(const std::string& error_msg,
const base::string16& email);
+ // Calls the javascript function 'sendLSTFetchResults' with the given
+ // base::Value result. This value will be passed to another
+ // WebUiMessageHandler which needs to handle the 'lstFetchResults' message
+ // with a single argument that is the dictionary of values relevant for the
+ // sign in of the user.
+ void SendLSTFetchResultsMessage(const base::Value& arg);
+
private:
// InlineLoginHandler overrides:
void SetExtraInitParams(base::DictionaryValue& params) override;
diff --git a/chrome/credential_provider/common/BUILD.gn b/chrome/credential_provider/common/BUILD.gn
new file mode 100644
index 0000000..69a9bf52
--- /dev/null
+++ b/chrome/credential_provider/common/BUILD.gn
@@ -0,0 +1,13 @@
+# 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.
+
+# Common string constants shared between the credential provider DLL
+# and Chrome.
+
+source_set("common_constants") {
+ sources = [
+ "gcp_strings.cc",
+ "gcp_strings.h",
+ ]
+}
diff --git a/chrome/credential_provider/gaiacp/gcp_strings.cc b/chrome/credential_provider/common/gcp_strings.cc
similarity index 85%
rename from chrome/credential_provider/gaiacp/gcp_strings.cc
rename to chrome/credential_provider/common/gcp_strings.cc
index 00806f6e..bf1d7eb 100644
--- a/chrome/credential_provider/gaiacp/gcp_strings.cc
+++ b/chrome/credential_provider/common/gcp_strings.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/credential_provider/gaiacp/gcp_strings.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
namespace credential_provider {
@@ -14,6 +14,7 @@
const char kKeyMdmIdToken[] = "mdm_id_token";
const char kKeyPassword[] = "password";
const char kKeyRefreshToken[] = "refresh_token";
+const char kKeyAccessToken[] = "access_token";
const char kKeySID[] = "sid";
const char kKeyTokenHandle[] = "token_handle";
const char kKeyUsername[] = "user_name";
@@ -41,4 +42,8 @@
L"SOFTWARE\\Google\\Update\\Clients\\"
L"{32987697-A14E-4B89-84D6-630D5431E831}";
+// Chrome is being opened to show the credential provider logon page. This
+// page is always shown in incognito mode.
+const char kGcpwSigninSwitch[] = "gcpw-signin";
+
} // namespace credential_provider
diff --git a/chrome/credential_provider/gaiacp/gcp_strings.h b/chrome/credential_provider/common/gcp_strings.h
similarity index 83%
rename from chrome/credential_provider/gaiacp/gcp_strings.h
rename to chrome/credential_provider/common/gcp_strings.h
index 481fdb1..78ac46c 100644
--- a/chrome/credential_provider/gaiacp/gcp_strings.h
+++ b/chrome/credential_provider/common/gcp_strings.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_CREDENTIAL_PROVIDER_GAIACP_GCP_STRINGS_H_
-#define CHROME_CREDENTIAL_PROVIDER_GAIACP_GCP_STRINGS_H_
+#ifndef CHROME_CREDENTIAL_PROVIDER_COMMON_GCP_STRINGS_H_
+#define CHROME_CREDENTIAL_PROVIDER_COMMON_GCP_STRINGS_H_
namespace credential_provider {
@@ -15,6 +15,7 @@
extern const char kKeyMdmIdToken[];
extern const char kKeyPassword[];
extern const char kKeyRefreshToken[];
+extern const char kKeyAccessToken[];
extern const char kKeySID[];
extern const char kKeyTokenHandle[];
extern const char kKeyUsername[];
@@ -38,6 +39,8 @@
extern const wchar_t kRegUpdaterClientStateAppPath[];
extern const wchar_t kRegUpdaterClientsAppPath[];
+extern const char kGcpwSigninSwitch[];
+
} // namespace credential_provider
-#endif // CHROME_CREDENTIAL_PROVIDER_GAIACP_GCP_STRINGS_H_
+#endif // CHROME_CREDENTIAL_PROVIDER_COMMON_GCP_STRINGS_H_
diff --git a/chrome/credential_provider/gaiacp/BUILD.gn b/chrome/credential_provider/gaiacp/BUILD.gn
index 34bdaa56..f9e5adfc 100644
--- a/chrome/credential_provider/gaiacp/BUILD.gn
+++ b/chrome/credential_provider/gaiacp/BUILD.gn
@@ -15,17 +15,17 @@
import("//testing/test.gni")
# This static library is shared with the setup program.
-
source_set("common") {
sources = [
- "gcp_strings.cc",
- "gcp_strings.h",
"gcp_utils.cc",
"gcp_utils.h",
"logging.cc",
"logging.h",
]
public_configs = [ ":common_config" ]
+ public_deps = [
+ "//chrome/credential_provider/common:common_constants",
+ ]
deps = [
"//base:base",
"//components/version_info",
diff --git a/chrome/credential_provider/gaiacp/dllmain.cc b/chrome/credential_provider/gaiacp/dllmain.cc
index b670b89..bddebd82 100644
--- a/chrome/credential_provider/gaiacp/dllmain.cc
+++ b/chrome/credential_provider/gaiacp/dllmain.cc
@@ -20,11 +20,11 @@
#include "base/values.h"
#include "base/win/registry.h"
#include "chrome/common/chrome_version.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
#include "chrome/credential_provider/gaiacp/gaia_credential.h"
#include "chrome/credential_provider/gaiacp/gaia_credential_base.h"
#include "chrome/credential_provider/gaiacp/gaia_credential_provider.h"
#include "chrome/credential_provider/gaiacp/gaia_credential_provider_module.h"
-#include "chrome/credential_provider/gaiacp/gcp_strings.h"
#include "chrome/credential_provider/gaiacp/gcp_utils.h"
#include "chrome/credential_provider/gaiacp/logging.h"
#include "chrome/credential_provider/gaiacp/os_user_manager.h"
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_base.cc b/chrome/credential_provider/gaiacp/gaia_credential_base.cc
index fcd63e0..0429541e 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential_base.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential_base.cc
@@ -21,8 +21,8 @@
#include "base/win/current_module.h"
#include "base/win/registry.h"
#include "base/win/scoped_handle.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
#include "chrome/credential_provider/gaiacp/gaia_credential_provider_i.h"
-#include "chrome/credential_provider/gaiacp/gcp_strings.h"
#include "chrome/credential_provider/gaiacp/gcp_utils.h"
#include "chrome/credential_provider/gaiacp/logging.h"
#include "chrome/credential_provider/gaiacp/os_process_manager.h"
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc b/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc
index fd9eaa3..f16c3db 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc
@@ -17,9 +17,9 @@
#include "base/test/multiprocess_test.h"
#include "base/time/time.h"
#include "base/values.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
#include "chrome/credential_provider/gaiacp/gaia_credential.h"
#include "chrome/credential_provider/gaiacp/gaia_credential_provider_i.h"
-#include "chrome/credential_provider/gaiacp/gcp_strings.h"
#include "chrome/credential_provider/test/com_fakes.h"
#include "chrome/credential_provider/test/gcp_fakes.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_provider.cc b/chrome/credential_provider/gaiacp/gaia_credential_provider.cc
index 64a5c7cc..8cfc88d 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential_provider.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential_provider.cc
@@ -12,9 +12,9 @@
#include "base/strings/string16.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
#include "chrome/credential_provider/gaiacp/gaia_credential.h"
#include "chrome/credential_provider/gaiacp/gaia_credential_provider_i.h"
-#include "chrome/credential_provider/gaiacp/gcp_strings.h"
#include "chrome/credential_provider/gaiacp/logging.h"
#include "chrome/credential_provider/gaiacp/os_user_manager.h"
#include "chrome/credential_provider/gaiacp/reauth_credential.h"
diff --git a/chrome/credential_provider/gaiacp/gcp_utils.cc b/chrome/credential_provider/gaiacp/gcp_utils.cc
index 1ce0825..f6dac4a 100644
--- a/chrome/credential_provider/gaiacp/gcp_utils.cc
+++ b/chrome/credential_provider/gaiacp/gcp_utils.cc
@@ -40,7 +40,7 @@
#include "base/win/current_module.h"
#include "base/win/registry.h"
#include "base/win/win_util.h"
-#include "chrome/credential_provider/gaiacp/gcp_strings.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
#include "chrome/credential_provider/gaiacp/logging.h"
namespace credential_provider {
diff --git a/chrome/credential_provider/gaiacp/os_process_manager.cc b/chrome/credential_provider/gaiacp/os_process_manager.cc
index 5e2da2c..8ae6fb4 100644
--- a/chrome/credential_provider/gaiacp/os_process_manager.cc
+++ b/chrome/credential_provider/gaiacp/os_process_manager.cc
@@ -37,7 +37,7 @@
#include "base/win/registry.h"
#include "base/win/scoped_process_information.h"
#include "base/win/win_util.h"
-#include "chrome/credential_provider/gaiacp/gcp_strings.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
#include "chrome/credential_provider/gaiacp/gcp_utils.h"
#include "chrome/credential_provider/gaiacp/logging.h"
diff --git a/chrome/credential_provider/gaiacp/reauth_credential.cc b/chrome/credential_provider/gaiacp/reauth_credential.cc
index e0ff970..91a1866 100644
--- a/chrome/credential_provider/gaiacp/reauth_credential.cc
+++ b/chrome/credential_provider/gaiacp/reauth_credential.cc
@@ -5,7 +5,7 @@
#include "chrome/credential_provider/gaiacp/reauth_credential.h"
#include "base/stl_util.h"
-#include "chrome/credential_provider/gaiacp/gcp_strings.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
#include "chrome/credential_provider/gaiacp/logging.h"
#include "chrome/credential_provider/gaiacp/os_user_manager.h"
#include "chrome/credential_provider/gaiacp/reg_utils.h"
diff --git a/chrome/credential_provider/gaiacp/reg_utils.cc b/chrome/credential_provider/gaiacp/reg_utils.cc
index 7e95ef619..357030f 100644
--- a/chrome/credential_provider/gaiacp/reg_utils.cc
+++ b/chrome/credential_provider/gaiacp/reg_utils.cc
@@ -8,7 +8,7 @@
#include "base/stl_util.h"
#include "base/win/registry.h"
-#include "chrome/credential_provider/gaiacp/gcp_strings.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
namespace credential_provider {
diff --git a/chrome/credential_provider/gaiacp/scoped_user_profile.cc b/chrome/credential_provider/gaiacp/scoped_user_profile.cc
index 0a3eb25..f57d221 100644
--- a/chrome/credential_provider/gaiacp/scoped_user_profile.cc
+++ b/chrome/credential_provider/gaiacp/scoped_user_profile.cc
@@ -13,7 +13,7 @@
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/registry.h"
-#include "chrome/credential_provider/gaiacp/gcp_strings.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
#include "chrome/credential_provider/gaiacp/gcp_utils.h"
#include "chrome/credential_provider/gaiacp/logging.h"
#include "chrome/credential_provider/gaiacp/reg_utils.h"
diff --git a/chrome/credential_provider/test/gcp_setup_unittests.cc b/chrome/credential_provider/test/gcp_setup_unittests.cc
index 77db864..d81ebc6 100644
--- a/chrome/credential_provider/test/gcp_setup_unittests.cc
+++ b/chrome/credential_provider/test/gcp_setup_unittests.cc
@@ -23,8 +23,8 @@
#include "base/test/test_reg_util_win.h"
#include "base/win/registry.h"
#include "build/build_config.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
#include "chrome/credential_provider/gaiacp/gaia_credential_provider_i.h"
-#include "chrome/credential_provider/gaiacp/gcp_strings.h"
#include "chrome/credential_provider/gaiacp/gcp_utils.h"
#include "chrome/credential_provider/setup/setup_lib.h"
#include "chrome/credential_provider/test/gcp_fakes.h"
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 3f86810..44a4e0af 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -396,6 +396,19 @@
}
}
+if (is_win) {
+ source_set("credential_provider_test_utils") {
+ testonly = true
+ sources = [
+ "../browser/ui/startup/credential_provider_signin_dialog_win_test_data.cc",
+ "../browser/ui/startup/credential_provider_signin_dialog_win_test_data.h",
+ ]
+ deps = [
+ "//base",
+ ]
+ }
+}
+
test("browser_tests") {
sources = [
# TODO(jbudorick): Move tests here from other lists as Android support is
@@ -1980,6 +1993,7 @@
sources += [
"../browser/browser_switcher/browser_switcher_service_browsertest.cc",
"../browser/printing/pdf_to_emf_converter_browsertest.cc",
+ "../browser/ui/startup/credential_provider_signin_dialog_win_browsertest.cc",
"../browser/ui/views/accessibility/invert_bubble_view_browsertest.cc",
"../browser/ui/views/settings_reset_prompt_dialog_browsertest.cc",
"../browser/ui/views/uninstall_view_browsertest.cc",
@@ -2002,6 +2016,7 @@
deps += [
"//chrome:other_version",
"//chrome/app:command_ids",
+ "//chrome/test:credential_provider_test_utils",
"//device/vr",
"//third_party/wtl",
"//ui/resources",
@@ -2933,6 +2948,12 @@
data_deps += [ "//chrome:chrome_framework" ]
}
+ if (is_win) {
+ assert(toolkit_views)
+ sources += [ "../browser/ui/startup/credential_provider_signin_info_fetcher_win_unittest.cc" ]
+ deps += [ "//chrome/test:credential_provider_test_utils" ]
+ }
+
if (enable_dice_support) {
sources += [
"../browser/signin/dice_response_handler_unittest.cc",
diff --git a/components/keep_alive_registry/keep_alive_types.cc b/components/keep_alive_registry/keep_alive_types.cc
index 8f47bc5..37190e9f 100644
--- a/components/keep_alive_registry/keep_alive_types.cc
+++ b/components/keep_alive_registry/keep_alive_types.cc
@@ -47,6 +47,8 @@
return out << "PROFILE_LOADER";
case KeepAliveOrigin::USER_MANAGER_VIEW:
return out << "USER_MANAGER_VIEW";
+ case KeepAliveOrigin::CREDENTIAL_PROVIDER_SIGNIN_DIALOG:
+ return out << "CREDENTIAL_PROVIDER_SIGNIN_DIALOG";
}
NOTREACHED();
diff --git a/components/keep_alive_registry/keep_alive_types.h b/components/keep_alive_registry/keep_alive_types.h
index 9e1d49d..879e0b7 100644
--- a/components/keep_alive_registry/keep_alive_types.h
+++ b/components/keep_alive_registry/keep_alive_types.h
@@ -44,7 +44,8 @@
PANEL_VIEW,
PROFILE_HELPER,
PROFILE_LOADER,
- USER_MANAGER_VIEW
+ USER_MANAGER_VIEW,
+ CREDENTIAL_PROVIDER_SIGNIN_DIALOG,
};
// Restart: Allow Chrome to restart when all the registered KeepAlives allow
diff --git a/components/signin/core/browser/signin_metrics.cc b/components/signin/core/browser/signin_metrics.cc
index 9abc7c9..6526d05 100644
--- a/components/signin/core/browser/signin_metrics.cc
+++ b/components/signin/core/browser/signin_metrics.cc
@@ -118,6 +118,10 @@
base::RecordAction(
base::UserMetricsAction("Signin_Signin_FromManageCardsBubble"));
break;
+ case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_Signin_FromMachineLogon"));
+ break;
case AccessPoint::ACCESS_POINT_MAX:
NOTREACHED();
break;
@@ -186,6 +190,7 @@
case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
case AccessPoint::ACCESS_POINT_UNKNOWN:
case AccessPoint::ACCESS_POINT_FORCE_SIGNIN_WARNING:
+ case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
NOTREACHED() << "Signin_SigninWithDefault_From* user actions"
<< " are not recorded for access_point "
<< static_cast<int>(access_point)
@@ -259,6 +264,7 @@
case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
case AccessPoint::ACCESS_POINT_UNKNOWN:
case AccessPoint::ACCESS_POINT_FORCE_SIGNIN_WARNING:
+ case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
NOTREACHED() << "Signin_SigninNotDefault_From* user actions"
<< " are not recorded for access point "
<< static_cast<int>(access_point)
@@ -332,6 +338,7 @@
case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
case AccessPoint::ACCESS_POINT_UNKNOWN:
case AccessPoint::ACCESS_POINT_FORCE_SIGNIN_WARNING:
+ case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
// These access points do not support personalized sign-in promos, so
// |Signin_SigninNewAccountPreDice_From*| user actions should not
// be recorded for them. Note: To avoid bloating the sign-in APIs, the
@@ -416,6 +423,7 @@
case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
case AccessPoint::ACCESS_POINT_UNKNOWN:
case AccessPoint::ACCESS_POINT_FORCE_SIGNIN_WARNING:
+ case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
// These access points do not support personalized sign-in promos, so
// |Signin_SigninNewAccountNoExistingAccount_From*| user actions should
// not be recorded for them. Note: To avoid bloating the sign-in APIs, the
@@ -496,6 +504,7 @@
case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
case AccessPoint::ACCESS_POINT_UNKNOWN:
case AccessPoint::ACCESS_POINT_FORCE_SIGNIN_WARNING:
+ case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
// These access points do not support personalized sign-in promos, so
// |Signin_SigninNewAccountExistingAccount_From*| user actions should not
// be recorded for them. Note: To avoid bloating the sign-in APIs, the
@@ -951,6 +960,7 @@
case AccessPoint::ACCESS_POINT_SUPERVISED_USER:
case AccessPoint::ACCESS_POINT_USER_MANAGER:
case AccessPoint::ACCESS_POINT_UNKNOWN:
+ case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
NOTREACHED() << "Signin_Impression_From* user actions"
<< " are not recorded for access point "
<< static_cast<int>(access_point);
@@ -1079,6 +1089,7 @@
case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
case AccessPoint::ACCESS_POINT_UNKNOWN:
case AccessPoint::ACCESS_POINT_FORCE_SIGNIN_WARNING:
+ case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
NOTREACHED() << "Signin_Impression{With|WithNo}Account_From* user actions"
<< " are not recorded for access point "
<< static_cast<int>(access_point)
diff --git a/components/signin/core/browser/signin_metrics.h b/components/signin/core/browser/signin_metrics.h
index 19b9dbfa..4529276 100644
--- a/components/signin/core/browser/signin_metrics.h
+++ b/components/signin/core/browser/signin_metrics.h
@@ -153,6 +153,7 @@
ACCESS_POINT_FORCE_SIGNIN_WARNING,
ACCESS_POINT_SAVE_CARD_BUBBLE,
ACCESS_POINT_MANAGE_CARDS_BUBBLE,
+ ACCESS_POINT_MACHINE_LOGON,
ACCESS_POINT_MAX, // This must be last.
};
@@ -185,7 +186,11 @@
REASON_UNLOCK,
REASON_UNKNOWN_REASON, // This should never have been used to get signin URL.
REASON_FORCED_SIGNIN_PRIMARY_ACCOUNT,
- REASON_MAX, // This must be last.
+ REASON_FETCH_LST_ONLY, // Used to simply login and acquire a login scope
+ // token without actually signing into any profiles on
+ // Chrome. This allows the chrome signin page to work
+ // in incognito mode.
+ REASON_MAX, // This must be last.
};
// Enum values used for use with the "Signin.Reauth" histogram.
diff --git a/components/signin/core/browser/signin_metrics_unittest.cc b/components/signin/core/browser/signin_metrics_unittest.cc
index a8939fa..7f7e96f 100644
--- a/components/signin/core/browser/signin_metrics_unittest.cc
+++ b/components/signin/core/browser/signin_metrics_unittest.cc
@@ -106,6 +106,8 @@
return "SaveCardBubble";
case AccessPoint::ACCESS_POINT_MANAGE_CARDS_BUBBLE:
return "ManageCardsBubble";
+ case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
+ return "MachineLogon";
case AccessPoint::ACCESS_POINT_MAX:
NOTREACHED();
return "";
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index eafe22a..d748932 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -17207,6 +17207,14 @@
</description>
</action>
+<action name="Signin_Signin_FromMachineLogon">
+ <owner>rogerta@chromium.org</owner>
+ <owner>tienmai@chromium.org</owner>
+ <description>
+ Record when a user signs in using a Windows machine's logon screen.
+ </description>
+</action>
+
<action name="Signin_Signin_FromManageCardsBubble">
<owner>manasverma@google.com</owner>
<owner>jsaul@chromium.org</owner>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index f11ee7d5..4a70bb4c 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -28382,6 +28382,10 @@
<int value="19" label="LM_SHORTCUT_START_MENU">
Launched from a Start Menu shortcut (Windows).
</int>
+ <int value="20" label="LM_GCPW_LOGON">
+ Launched as a logon stub for the Google Credential Provider for Windows
+ (Windows).
+ </int>
</enum>
<enum name="LaunchType">