[gnome-shell] ShellUserVerifier: catch DBus errors and report them to the user



commit 10884ef7f5ba0b5a0ad96130b4e386af813819af
Author: Giovanni Campagna <gcampagna src gnome org>
Date:   Thu Sep 6 16:40:13 2012 +0200

    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

 js/gdm/loginDialog.js |    4 +++
 js/gdm/util.js        |   72 ++++++++++++++++++++++++++++++++-----------------
 js/ui/unlockDialog.js |    6 ++++
 3 files changed, 57 insertions(+), 25 deletions(-)
---
diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js
index 3d7996c..8cb4395 100644
--- a/js/gdm/loginDialog.js
+++ b/js/gdm/loginDialog.js
@@ -649,6 +649,10 @@ const LoginDialog = new Lang.Class({
         this._userVerifier.connect('ask-question', Lang.bind(this, this._askQuestion));
         this._userVerifier.connect('show-message', Lang.bind(this, this._showMessage));
         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('hide-login-hint', Lang.bind(this, this._hideLoginHint));
diff --git a/js/gdm/util.js b/js/gdm/util.js
index 681c0a6..4d4754d 100644
--- a/js/gdm/util.js
+++ b/js/gdm/util.js
@@ -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) {
         try {
             this._userVerifier = client.open_reauthentication_channel_finish(result);
-            this._connectSignals();
-            this._beginVerification();
-
-            this._hold.release();
-        } catch (e) {
-            if (this._reauthOnly) {
-                if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
-                    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
+        } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
+            return;
+        } catch(e if e.matches(Gio.DBusError, Gio.DBusError.ACCESS_DENIED) &&
+                !this._reauthOnly) {
+            // Gdm emits org.freedesktop.DBus.Error.AccessDenied when there is
+            // no session to reauthenticate. Fall back to performing verification
+            // from this login session
             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) {
         try {
             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;
         }
 
@@ -199,6 +208,9 @@ const ShellUserVerifier = new Lang.Class({
                     obj.call_begin_verification_for_user_finish(result);
                 } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
                     return;
+                } catch(e) {
+                    this._reportInitError('Failed to start verification for user', e);
+                    return;
                 }
 
                 this._hold.release();
@@ -215,6 +227,9 @@ const ShellUserVerifier = new Lang.Class({
                         obj.call_begin_verification_for_user_finish(result);
                     } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
                         return;
+                    } catch(e) {
+                        this._reportInitError('Failed to start fingerprint verification for user', e);
+                        return;
                     }
 
                     this._hold.release();
@@ -228,6 +243,9 @@ const ShellUserVerifier = new Lang.Class({
                     obj.call_begin_verification_finish(result);
                 } catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
                     return;
+                } catch(e) {
+                    this._reportInitError('Failed to start verification', e);
+                    return;
                 }
 
                 this._hold.release();
@@ -306,23 +324,27 @@ const ShellUserVerifier = new Lang.Class({
         this.emit('verification-complete');
     },
 
-    _verificationFailed: function() {
+    _verificationFailed: function(retry) {
         // For Not Listed / enterprise logins, immediately reset
         // the dialog
         // Otherwise, we allow ALLOWED_FAILURES attempts. After that, we
         // go back to the welcome screen.
 
-        if (!this._userName ||
-            (++this._failCounter) == this._settings.get_int(ALLOWED_FAILURES_KEY)) {
+        let canRetry = retry && this._userName &&
+            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
             Mainloop.timeout_add(3000, Lang.bind(this, function() {
                 this.cancel();
 
                 this._onReset();
             }));
-        } else {
-            this.clear();
-            this.begin(this._userName, new Batch.Hold());
         }
 
         this.emit('verification-failed');
@@ -333,7 +355,7 @@ const ShellUserVerifier = new Lang.Class({
         // But if, e.g., fingerprint fails, still give
         // password authentication a chance to succeed
         if (serviceName == PASSWORD_SERVICE_NAME) {
-            this._verificationFailed();
+            this._verificationFailed(true);
         }
 
         this.emit('hide-login-hint');
diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js
index 127a924..8701a43 100644
--- a/js/ui/unlockDialog.js
+++ b/js/ui/unlockDialog.js
@@ -133,6 +133,12 @@ const UnlockDialog = new Lang.Class({
         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('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.contentLayout.add_actor(this._userWidget.actor);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]