0

[CrOS] Login: Support closeView message from Gaia.

Fixed: 1201660
Change-Id: Ic86efb776247b04ff45ca988c4648ad639fd09c8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2853360
Commit-Queue: Roman Sorokin [CET] <rsorokin@chromium.org>
Reviewed-by: Xiyuan Xia <xiyuan@chromium.org>
Reviewed-by: Robert Kaplow <rkaplow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#880912}
This commit is contained in:
Roman Sorokin
2021-05-10 11:01:59 +00:00
committed by Chromium LUCI CQ
parent a4c6c12b37
commit c67acde3f4
7 changed files with 252 additions and 45 deletions
ash/constants
chrome/browser
ash
resources
gaia_auth_host
ui
webui
google_apis/test
tools/metrics/histograms/histograms_xml/chromeos

@ -377,6 +377,11 @@ const base::Feature kFilesZipPack{"FilesZipPack",
const base::Feature kFilesZipUnpack{"FilesZipUnpack",
base::FEATURE_DISABLED_BY_DEFAULT};
// Enables or disables handle of `closeView` message from Gaia. The message is
// supposed to end the flow.
const base::Feature kGaiaCloseViewMessage{"GaiaCloseViewMessage",
base::FEATURE_DISABLED_BY_DEFAULT};
// Enables the Gaia reauth endpoint with deleted user customization page.
const base::Feature kGaiaReauthEndpoint{"GaiaReauthEndpoint",
base::FEATURE_ENABLED_BY_DEFAULT};
@ -846,6 +851,10 @@ bool IsFamilyLinkOnSchoolDeviceEnabled() {
return base::FeatureList::IsEnabled(kFamilyLinkOnSchoolDevice);
}
bool IsGaiaCloseViewMessageEnabled() {
return base::FeatureList::IsEnabled(kGaiaCloseViewMessage);
}
bool IsGaiaReauthEndpointEnabled() {
return base::FeatureList::IsEnabled(kGaiaReauthEndpoint);
}

@ -187,6 +187,8 @@ COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kFsNosymfollow;
COMPONENT_EXPORT(ASH_CONSTANTS)
extern const base::Feature kHandwritingGestureEditing;
COMPONENT_EXPORT(ASH_CONSTANTS)
extern const base::Feature kGaiaCloseViewMessage;
COMPONENT_EXPORT(ASH_CONSTANTS)
extern const base::Feature kGaiaReauthEndpoint;
COMPONENT_EXPORT(ASH_CONSTANTS)
extern const base::Feature kGamepadVibration;
@ -371,6 +373,7 @@ COMPONENT_EXPORT(ASH_CONSTANTS) bool IsDiagnosticsAppEnabled();
COMPONENT_EXPORT(ASH_CONSTANTS) bool IsEcheSWAEnabled();
COMPONENT_EXPORT(ASH_CONSTANTS) bool IsEcheSWAResizingEnabled();
COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFamilyLinkOnSchoolDeviceEnabled();
COMPONENT_EXPORT(ASH_CONSTANTS) bool IsGaiaCloseViewMessageEnabled();
COMPONENT_EXPORT(ASH_CONSTANTS) bool IsGaiaReauthEndpointEnabled();
COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHostnameSettingEnabled();
COMPONENT_EXPORT(ASH_CONSTANTS) bool IsImeSandboxEnabled();

@ -291,7 +291,7 @@ class WebviewLoginTest : public OobeBaseTest {
command_line->AppendSwitch(switches::kOobeSkipPostLogin);
OobeBaseTest::SetUpCommandLine(command_line);
}
base::HistogramTester histogram_tester;
base::HistogramTester histogram_tester_;
protected:
void ExpectIdentifierPage() {
@ -341,6 +341,17 @@ class WebviewLoginTest : public OobeBaseTest {
return web_view_found;
}
void DisableImplicitServices() {
SigninFrameJS().ExecuteAsync(
"gaia.chromeOSLogin.sendImplicitServices = false");
}
void WaitForServicesSet() {
test::OobeJS()
.CreateWaiter("$('gaia-signin').authenticator_.services_")
->Wait();
}
protected:
chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_;
FakeGaiaMixin fake_gaia_{&mixin_host_, embedded_test_server()};
@ -350,8 +361,70 @@ class WebviewLoginTest : public OobeBaseTest {
DISALLOW_COPY_AND_ASSIGN(WebviewLoginTest);
};
/* is kGaiaCloseViewMessage enabled */
/* Does Gaia send the 'closeView' message */
using CloseViewParam = std::tuple<bool, bool>;
class WebviewCloseViewLoginTest
: public WebviewLoginTest,
public ::testing::WithParamInterface<CloseViewParam> {
public:
WebviewCloseViewLoginTest() {
scoped_feature_list_.Reset();
if (IsFeatureEnabled(GetParam())) {
scoped_feature_list_.InitAndEnableFeature(
ash::features::kGaiaCloseViewMessage);
} else {
scoped_feature_list_.InitAndDisableFeature(
ash::features::kGaiaCloseViewMessage);
}
}
static std::string GetName(
const testing::TestParamInfo<CloseViewParam>& param) {
std::string result;
result +=
IsFeatureEnabled(param.param) ? "ClientEnabled" : "ClientDisabled";
result += "_";
result +=
GaiaSendsCloseView(param.param) ? "ServerEnabled" : "ServerDisabled";
return result;
}
protected:
static bool IsFeatureEnabled(const CloseViewParam& param) {
return std::get<0>(param);
}
static bool GaiaSendsCloseView(const CloseViewParam& param) {
return std::get<1>(param);
}
void SendCloseViewOrEmulateTimeout() {
if (GaiaSendsCloseView(GetParam())) {
SigninFrameJS().ExecuteAsync("gaia.chromeOSLogin.sendCloseView()");
return;
}
if (!IsFeatureEnabled(GetParam()))
return;
EmulateGaiaDoneTimeout();
}
void EmulateGaiaDoneTimeout() {
// Wait for user info timer to be set.
test::OobeJS()
.CreateWaiter("$('gaia-signin').authenticator_.gaiaDoneTimer_")
->Wait();
// Emulate timeout fire.
test::OobeJS().ExecuteAsync(
"$('gaia-signin').authenticator_.onGaiaDoneTimeout_()");
}
};
// Basic signin with username and password.
IN_PROC_BROWSER_TEST_F(WebviewLoginTest, NativeTest) {
IN_PROC_BROWSER_TEST_P(WebviewCloseViewLoginTest, NativeTest) {
WaitForGaiaPageLoadAndPropertyUpdate();
ExpectIdentifierPage();
SigninFrameJS().TypeIntoPath(FakeGaiaMixin::kFakeUserEmail,
@ -397,11 +470,27 @@ IN_PROC_BROWSER_TEST_F(WebviewLoginTest, NativeTest) {
FakeGaiaMixin::kPasswordPath);
test::OobeJS().ClickOnPath(kPrimaryButton);
if (IsFeatureEnabled(GetParam()))
WaitForServicesSet();
SendCloseViewOrEmulateTimeout();
test::WaitForPrimaryUserSessionStart();
histogram_tester_.ExpectUniqueSample("ChromeOS.Gaia.Message.Gaia.UserInfo",
true, 1);
if (!IsFeatureEnabled(GetParam())) {
histogram_tester_.ExpectTotalCount("ChromeOS.Gaia.Message.Gaia.CloseView",
0);
return;
}
histogram_tester_.ExpectUniqueSample("ChromeOS.Gaia.Message.Gaia.CloseView",
GaiaSendsCloseView(GetParam()), 1);
}
// Basic signin with username and password.
IN_PROC_BROWSER_TEST_F(WebviewLoginTest, Basic) {
IN_PROC_BROWSER_TEST_P(WebviewCloseViewLoginTest, Basic) {
WaitForGaiaPageLoadAndPropertyUpdate();
ExpectIdentifierPage();
@ -420,6 +509,11 @@ IN_PROC_BROWSER_TEST_F(WebviewLoginTest, Basic) {
FakeGaiaMixin::kPasswordPath);
test::OobeJS().ClickOnPath(kPrimaryButton);
if (IsFeatureEnabled(GetParam()))
WaitForServicesSet();
SendCloseViewOrEmulateTimeout();
// The login view should be destroyed after the browser window opens.
ui_test_utils::WaitForBrowserToOpen();
EXPECT_FALSE(LoginDisplayHost::default_host()->GetWebUILoginView());
@ -431,11 +525,11 @@ IN_PROC_BROWSER_TEST_F(WebviewLoginTest, Basic) {
EXPECT_FALSE(LoginDisplayHost::default_host());
histogram_tester.ExpectUniqueSample("ChromeOS.SAML.APILogin", 0, 1);
histogram_tester.ExpectTotalCount("OOBE.GaiaLoginTime", 1);
histogram_tester_.ExpectUniqueSample("ChromeOS.SAML.APILogin", 0, 1);
histogram_tester_.ExpectTotalCount("OOBE.GaiaLoginTime", 1);
}
IN_PROC_BROWSER_TEST_F(WebviewLoginTest, BackButton) {
IN_PROC_BROWSER_TEST_P(WebviewCloseViewLoginTest, BackButton) {
WaitForGaiaPageLoadAndPropertyUpdate();
// Start with identifer page.
@ -467,6 +561,11 @@ IN_PROC_BROWSER_TEST_F(WebviewLoginTest, BackButton) {
FakeGaiaMixin::kPasswordPath);
test::OobeJS().ClickOnPath(kPrimaryButton);
if (IsFeatureEnabled(GetParam()))
WaitForServicesSet();
SendCloseViewOrEmulateTimeout();
test::WaitForPrimaryUserSessionStart();
}
@ -644,7 +743,7 @@ IN_PROC_BROWSER_TEST_F(ReauthEndpointWebviewLoginOwnerTest, SupervisedUser) {
reauth_user_.account_id.GetUserEmail());
EXPECT_EQ(fake_gaia_.fake_gaia()->is_supervised(), "1");
EXPECT_EQ(fake_gaia_.fake_gaia()->is_device_owner(), "1");
histogram_tester.ExpectTotalCount("OOBE.GaiaLoginTime", 0);
histogram_tester_.ExpectTotalCount("OOBE.GaiaLoginTime", 0);
}
IN_PROC_BROWSER_TEST_F(WebviewLoginTest, StoragePartitionHandling) {
@ -1546,6 +1645,7 @@ class WebviewChildLoginTest : public WebviewLoginTest {
IN_PROC_BROWSER_TEST_F(WebviewChildLoginTest, UserInfoSentBeforeAuthFinished) {
WaitForGaiaPageLoadAndPropertyUpdate();
ExpectIdentifierPage();
DisableImplicitServices();
SigninFrameJS().TypeIntoPath(child_account_id_.GetUserEmail(),
FakeGaiaMixin::kEmailPath);
test::OobeJS().ClickOnPath(kPrimaryButton);
@ -1555,12 +1655,10 @@ IN_PROC_BROWSER_TEST_F(WebviewChildLoginTest, UserInfoSentBeforeAuthFinished) {
FakeGaiaMixin::kPasswordPath);
test::OobeJS().ClickOnPath(kPrimaryButton);
// Wait for services to be set.
test::OobeJS()
.CreateWaiter("$('gaia-signin').authenticator_.services_")
->Wait();
WaitForServicesSet();
// Timer should not be set.
test::OobeJS().ExpectFalse("$('gaia-signin').authenticator_.userInfoTimer_");
test::OobeJS().ExpectFalse("$('gaia-signin').authenticator_.gaiaDoneTimer_");
test::WaitForPrimaryUserSessionStart();
@ -1574,6 +1672,7 @@ IN_PROC_BROWSER_TEST_F(WebviewChildLoginTest, UserInfoSentBeforeAuthFinished) {
IN_PROC_BROWSER_TEST_F(WebviewChildLoginTest, UserInfoSentAfterTimerSet) {
WaitForGaiaPageLoadAndPropertyUpdate();
ExpectIdentifierPage();
DisableImplicitServices();
SigninFrameJS().TypeIntoPath(child_account_id_.GetUserEmail(),
FakeGaiaMixin::kEmailPath);
test::OobeJS().ClickOnPath(kPrimaryButton);
@ -1583,7 +1682,7 @@ IN_PROC_BROWSER_TEST_F(WebviewChildLoginTest, UserInfoSentAfterTimerSet) {
// Wait for user info timer to be set.
test::OobeJS()
.CreateWaiter("$('gaia-signin').authenticator_.userInfoTimer_")
.CreateWaiter("$('gaia-signin').authenticator_.gaiaDoneTimer_")
->Wait();
// Send user info after that.
@ -1597,9 +1696,10 @@ IN_PROC_BROWSER_TEST_F(WebviewChildLoginTest, UserInfoSentAfterTimerSet) {
}
// Verifies flow when user info message is never sent.
IN_PROC_BROWSER_TEST_F(WebviewLoginTest, UserInfoNeverSent) {
IN_PROC_BROWSER_TEST_P(WebviewCloseViewLoginTest, UserInfoNeverSent) {
WaitForGaiaPageLoadAndPropertyUpdate();
ExpectIdentifierPage();
DisableImplicitServices();
SigninFrameJS().TypeIntoPath(FakeGaiaMixin::kFakeUserEmail,
FakeGaiaMixin::kEmailPath);
test::OobeJS().ClickOnPath(kPrimaryButton);
@ -1607,17 +1707,16 @@ IN_PROC_BROWSER_TEST_F(WebviewLoginTest, UserInfoNeverSent) {
FakeGaiaMixin::kPasswordPath);
test::OobeJS().ClickOnPath(kPrimaryButton);
// Wait for user info timer to be set.
test::OobeJS()
.CreateWaiter("$('gaia-signin').authenticator_.userInfoTimer_")
->Wait();
if (GaiaSendsCloseView(GetParam()))
SigninFrameJS().ExecuteAsync("gaia.chromeOSLogin.sendCloseView()");
// Emulate timeout fire.
test::OobeJS().ExecuteAsync(
"$('gaia-signin').authenticator_.onUserInfoTimeout_()");
EmulateGaiaDoneTimeout();
test::WaitForPrimaryUserSessionStart();
histogram_tester_.ExpectUniqueSample("ChromeOS.Gaia.Message.Gaia.UserInfo",
false, 1);
const user_manager::UserManager* const user_manager =
user_manager::UserManager::Get();
EXPECT_FALSE(user_manager->GetActiveUser()->IsChild());
@ -1632,7 +1731,6 @@ IN_PROC_BROWSER_TEST_F(WebviewLoginTest, PasswordMetrics) {
FakeGaiaMixin::kEmailPath);
test::OobeJS().ClickOnPath(kPrimaryButton);
base::HistogramTester histogram_tester;
// This should generate first "Started" event.
SigninFrameJS().ExecuteAsync(
"gaia.chromeOSLogin.attemptLogin('email@email.com', 'password')");
@ -1643,8 +1741,13 @@ IN_PROC_BROWSER_TEST_F(WebviewLoginTest, PasswordMetrics) {
test::OobeJS().ClickOnPath(kPrimaryButton);
test::WaitForPrimaryUserSessionStart();
histogram_tester.ExpectBucketCount("ChromeOS.Gaia.PasswordFlow", 0, 2);
histogram_tester.ExpectBucketCount("ChromeOS.Gaia.PasswordFlow", 1, 1);
histogram_tester_.ExpectBucketCount("ChromeOS.Gaia.PasswordFlow", 0, 2);
histogram_tester_.ExpectBucketCount("ChromeOS.Gaia.PasswordFlow", 1, 1);
}
INSTANTIATE_TEST_SUITE_P(All,
WebviewCloseViewLoginTest,
testing::Combine(testing::Bool(), testing::Bool()),
&WebviewCloseViewLoginTest::GetName);
} // namespace chromeos

@ -93,6 +93,7 @@ cr.define('cr.login', function() {
* isSupervisedUser: boolean,
* isDeviceOwner: boolean,
* ssoProfile: string,
* enableCloseView: boolean,
* }}
*/
/* #export */ let AuthParams;
@ -109,6 +110,12 @@ cr.define('cr.login', function() {
const SAML_REDIRECTION_PATH = 'samlredirect';
const BLANK_PAGE_URL = 'about:blank';
// Metric names for messages we get from Gaia.
const GAIA_MESSAGE_SAML_USER_INFO = 'ChromeOS.Gaia.Message.Saml.UserInfo';
const GAIA_MESSAGE_GAIA_USER_INFO = 'ChromeOS.Gaia.Message.Gaia.UserInfo';
const GAIA_MESSAGE_SAML_CLOSE_VIEW = 'ChromeOS.Gaia.Message.Saml.CloseView';
const GAIA_MESSAGE_GAIA_CLOSE_VIEW = 'ChromeOS.Gaia.Message.Gaia.CloseView';
/**
* The source URL parameter for the constrained signin flow.
*/
@ -206,12 +213,15 @@ cr.define('cr.login', function() {
'isSupervisedUser', // True if the user is supervised user.
'isDeviceOwner', // True if the user is device owner.
'doSamlRedirect', // True if the authentication is done via external IdP.
'enableCloseView', // True if authenticator should wait for the closeView
// message from Gaia.
];
// Timeout in ms to wait for the user info message. The message is used to
// extract user services and to define whether or not the account is a child
// one.
const USER_INFO_WAIT_TIMEOUT_MS = 5 * 1000;
// Timeout in ms to wait for the message from Gaia indicating end of the flow.
// Could be userInfo (The message is used to extract user services and to
// define whether or not the account is a child one) or closeView (specific
// message to indicate the end of the flow).
const GAIA_DONE_WAIT_TIMEOUT_MS = 5 * 1000;
/**
* Extract domain name from an URL.
@ -267,6 +277,12 @@ cr.define('cr.login', function() {
},
'userInfo'(msg) {
this.services_ = msg.services;
if (!this.authCompletedFired_) {
const metric = this.authFlow == AuthFlow.SAML ?
GAIA_MESSAGE_SAML_USER_INFO :
GAIA_MESSAGE_GAIA_USER_INFO;
chrome.send('metricsHandler:recordBooleanHistogram', [metric, true]);
}
if (this.email_ && this.gaiaId_ && this.sessionIndex_) {
this.maybeCompleteAuth_();
}
@ -321,6 +337,27 @@ cr.define('cr.login', function() {
return;
}
this.syncTrustedVaultKeys_ = msg.value;
},
'closeView'(msg) {
if (!this.enableCloseView_) {
return;
}
if (!this.services_) {
console.error('Authenticator: UserInfo should come before closeView');
}
if (!this.authCompletedFired_) {
const metric = this.authFlow == AuthFlow.SAML ?
GAIA_MESSAGE_SAML_CLOSE_VIEW :
GAIA_MESSAGE_GAIA_CLOSE_VIEW;
chrome.send('metricsHandler:recordBooleanHistogram', [metric, true]);
}
this.closeViewReceived_ = true;
if (this.email_ && this.gaiaId_ && this.sessionIndex_) {
this.maybeCompleteAuth_();
}
}
};
@ -377,6 +414,7 @@ cr.define('cr.login', function() {
webview;
assert(this.webview_);
this.enableGaiaActionButtons_ = false;
this.enableCloseView_ = false;
this.webviewEventManager_ = WebviewEventManager.create();
this.clientId_ = null;
@ -399,7 +437,7 @@ cr.define('cr.login', function() {
this.needPassword = true;
this.enableSyncTrustedVaultKeys_ = false;
this.services_ = null;
this.userInfoTimer_ = null;
this.gaiaDoneTimer_ = null;
/**
* Caches the result of |getIsSamlUserPasswordlessCallback| invocation for
* the current user. Null if no result is obtained yet.
@ -412,6 +450,7 @@ cr.define('cr.login', function() {
this.samlAclUrl_ = null;
/** @private {?SyncTrustedVaultKeys} */
this.syncTrustedVaultKeys_ = null;
this.closeViewReceived_ = false;
window.addEventListener(
'message', this.onMessageFromWebview_.bind(this), false);
@ -449,9 +488,10 @@ cr.define('cr.login', function() {
this.samlHandler_.reset();
this.videoEnabled = false;
this.services_ = null;
this.userInfoTimer_ = null;
this.gaiaDoneTimer_ = null;
this.isSamlUserPasswordless_ = null;
this.syncTrustedVaultKeys_ = null;
this.closeViewReceived_ = false;
}
/**
@ -617,6 +657,7 @@ cr.define('cr.login', function() {
this.dontResizeNonEmbeddedPages = data.dontResizeNonEmbeddedPages;
this.enableGaiaActionButtons_ = data.enableGaiaActionButtons;
this.enableSyncTrustedVaultKeys_ = !!data.enableSyncTrustedVaultKeys;
this.enableCloseView_ = !!data.enableCloseView;
this.initialFrameUrl_ = this.constructInitialFrameUrl_(data);
this.reloadUrl_ = data.frameUrl || this.initialFrameUrl_;
@ -1013,23 +1054,26 @@ cr.define('cr.login', function() {
}
// Could be set either by `userInfo` message or by the
// `onUserInfoTimeout_`.
// `onGaiaDoneTimeout_`.
const userInfoAvailable = !!this.services_;
if (userInfoAvailable && this.userInfoTimer_) {
window.clearTimeout(this.userInfoTimer_);
this.userInfoTimer_ = null;
const gaiaDone = userInfoAvailable &&
(!this.enableCloseView_ || this.closeViewReceived_);
if (gaiaDone && this.gaiaDoneTimer_) {
window.clearTimeout(this.gaiaDoneTimer_);
this.gaiaDoneTimer_ = null;
}
if (this.userInfoTimer_) {
// Early out if `userInfoTimer_` is running.
if (this.gaiaDoneTimer_) {
// Early out if `gaiaDoneTimer_` is running.
return;
}
if (!userInfoAvailable) {
// Start `userInfoTimer_` if user info is not available.
this.userInfoTimer_ = window.setTimeout(
this.onUserInfoTimeout_.bind(this), USER_INFO_WAIT_TIMEOUT_MS);
if (!gaiaDone) {
// Start `gaiaDoneTimer_` if user info is not available.
this.gaiaDoneTimer_ = window.setTimeout(
this.onGaiaDoneTimeout_.bind(this), GAIA_DONE_WAIT_TIMEOUT_MS);
return;
}
@ -1387,11 +1431,27 @@ cr.define('cr.login', function() {
* Callback for the user info message waiting timeout.
* @private
*/
onUserInfoTimeout_() {
console.warn('User info timeout: Forcing empty services.');
assert(!this.services_);
this.services_ = [];
this.userInfoTimer_ = null;
onGaiaDoneTimeout_() {
if (!this.services_) {
console.error('Gaia done timeout: Forcing empty services.');
this.services_ = [];
const metric = this.authFlow == AuthFlow.SAML ?
GAIA_MESSAGE_SAML_USER_INFO :
GAIA_MESSAGE_GAIA_USER_INFO;
chrome.send('metricsHandler:recordBooleanHistogram', [metric, false]);
}
if (this.enableCloseView_ && !this.closeViewReceived_) {
console.error('Gaia done timeout: closeView was not called.');
this.closeViewReceived_ = true;
const metric = this.authFlow == AuthFlow.SAML ?
GAIA_MESSAGE_SAML_CLOSE_VIEW :
GAIA_MESSAGE_GAIA_CLOSE_VIEW;
chrome.send('metricsHandler:recordBooleanHistogram', [metric, false]);
}
this.gaiaDoneTimer_ = null;
this.maybeCompleteAuth_();
}
}

@ -509,6 +509,8 @@ void GaiaScreenHandler::LoadGaiaWithPartitionAndVersionAndConsent(
login::ExtractSamlPasswordAttributesEnabled());
params.SetBoolean("enableSyncTrustedVaultKeys",
IsSyncTrustedVaultKeysEnabled());
params.SetBoolean("enableCloseView",
ash::features::IsGaiaCloseViewMessageEnabled());
if (public_saml_url_fetcher_) {
params.SetBoolean("startsOnSamlPage", true);

@ -9,6 +9,7 @@ gaia.chromeOSLogin.parent_webview_oob_url_ = 'chrome://oobe';
gaia.chromeOSLogin.parent_webview_ = undefined;
gaia.chromeOSLogin.parent_webview_url_ = undefined;
gaia.chromeOSLogin.initialized_ = false;
gaia.chromeOSLogin.sendImplicitServices = true;
const urlParams = new URLSearchParams(window.location.search);
const syncTrustedVaultKeysRequestedByClient = !!urlParams.get('szkr');
@ -77,6 +78,14 @@ gaia.chromeOSLogin.sendUserInfo = function(services) {
gaia.chromeOSLogin.parent_webview_url_);
};
gaia.chromeOSLogin.sendCloseView = function() {
msg = {
'method': 'closeView',
};
gaia.chromeOSLogin.parent_webview_.postMessage(msg,
gaia.chromeOSLogin.parent_webview_url_);
};
gaia.chromeOSLogin.backButton = function(show) {
var msg = {
'method': 'backButton',
@ -130,6 +139,8 @@ function goNext() {
services = [];
} else {
console.warn("Services are not set for testing.");
if (gaia.chromeOSLogin.sendImplicitServices)
services = []
}
request = new XMLHttpRequest();

@ -579,6 +579,25 @@ incoming reviews. Googlers can read more about this at go/gwsq-gerrit.
</summary>
</histogram>
<histogram name="ChromeOS.Gaia.Message.{GaiaAuthFlow}.{MessageName}"
enum="BooleanReceived" expires_after="2022-01-01">
<owner>rsorokin@chromium.org</owner>
<owner>cros-oac@google.com</owner>
<summary>
Records whether or not {MessageName} was received during the {GaiaAuthFlow}
authentication on the login screen. Recorded on the successful online
authentication only.
</summary>
<token key="GaiaAuthFlow">
<variant name="Gaia"/>
<variant name="Saml"/>
</token>
<token key="MessageName">
<variant name="CloseView"/>
<variant name="UserInfo"/>
</token>
</histogram>
<histogram name="ChromeOS.Gaia.PasswordFlow" enum="BooleanStartedCompleted"
expires_after="2022-01-01">
<owner>rsorokin@chromium.org</owner>