Commit d26f388a authored by Anastasiia N's avatar Anastasiia N Committed by Commit Bot

Implement getAccounts API

Support |getAccounts| Gaia request - send |accountsListed| message with
list of emails of accounts in session.

Bug: b/123630392
Change-Id: I2e920bf8a1303a17d70d74f0069a6ad9298aa86d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2353348Reviewed-by: default avatarKush Sinha <sinhak@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Commit-Queue: Anastasiia N <anastasiian@chromium.org>
Cr-Commit-Position: refs/heads/master@{#798569}
parent d2cec01c
......@@ -61,6 +61,13 @@ export class EduAccountLoginBrowserProxy {
*/
completeLogin(credentials, eduLoginParams) {}
/**
* Send 'getAccounts' message to the handler. The promise will be resolved
* with the list of emails of accounts in session.
* @return {Promise<Array<string>>}
*/
getAccounts() {}
/** Send 'dialogClose' message to close the login dialog. */
dialogClose() {}
}
......@@ -109,6 +116,11 @@ export class EduAccountLoginBrowserProxyImpl {
chrome.send('completeLogin', [credentials, eduLoginParams]);
}
/** @override */
getAccounts() {
return sendWithPromise('getAccounts');
}
/** @override */
dialogClose() {
chrome.send('dialogClose');
......
......@@ -85,6 +85,8 @@ Polymer({
this.authExtHost_.addEventListener(
'authCompleted', e => this.onAuthCompleted_(
/** @type {!CustomEvent<!AuthCompletedCredentials>} */(e)));
this.authExtHost_.addEventListener(
'getAccounts', () => this.onGetAccounts_());
},
/**
......@@ -129,6 +131,13 @@ Polymer({
this.loading_ = true;
},
/** @private */
onGetAccounts_() {
this.browserProxy_.getAccounts().then(result => {
this.authExtHost_.getAccountsResponse(result);
});
},
/**
* Loads auth extension.
* @param {!AuthParams} data Parameters for auth extension.
......
......@@ -207,6 +207,9 @@ cr.define('cr.login', function() {
'backButton'(msg) {
this.dispatchEvent(new CustomEvent('backButton', {detail: msg.show}));
},
'getAccounts'(msg) {
this.dispatchEvent(new Event('getAccounts'));
},
'showView'(msg) {
this.dispatchEvent(new Event('showView'));
},
......@@ -595,6 +598,14 @@ cr.define('cr.login', function() {
this.isLoaded_ = true;
}
/**
* Called in response to 'getAccounts' event.
* @param {Array<string>} accounts list of emails
*/
getAccountsResponse(accounts) {
this.sendMessageToWebview('accountsListed', accounts);
}
constructInitialFrameUrl_(data) {
if (data.doSamlRedirect) {
let url = this.idpOrigin_ + SAML_REDIRECTION_PATH;
......@@ -860,11 +871,22 @@ cr.define('cr.login', function() {
}
/**
* Invoked to send a HTML5 message to the webview element.
* @param {*} payload Payload of the HTML5 message.
* Invoked to send a HTML5 message with attached data to the webview
* element.
* @param {string} messageType Type of the HTML5 message.
* @param {Object=} messageData Data to be attached to the message.
*/
sendMessageToWebview(payload) {
sendMessageToWebview(messageType, messageData = null) {
const currentUrl = this.webview_.src;
let payload = undefined;
if (messageData) {
payload = {type: messageType, data: messageData};
} else {
// TODO(crbug.com/1116343): Use new message format when it will be
// available in production.
payload = messageType;
}
this.webview_.contentWindow.postMessage(payload, currentUrl);
}
......
......@@ -105,6 +105,8 @@ Polymer({
/** @type {!CustomEvent<!AuthCompletedCredentials>} */ (e)));
this.authExtHost_.addEventListener(
'showIncognito', () => this.onShowIncognito_());
this.authExtHost_.addEventListener(
'getAccounts', () => this.onGetAccounts_());
},
/**
......@@ -156,6 +158,13 @@ Polymer({
this.browserProxy_.showIncognito();
},
/** @private */
onGetAccounts_() {
this.browserProxy_.getAccounts().then(result => {
this.authExtHost_.getAccountsResponse(result);
});
},
/**
* Loads auth extension.
* @param {!AuthParams} data Parameters for auth extension.
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {addSingletonGetter} from 'chrome://resources/js/cr.m.js';
import {addSingletonGetter, sendWithPromise} from 'chrome://resources/js/cr.m.js';
import {AuthCompletedCredentials} from '../gaia_auth_host/authenticator.m.js';
......@@ -46,6 +46,13 @@ export class InlineLoginBrowserProxy {
/** Send 'showIncognito' message to the handler */
showIncognito() {}
/**
* Send 'getAccounts' message to the handler. The promise will be resolved
* with the list of emails of accounts in session.
* @return {Promise<Array<string>>}
*/
getAccounts() {}
/** Send 'dialogClose' message to close the login dialog. */
dialogClose() {}
}
......@@ -87,6 +94,11 @@ export class InlineLoginBrowserProxyImpl {
chrome.send('showIncognito');
}
/** @override */
getAccounts() {
return sendWithPromise('getAccounts');
}
/** @override */
dialogClose() {
chrome.send('dialogClose');
......
......@@ -22,7 +22,6 @@
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/webui/signin/inline_login_dialog_chromeos.h"
#include "chrome/browser/ui/webui/signin/inline_login_handler.h"
#include "chromeos/components/account_manager/account_manager.h"
#include "chromeos/components/account_manager/account_manager_factory.h"
#include "chromeos/constants/chromeos_features.h"
#include "components/signin/public/identity_manager/account_info.h"
......@@ -38,6 +37,12 @@ namespace {
constexpr char kCrosAddAccountFlow[] = "crosAddAccount";
constexpr char kCrosAddAccountEduFlow[] = "crosAddAccountEdu";
std::string AnonymizeAccountEmail(const std::string& email) {
std::string result;
base::Base64Encode(crypto::SHA256HashString(email), &result);
return result + "@example.com";
}
bool GaiaActionButtonsEnabled() {
return base::FeatureList::IsEnabled(chromeos::features::kGaiaActionButtons);
}
......@@ -252,6 +257,10 @@ void InlineLoginHandlerChromeOS::RegisterMessages() {
base::BindRepeating(
&InlineLoginHandlerChromeOS::ShowIncognitoAndCloseDialog,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"getAccounts",
base::BindRepeating(&InlineLoginHandlerChromeOS::GetAccountsInSession,
base::Unretained(this)));
}
void InlineLoginHandlerChromeOS::SetExtraInitParams(
......@@ -347,4 +356,36 @@ void InlineLoginHandlerChromeOS::ShowIncognitoAndCloseDialog(
close_dialog_closure_.Run();
}
void InlineLoginHandlerChromeOS::GetAccountsInSession(
const base::ListValue* args) {
const std::string& callback_id = args->GetList()[0].GetString();
const Profile* profile = Profile::FromWebUI(web_ui());
chromeos::AccountManager* account_manager =
g_browser_process->platform_part()
->GetAccountManagerFactory()
->GetAccountManager(profile->GetPath().value());
account_manager->GetAccounts(
base::BindOnce(&InlineLoginHandlerChromeOS::OnGetAccounts,
weak_factory_.GetWeakPtr(), callback_id));
}
void InlineLoginHandlerChromeOS::OnGetAccounts(
const std::string& callback_id,
const std::vector<AccountManager::Account>& accounts) {
base::ListValue account_emails;
for (const auto& account : accounts) {
if (account.key.account_type ==
account_manager::AccountType::ACCOUNT_TYPE_ACTIVE_DIRECTORY) {
// Don't send Active Directory account email to Gaia.
account_emails.Append(AnonymizeAccountEmail(account.raw_email));
} else {
account_emails.Append(account.raw_email);
}
}
ResolveJavascriptCallback(base::Value(callback_id),
std::move(account_emails));
}
} // namespace chromeos
......@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "chrome/browser/ui/webui/signin/inline_login_handler.h"
#include "chromeos/components/account_manager/account_manager.h"
#include "google_apis/gaia/gaia_auth_consumer.h"
#include "google_apis/gaia/gaia_auth_fetcher.h"
......@@ -36,8 +37,12 @@ class InlineLoginHandlerChromeOS : public InlineLoginHandler {
private:
void ShowIncognitoAndCloseDialog(const base::ListValue* args);
void GetAccountsInSession(const base::ListValue* args);
void OnGetAccounts(const std::string& callback_id,
const std::vector<AccountManager::Account>& accounts);
base::RepeatingClosure close_dialog_closure_;
base::WeakPtrFactory<InlineLoginHandlerChromeOS> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(InlineLoginHandlerChromeOS);
};
......
......@@ -11,7 +11,7 @@ import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
import {NativeEventTarget as EventTarget} from 'chrome://resources/js/cr/event_target.m.js';
import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {TestEduAccountLoginBrowserProxy} from './edu_login_test_util.js';
import {getFakeAccountsList, TestEduAccountLoginBrowserProxy} from './edu_login_test_util.js';
window.edu_login_signin_tests = {};
edu_login_signin_tests.suiteName = 'EduLoginSigninTest';
......@@ -45,6 +45,10 @@ suite(edu_login_signin_tests.suiteName, function() {
this.loadCalls = 0;
/** @type {Number} */
this.resetStatesCalls = 0;
/** @type {number} */
this.getAccountsResponseCalls = 0;
/** @type {Array<string>} */
this.getAccountsResponseResult = null;
}
/**
......@@ -60,6 +64,14 @@ suite(edu_login_signin_tests.suiteName, function() {
resetStates() {
this.resetStatesCalls++;
}
/**
* @param {Array<string>} accounts list of emails.
*/
getAccountsResponse(accounts) {
this.getAccountsResponseCalls++;
this.getAccountsResponseResult = accounts;
}
}
setup(function() {
......@@ -119,6 +131,15 @@ suite(edu_login_signin_tests.suiteName, function() {
assertEquals(fakeCredentials, result[0]);
assertDeepEquals(fakeLoginParams, result[1]);
});
testAuthenticator.dispatchEvent(new Event('getAccounts'));
assertEquals(1, testBrowserProxy.getCallCount('getAccounts'));
testBrowserProxy.whenCalled('getAccounts').then(function() {
assertEquals(1, testAuthenticator.getAccountsResponseCalls);
assertDeepEquals(
getFakeAccountsList(),
testAuthenticator.getAccountsResponseResult);
});
});
test(assert(edu_login_signin_tests.TestNames.GoBackInWebview), function() {
......
......@@ -29,6 +29,11 @@ export function getFakeParentsList() {
];
}
/** @return {!Array<string>} */
export function getFakeAccountsList() {
return ['test@gmail.com', 'test2@gmail.com', 'test3@gmail.com'];
}
/** @implements {EduAccountLoginBrowserProxy} */
export class TestEduAccountLoginBrowserProxy extends TestBrowserProxy {
constructor() {
......@@ -40,6 +45,7 @@ export class TestEduAccountLoginBrowserProxy extends TestBrowserProxy {
'authExtensionReady',
'switchToFullTab',
'completeLogin',
'getAccounts',
'dialogClose',
]);
......@@ -106,6 +112,12 @@ export class TestEduAccountLoginBrowserProxy extends TestBrowserProxy {
this.methodCalled('completeLogin', [credentials, eduLoginParams]);
}
/** @override */
getAccounts() {
this.methodCalled('getAccounts');
return Promise.resolve(getFakeAccountsList());
}
/** @override */
dialogClose() {
this.methodCalled('dialogClose');
......
......@@ -10,8 +10,9 @@ import {isChromeOS} from 'chrome://resources/js/cr.m.js';
import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {assertEquals, assertFalse, assertTrue} from '../chai_assert.js';
import {TestAuthenticator, TestInlineLoginBrowserProxy} from './inline_login_test_util.js';
import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from '../chai_assert.js';
import {getFakeAccountsList, TestAuthenticator, TestInlineLoginBrowserProxy} from './inline_login_test_util.js';
window.inline_login_test = {};
inline_login_test.suiteName = 'InlineLoginTest';
......@@ -97,6 +98,14 @@ suite(inline_login_test.suiteName, () => {
testAuthenticator.dispatchEvent(new Event('showIncognito'));
assertEquals(1, testBrowserProxy.getCallCount('showIncognito'));
testAuthenticator.dispatchEvent(new Event('getAccounts'));
assertEquals(1, testBrowserProxy.getCallCount('getAccounts'));
testBrowserProxy.whenCalled('getAccounts').then(function() {
assertEquals(1, testAuthenticator.getAccountsResponseCalls);
assertDeepEquals(
getFakeAccountsList(), testAuthenticator.getAccountsResponseResult);
});
});
test(assert(inline_login_test.TestNames.BackButton), () => {
......
......@@ -8,6 +8,11 @@ import {NativeEventTarget as EventTarget} from 'chrome://resources/js/cr/event_t
import {TestBrowserProxy} from '../test_browser_proxy.m.js';
/** @return {!Array<string>} */
export function getFakeAccountsList() {
return ['test@gmail.com', 'test2@gmail.com', 'test3@gmail.com'];
}
export class TestAuthenticator extends EventTarget {
constructor() {
super();
......@@ -17,6 +22,10 @@ export class TestAuthenticator extends EventTarget {
this.data = null;
/** @type {number} */
this.loadCalls = 0;
/** @type {number} */
this.getAccountsResponseCalls = 0;
/** @type {Array<string>} */
this.getAccountsResponseResult = null;
}
/**
......@@ -28,6 +37,14 @@ export class TestAuthenticator extends EventTarget {
this.authMode = authMode;
this.data = data;
}
/**
* @param {Array<string>} accounts list of emails.
*/
getAccountsResponse(accounts) {
this.getAccountsResponseCalls++;
this.getAccountsResponseResult = accounts;
}
}
/** @implements {InlineLoginBrowserProxy} */
......@@ -41,6 +58,7 @@ export class TestInlineLoginBrowserProxy extends TestBrowserProxy {
'lstFetchResults',
'metricsHandler:recordAction',
'showIncognito',
'getAccounts',
'dialogClose',
]);
}
......@@ -80,6 +98,12 @@ export class TestInlineLoginBrowserProxy extends TestBrowserProxy {
this.methodCalled('showIncognito');
}
/** @override */
getAccounts() {
this.methodCalled('getAccounts');
return Promise.resolve(getFakeAccountsList());
}
/** @override */
dialogClose() {
this.methodCalled('dialogClose');
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment