ShellUserVerifier: catch DBus errors and report them to the user

Instead of leaving the login or unlock dialogs in an inconsistent state,
catch DBus errors and show an Authentication Error message. The error
details are logged in the session logs.

https://bugzilla.gnome.org/show_bug.cgi?id=683060
This commit is contained in:
Giovanni Campagna 2012-09-06 16:40:13 +02:00 committed by Florian Müllner
parent 5e12e5f42a
commit 10884ef7f5
3 changed files with 57 additions and 25 deletions

View File

@ -649,6 +649,10 @@ const LoginDialog = new Lang.Class({
this._userVerifier.connect('ask-question', Lang.bind(this, this._askQuestion)); this._userVerifier.connect('ask-question', Lang.bind(this, this._askQuestion));
this._userVerifier.connect('show-message', Lang.bind(this, this._showMessage)); this._userVerifier.connect('show-message', Lang.bind(this, this._showMessage));
this._userVerifier.connect('reset', Lang.bind(this, this._onReset)); this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
this._userVerifier.connect('not-supported', Lang.bind(this, function(verifier, error) {
Main.notifyError(_("Configuration problem: Could not connect to GDM"), error.message);
this._onReset();
}));
this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint)); this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint));
this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint)); this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint));

View File

@ -141,34 +141,43 @@ const ShellUserVerifier = new Lang.Class({
})); }));
}, },
_reportInitError: function(where, error) {
logError(error, where);
this._hold.relase();
this.emit('show-message', _("Authentication error"), 'login-dialog-message-warning');
this._verificationFailed(false);
},
_reauthenticationChannelOpened: function(client, result) { _reauthenticationChannelOpened: function(client, result) {
try { try {
this._userVerifier = client.open_reauthentication_channel_finish(result); this._userVerifier = client.open_reauthentication_channel_finish(result);
this._connectSignals(); } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
this._beginVerification(); return;
} catch(e if e.matches(Gio.DBusError, Gio.DBusError.ACCESS_DENIED) &&
this._hold.release(); !this._reauthOnly) {
} catch (e) { // Gdm emits org.freedesktop.DBus.Error.AccessDenied when there is
if (this._reauthOnly) { // no session to reauthenticate. Fall back to performing verification
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) // from this login session
return;
logError(e, 'Failed to open reauthentication channel');
this.emit('verification-failed');
this._hold.release();
return;
}
// If there's no session running, or it otherwise fails, then fall back
// to performing verification from this login session
client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot)); client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot));
return;
} catch(e) {
this._reportInitError('Failed to open reauthentication channel', e);
return;
} }
this._connectSignals();
this._beginVerification();
this._hold.release();
}, },
_userVerifierGot: function(client, result) { _userVerifierGot: function(client, result) {
try { try {
this._userVerifier = client.get_user_verifier_finish(result); this._userVerifier = client.get_user_verifier_finish(result);
} catch(e if e.matches(Gio.IOErrorEnum, Gio.ErrorEnum.CANCELLED)) { } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
return;
} catch(e) {
this._reportInitError('Failed to obtain user verifier', e);
return; return;
} }
@ -199,6 +208,9 @@ const ShellUserVerifier = new Lang.Class({
obj.call_begin_verification_for_user_finish(result); obj.call_begin_verification_for_user_finish(result);
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
return; return;
} catch(e) {
this._reportInitError('Failed to start verification for user', e);
return;
} }
this._hold.release(); this._hold.release();
@ -215,6 +227,9 @@ const ShellUserVerifier = new Lang.Class({
obj.call_begin_verification_for_user_finish(result); obj.call_begin_verification_for_user_finish(result);
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
return; return;
} catch(e) {
this._reportInitError('Failed to start fingerprint verification for user', e);
return;
} }
this._hold.release(); this._hold.release();
@ -228,6 +243,9 @@ const ShellUserVerifier = new Lang.Class({
obj.call_begin_verification_finish(result); obj.call_begin_verification_finish(result);
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
return; return;
} catch(e) {
this._reportInitError('Failed to start verification', e);
return;
} }
this._hold.release(); this._hold.release();
@ -306,23 +324,27 @@ const ShellUserVerifier = new Lang.Class({
this.emit('verification-complete'); this.emit('verification-complete');
}, },
_verificationFailed: function() { _verificationFailed: function(retry) {
// For Not Listed / enterprise logins, immediately reset // For Not Listed / enterprise logins, immediately reset
// the dialog // the dialog
// Otherwise, we allow ALLOWED_FAILURES attempts. After that, we // Otherwise, we allow ALLOWED_FAILURES attempts. After that, we
// go back to the welcome screen. // go back to the welcome screen.
if (!this._userName || let canRetry = retry && this._userName &&
(++this._failCounter) == this._settings.get_int(ALLOWED_FAILURES_KEY)) { this._failCounter < this._settings.get_int(ALLOWED_FAILURES_KEY);
if (canRetry) {
this._failCounter++;
this.clear();
this.begin(this._userName, new Batch.Hold());
} else {
// Allow some time to see the message, then reset everything // Allow some time to see the message, then reset everything
Mainloop.timeout_add(3000, Lang.bind(this, function() { Mainloop.timeout_add(3000, Lang.bind(this, function() {
this.cancel(); this.cancel();
this._onReset(); this._onReset();
})); }));
} else {
this.clear();
this.begin(this._userName, new Batch.Hold());
} }
this.emit('verification-failed'); this.emit('verification-failed');
@ -333,7 +355,7 @@ const ShellUserVerifier = new Lang.Class({
// But if, e.g., fingerprint fails, still give // But if, e.g., fingerprint fails, still give
// password authentication a chance to succeed // password authentication a chance to succeed
if (serviceName == PASSWORD_SERVICE_NAME) { if (serviceName == PASSWORD_SERVICE_NAME) {
this._verificationFailed(); this._verificationFailed(true);
} }
this.emit('hide-login-hint'); this.emit('hide-login-hint');

View File

@ -133,6 +133,12 @@ const UnlockDialog = new Lang.Class({
this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint)); this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint));
this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint)); this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint));
this._userVerifier.connect('not-supported', Lang.bind(this, function(verifier, error) {
Main.notifyError(_("Could not connect to GDM. Screen locking was automatically disabled."), error.message);
this._userVerifier.clear();
this.emit('unlocked');
}));
this._userWidget = new UserWidget(this._user); this._userWidget = new UserWidget(this._user);
this.contentLayout.add_actor(this._userWidget.actor); this.contentLayout.add_actor(this._userWidget.actor);