Commit de3023f9 authored by Maksim Ivanov's avatar Maksim Ivanov Committed by Commit Bot

Don't ask password for smart card sign-ins

Add plumbing that allows to skip the "manual password entry"
logic when the smart card SAML sign-in is used. Without this,
the user would be asked to type their password at the end of
their HTTPS-client-certificate-based SAML sign-in.

For this, the gaia sign-in screen JS code will ask the C++ handler
whether the user is expected to have a password. In this CL, the
handler is just a stub. It will be replaced later with an actual
smart card sign-in logic, once it's implemented.

No changes in behavior are expected from this CL alone.

BUG=chromium:826417
TEST=none (existing tests)

Cq-Include-Trybots: master.tryserver.chromium.linux:closure_compilation
Change-Id: I44012f02fade8823556bcf1200a122b0791d8292
Reviewed-on: https://chromium-review.googlesource.com/1097406Reviewed-by: default avatarAchuith Bhandarkar <achuith@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Commit-Queue: Maksim Ivanov <emaxx@chromium.org>
Cr-Commit-Position: refs/heads/master@{#567203}
parent b10850d8
......@@ -247,6 +247,8 @@ login.createScreen('GaiaSigninScreen', 'gaia-signin', function() {
this.gaiaAuthHost_.missingGaiaInfoCallback =
this.missingGaiaInfo_.bind(this);
this.gaiaAuthHost_.samlApiUsedCallback = this.samlApiUsed_.bind(this);
this.gaiaAuthHost_.getIsSamlUserPasswordlessCallback =
this.getIsSamlUserPasswordless_.bind(this);
this.gaiaAuthHost_.addEventListener(
'authDomainChange', this.onAuthDomainChange_.bind(this));
this.gaiaAuthHost_.addEventListener(
......@@ -906,6 +908,18 @@ login.createScreen('GaiaSigninScreen', 'gaia-signin', function() {
}
},
/**
* Invoked when the the GAIA host requests whether the specified user is a
* user without a password (neither a manually entered one nor one provided
* via Credentials Passing API).
* @param {string} email
* @param {function(boolean)} callback
* @private
*/
getIsSamlUserPasswordless_: function(email, callback) {
cr.sendWithPromise('getIsSamlUserPasswordless', email).then(callback);
},
/**
* Invoked when the auth host emits 'backButton' event.
* @private
......
......@@ -154,8 +154,22 @@ cr.define('cr.login', function() {
this.insecureContentBlockedCallback = null;
this.samlApiUsedCallback = null;
this.missingGaiaInfoCallback = null;
/**
* Callback allowing to request whether the specified user which
* authenticates via SAML is a user without a password (neither a manually
* entered one nor one provided via Credentials Passing API).
* @type {function(string, function(boolean))}
*/
this.getIsSamlUserPasswordlessCallback = null;
this.needPassword = true;
this.services_ = null;
/**
* Caches the result of |getIsSamlUserPasswordlessCallback| invocation for
* the current user. Null if no result is obtained yet.
* @type {?boolean}
* @private
*/
this.isSamlUserPasswordless_ = null;
this.bindToWebview_(webview);
......@@ -189,6 +203,7 @@ cr.define('cr.login', function() {
this.samlHandler_.reset();
this.videoEnabled = false;
this.services_ = null;
this.isSamlUserPasswordless_ = null;
};
/**
......@@ -532,6 +547,7 @@ cr.define('cr.login', function() {
this.email_ = signinDetails['email'].slice(1, -1);
this.gaiaId_ = signinDetails['obfuscatedid'].slice(1, -1);
this.sessionIndex_ = signinDetails['sessionindex'];
this.isSamlUserPasswordless_ = null;
} else if (headerName == LOCATION_HEADER) {
// If the "choose what to sync" checkbox was clicked, then the continue
// URL will contain a source=3 field.
......@@ -641,6 +657,7 @@ cr.define('cr.login', function() {
this.email_ = msg.email;
if (this.authMode == AuthMode.DESKTOP)
this.password_ = msg.password;
this.isSamlUserPasswordless_ = null;
this.chooseWhatToSync_ = msg.chooseWhatToSync;
// We need to dispatch only first event, before user enters password.
......@@ -716,6 +733,25 @@ cr.define('cr.login', function() {
if (!this.services_)
return;
if (this.isSamlUserPasswordless_ === null &&
this.authFlow == AuthFlow.SAML && this.email_ &&
this.getIsSamlUserPasswordlessCallback) {
// Start a request to obtain the |isSamlUserPasswordless_| value for the
// current user. Once the response arrives, maybeCompleteAuth_() will be
// called again.
this.getIsSamlUserPasswordlessCallback(
this.email_,
this.onGotIsSamlUserPasswordless_.bind(this, this.email_));
return;
}
if (this.isSamlUserPasswordless_ && this.authFlow == AuthFlow.SAML &&
this.email_) {
// No password needed for this user, so complete immediately.
this.onAuthCompleted_();
return;
}
if (this.samlHandler_.samlApiUsed) {
if (this.samlApiUsedCallback) {
this.samlApiUsedCallback();
......@@ -766,6 +802,22 @@ cr.define('cr.login', function() {
this.onAuthCompleted_();
};
/**
* Invoked when the result of |getIsSamlUserPasswordlessCallback| arrives.
* @param {string} email
* @param {boolean} isSamlUserPasswordless
* @private
*/
Authenticator.prototype.onGotIsSamlUserPasswordless_ = function(
email, isSamlUserPasswordless) {
// Compare the request's e-mail with the currently set one, in order to
// ignore responses to old requests.
if (this.email_ && this.email_ == email) {
this.isSamlUserPasswordless_ = isSamlUserPasswordless;
this.maybeCompleteAuth_();
}
};
/**
* Invoked to process authentication completion.
* @private
......@@ -789,6 +841,13 @@ cr.define('cr.login', function() {
}
}
}
if (this.isSamlUserPasswordless_ && this.authFlow == AuthFlow.SAML &&
this.email_) {
// In the passwordless case, the user data will be protected by non
// password based mechanisms. Clear anything that got collected into
// |password_|, if any.
this.password_ = '';
}
this.dispatchEvent(new CustomEvent(
'authCompleted',
// TODO(rsorokin): get rid of the stub values.
......
......@@ -571,6 +571,8 @@ void GaiaScreenHandler::RegisterMessages() {
&GaiaScreenHandler::HandleUpdateGaiaDialogSize);
AddCallback("updateGaiaDialogVisibility",
&GaiaScreenHandler::HandleUpdateGaiaDialogVisibility);
AddCallback("getIsSamlUserPasswordless",
&GaiaScreenHandler::HandleGetIsSamlUserPasswordless);
// Allow UMA metrics collection from JS.
web_ui()->AddMessageHandler(std::make_unique<MetricsHandler>());
......@@ -834,6 +836,17 @@ void GaiaScreenHandler::HandleShowAddUser(const base::ListValue* args) {
OnShowAddUser();
}
void GaiaScreenHandler::HandleGetIsSamlUserPasswordless(
const std::string& callback_id,
const std::string& typed_email) {
AllowJavascript();
// TODO(emaxx,https://crbug.com/826417): Determine the result value based on
// known_user properties if the user already existed, or the
// DeviceSamlLoginAuthenticationType policy if that's a new user.
ResolveJavascriptCallback(base::Value(callback_id),
base::Value(false) /* isSamlUserPasswordless */);
}
void GaiaScreenHandler::OnShowAddUser() {
signin_screen_handler_->is_account_picker_showing_first_time_ = false;
lock_screen_utils::EnforcePolicyInputMethods(std::string());
......
......@@ -131,6 +131,8 @@ class GaiaScreenHandler : public BaseScreenHandler,
void HandleUpdateGaiaDialogSize(int width, int height);
void HandleUpdateGaiaDialogVisibility(bool visible);
void HandleShowAddUser(const base::ListValue* args);
void HandleGetIsSamlUserPasswordless(const std::string& callback_id,
const std::string& typed_email);
void OnShowAddUser();
// Really handles the complete login message.
......
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