'remember password' fixes
authorKevin Wasserman <krwasserman@hotmail.com>
Wed, 25 Sep 2013 21:27:54 +0000 (17:27 -0400)
committerKevin Wasserman <krwasserman@hotmail.com>
Wed, 25 Sep 2013 21:27:54 +0000 (17:27 -0400)
Identities without 'remember password' checked never have their
password stored to disk in any manner.

The password will remain in uncacheable memory until the
identity selector process exits.

User is now prompted to enter a password any time an identity
without a password is about to be sent to a service. The
'add password' dialog now shows the display name, NAI, and
requesting service for the identity.

src/moonshot-add-dialog.vala
src/moonshot-id.vala
src/moonshot-identities-manager.vala
src/moonshot-identity-management-view.vala
src/moonshot-identity-manager-app.vala
src/moonshot-keyring-store.vala
src/moonshot-local-flat-file-store.vala
src/moonshot-password-dialog.vala

index 44ac597..141f788 100644 (file)
@@ -6,6 +6,7 @@ class AddIdentityDialog : Dialog
     private Entry issuer_entry;
     private Entry username_entry;
     private Entry password_entry;
+    private CheckButton remember_checkbutton;
     
     public string display_name {
         get { return displayname_entry.get_text(); }
@@ -23,6 +24,10 @@ class AddIdentityDialog : Dialog
         get { return password_entry.get_text (); }
     }
 
+    public bool store_password {
+        get { return remember_checkbutton.active; }
+    }
+
     public AddIdentityDialog ()
     {
         this.set_title (_("Add ID Card"));
@@ -52,7 +57,7 @@ class AddIdentityDialog : Dialog
         this.password_entry = new Entry ();
         password_entry.set_invisible_char ('*');
         password_entry.set_visibility (false);
-        var remember_checkbutton = new CheckButton.with_label (_("Remember password"));
+        this.remember_checkbutton = new CheckButton.with_label (_("Remember password"));
 
         set_atk_relation (displayname_label, displayname_entry, Atk.RelationType.LABEL_FOR);
         set_atk_relation (issuer_label, issuer_entry, Atk.RelationType.LABEL_FOR);
index 4a38fd6..bc121f5 100644 (file)
@@ -25,7 +25,7 @@ public class IdCard : Object
   private unowned string _password;
   public string password {
     get {
-      return _password;
+      return (_password!=null) ? _password : "";
     }
     set {
       if (_password != null) {
@@ -51,6 +51,8 @@ public class IdCard : Object
 
   public unowned string nai { get {  _nai = username + "@" + issuer; return _nai;}}
 
+  public bool store_password { get; set; default = false; }
+
   public bool IsNoIdentity() 
   {
     return (display_name == NO_IDENTITY);
index e434503..501d065 100644 (file)
@@ -1,8 +1,62 @@
 using Gee;
 
+public class Password {
+#if GNOME_KEYRING
+    private unowned string _password;
+    public string password {
+        get {
+            return _password;
+        }
+        set {
+            if (_password != null) {
+                GnomeKeyring.memory_free((void *)_password);
+                _password = null;
+            }
+            if (value != null)
+                _password = GnomeKeyring.memory_strdup(value); 
+        }
+    }
+#else
+    public string password { get; set; default = null; }
+#endif
+
+    public Password(string in_password) {
+        password = in_password;
+    }
+
+    ~Password() {
+        password = null;
+    }
+}
+
+public class PasswordHashTable : Object {
+    private HashTable<string, Password> password_table;
+
+    private static string ComputeHashKey(IdCard card, IIdentityCardStore store) {
+        return "%s_store_%d".printf( card.display_name, store.get_store_type() );
+    }
+
+    public void CachePassword(IdCard card, IIdentityCardStore store) {
+        password_table.replace(ComputeHashKey(card, store), new Password(card.password));
+    }
+
+    public void RemovePassword(IdCard card, IIdentityCardStore store) {
+        password_table.remove(ComputeHashKey(card, store));
+    }
+    public void RetrievePassword(IdCard card, IIdentityCardStore store) {
+        weak Password password = password_table.lookup(ComputeHashKey(card, store));
+        if (password != null) {
+            card.password = password.password;
+        }
+    }
+    public PasswordHashTable() {
+        password_table = new HashTable<string, Password>(GLib.str_hash, GLib.str_equal);
+    }
+}
+
 public class IdentityManagerModel : Object {
     private const string FILE_NAME = "identities.txt";
-
+    private PasswordHashTable password_table;
     private IIdentityCardStore store;
     public LinkedList<IdCard>  get_card_list() {
          var identities = store.get_card_list();
@@ -18,6 +72,11 @@ public class IdentityManagerModel : Object {
          });
          if (identities.is_empty || !identities[0].IsNoIdentity())
              identities.insert(0, IdCard.NewNoIdentity());
+         foreach (IdCard id_card in identities) {
+             if (!id_card.store_password) {
+                 password_table.RetrievePassword(id_card, store);
+             }
+         }
          return identities;
     }
     public signal void card_list_changed();
@@ -61,17 +120,24 @@ public class IdentityManagerModel : Object {
           card.display_name = candidate;
         }
 
+        if (!card.store_password)
+            password_table.CachePassword(card, store);
         store.add_card(card);
         set_store_type(saved_store_type);
         card_list_changed();
      }
 
      public void update_card(IdCard card) {
+        if (!card.store_password)
+            password_table.CachePassword(card, store);
+        else
+            password_table.RemovePassword(card, store);
         store.update_card(card);
         card_list_changed();
      }
 
      public void remove_card(IdCard card) {
+        password_table.RemovePassword(card, store);
         store.remove_card(card);
         card_list_changed();
      }
@@ -114,6 +180,7 @@ public class IdentityManagerModel : Object {
 
     public IdentityManagerModel(IdentityManagerApp parent_app, IIdentityCardStore.StoreType store_type) {
         parent = parent_app;
+        password_table = new PasswordHashTable();
         set_store_type(store_type);
     }
 }
index 1a89cf2..a6e7955 100644 (file)
@@ -21,6 +21,7 @@ public class IdentityManagerView : Window {
     private Entry password_entry;
     private Label prompting_service;
     private Label no_identity_title;
+    private CheckButton remember_checkbutton;
 
     private ListStore* listmodel;
     private TreeModelFilter filter;
@@ -217,6 +218,7 @@ public class IdentityManagerView : Window {
            this.username_entry.set_text (id_card.username);
            this.password_entry.set_text (id_card.password ?? "");
            this.vbox_right.pack_start(login_vbox, false, true, 0);
+           this.remember_checkbutton.active = id_card.store_password;
        }
        this.vbox_right.pack_start (services_vbox, false, true, 0);
 
@@ -253,6 +255,7 @@ public class IdentityManagerView : Window {
             id_card.issuer = "Issuer";
         id_card.username = dialog.username;
         id_card.password = dialog.password;
+        id_card.store_password = dialog.store_password;
         id_card.services = {};
         id_card.set_data("pixbuf", find_icon ("avatar-default", 48));
 
@@ -423,23 +426,18 @@ public class IdentityManagerView : Window {
         this.request_queue.push_tail (request);
     }
 
-    public void send_identity_cb (IdCard identity)
+    public void check_add_password(IdCard identity, IdentityRequest request, IdentityManagerModel model)
     {
-        return_if_fail (request_queue.length > 0);
-
-       candidates = null;
-        var request = this.request_queue.pop_head ();
-        bool reset_password = false;
-
-        if ((identity.password == null) && !identity.IsNoIdentity())
+        if ((identity.password == "") && !identity.IsNoIdentity())
         {
-            var dialog = new AddPasswordDialog ();
+            var dialog = new AddPasswordDialog (identity, request);
             var result = dialog.run ();
 
             switch (result) {
             case ResponseType.OK:
                 identity.password = dialog.password;
-                reset_password = ! dialog.remember;
+                identity.store_password = dialog.remember;
+                model.update_card(identity);
                 break;
             default:
                 identity = null;
@@ -448,7 +446,15 @@ public class IdentityManagerView : Window {
 
             dialog.destroy ();
         }
+    }
 
+    public void send_identity_cb (IdCard identity)
+    {
+        return_if_fail (request_queue.length > 0);
+
+       candidates = null;
+        var request = this.request_queue.pop_head ();
+        check_add_password(identity, request, identities_manager);
         if (this.request_queue.is_empty())
         {
             candidates = null;
@@ -472,10 +478,6 @@ public class IdentityManagerView : Window {
             parent_app.default_id_card = identity;
 
         request.return_identity (identity);
-
-        if (reset_password)
-            identity.password = null;
-
     }
 
     private void label_make_bold (Label label)
@@ -754,7 +756,7 @@ SUCH DAMAGE.
         this.password_entry = new Entry ();
         password_entry.set_invisible_char ('*');
         password_entry.set_visibility (false);
-        var remember_checkbutton = new CheckButton.with_label (_("Remember password"));
+        this.remember_checkbutton = new CheckButton.with_label (_("Remember password"));
         var login_table = new Table (3, 3, false);
         login_table.set_col_spacings (10);
         login_table.set_row_spacings (10);
index 681d811..d961141 100644 (file)
@@ -209,6 +209,9 @@ public class IdentityManagerApp {
         // callback because we may be being called from a 'yield')
         Idle.add(
             () => {
+                if (view != null) {
+                    view.check_add_password(identity, request, model);
+                }
                 request.return_identity (identity);
 // The following occasionally causes the app to exit without sending the dbus
 // reply, so for now we just don't exit
index 5b63173..78c7af2 100644 (file)
@@ -57,6 +57,7 @@ public class KeyringStore : Object, IIdentityCardStore {
             int i;
             int rules_patterns_index = -1;
             int rules_always_confirm_index = -1;
+            string store_password = null;
             for (i=0; i<entry.attributes.len; i++) {
                 var attribute = entry.attributes.data[i];
                string value = attribute.string_value;
@@ -80,6 +81,8 @@ public class KeyringStore : Object, IIdentityCardStore {
                     id_card.trust_anchor.subject = value;
                 } else if (attribute.name == "Subject-Alt") {
                     id_card.trust_anchor.subject_alt = value;
+                } else if (attribute.name == "StorePassword") {
+                    store_password = value;
                 }
             }
             if ((rules_always_confirm_index != -1) && (rules_patterns_index != -1)) {
@@ -96,7 +99,16 @@ public class KeyringStore : Object, IIdentityCardStore {
                    id_card.rules = rules;
                 }
             }
-            id_card.password = entry.secret;
+
+            if (store_password != null)
+                id_card.store_password = (store_password == "yes");
+            else
+                id_card.store_password = ((entry.secret != null) && (entry.secret != ""));
+
+            if (id_card.store_password)
+                id_card.password = entry.secret;
+            else
+                id_card.password = null;
             id_card_list.add(id_card);
         });
     }
@@ -127,10 +139,12 @@ public class KeyringStore : Object, IIdentityCardStore {
             attributes.append_string("Server-Cert", id_card.trust_anchor.server_cert);
             attributes.append_string("Subject", id_card.trust_anchor.subject);
             attributes.append_string("Subject-Alt", id_card.trust_anchor.subject_alt);
+            attributes.append_string("StorePassword", id_card.store_password ? "yes" : "no");
 
             GnomeKeyring.Result result = GnomeKeyring.item_create_sync(null,
-                item_type, id_card.display_name,
-                attributes, id_card.password, true, out item_id);
+                item_type, id_card.display_name, attributes,
+                id_card.store_password ? id_card.password : "",
+                true, out item_id);
             if (result != GnomeKeyring.Result.OK) {
                 stdout.printf("GnomeKeyring.item_create_sync() failed. result: %d", result);
             }
index 1610efd..baafa72 100644 (file)
@@ -53,7 +53,11 @@ public class LocalFlatFileStore : Object, IIdentityCardStore {
                 id_card.services = key_file.get_string_list (identity, "Services");
                 id_card.display_name = key_file.get_string (identity, "DisplayName");
                 id_card.set_data ("pixbuf", find_icon ("avatar-default", 48));
-                
+                if (key_file.has_key (identity, "StorePassword")) {
+                    id_card.store_password = (key_file.get_string (identity, "StorePassword") == "yes");
+                } else {
+                    id_card.store_password = (id_card.password != null) && (id_card.password != "");
+                }
                 
                 if (key_file.has_key (identity, "Rules-Patterns") &&
                     key_file.has_key (identity, "Rules-AlwaysConfirm")) {
@@ -108,13 +112,17 @@ public class LocalFlatFileStore : Object, IIdentityCardStore {
             key_file.set_string (id_card.display_name, "Issuer", id_card.issuer ?? "");
             key_file.set_string (id_card.display_name, "DisplayName", id_card.display_name ?? "");
             key_file.set_string (id_card.display_name, "Username", id_card.username ?? "");
-            key_file.set_string (id_card.display_name, "Password", id_card.password ?? "");
+            if (id_card.store_password && (id_card.password != null))
+              key_file.set_string (id_card.display_name, "Password", id_card.password);
+            else
+              key_file.set_string (id_card.display_name, "Password", "");
             key_file.set_string_list (id_card.display_name, "Services", id_card.services ?? {});
 
             if (id_card.rules.length > 0) {
               key_file.set_string_list (id_card.display_name, "Rules-Patterns", rules_patterns);
               key_file.set_string_list (id_card.display_name, "Rules-AlwaysConfirm", rules_always_conf);
             }
+            key_file.set_string (id_card.display_name, "StorePassword", id_card.store_password ? "yes" : "no");
             
             // Trust anchor 
             key_file.set_string (id_card.display_name, "CA-Cert", id_card.trust_anchor.ca_cert ?? "");
index 35f239b..060959d 100644 (file)
@@ -13,9 +13,9 @@ class AddPasswordDialog : Dialog
         get { return remember_checkbutton.get_active (); }
     }
 
-    public AddPasswordDialog ()
+    public AddPasswordDialog (IdCard id_card, IdentityRequest request)
     {
-        this.set_title (_("Please enter your password"));
+        this.set_title (_("Please enter password for ") + id_card.display_name);
         this.set_modal (true);
 
         this.add_buttons (_("Send"), ResponseType.OK,
@@ -25,6 +25,16 @@ class AddPasswordDialog : Dialog
         var content_area = this.get_content_area ();
         ((Box) content_area).set_spacing (12);
 
+        var service_label = new Label (_("for use with:"));
+        service_label.set_alignment (1, (float) 0.5);
+        var service_value = new Label (request.service);
+        service_value.set_alignment (0, (float) 0.5);
+
+        var nai_label = new Label (_("Network Access Identifier:"));
+        nai_label.set_alignment (1, (float) 0.5);
+        var nai_value = new Label (id_card.nai);
+        nai_value.set_alignment (0, (float) 0.5);
+
         var password_label = new Label (_("Password:"));
         password_label.set_alignment (1, (float) 0.5);
         this.password_entry = new Entry ();
@@ -35,9 +45,13 @@ class AddPasswordDialog : Dialog
 
         set_atk_relation (password_entry, password_entry, Atk.RelationType.LABEL_FOR);
 
-        var table = new Table (2, 2, false);
+        var table = new Table (4, 2, false);
         table.set_col_spacings (10);
         table.set_row_spacings (10);
+        table.attach_defaults (service_label, 0, 1, 0, 1);
+        table.attach_defaults (service_value, 1, 2, 0, 1);
+        table.attach_defaults (nai_label, 0, 1, 1, 2);
+        table.attach_defaults (nai_value, 1, 2, 1, 2);
         table.attach_defaults (password_label, 0, 1, 2, 3);
         table.attach_defaults (password_entry, 1, 2, 2, 3);
         table.attach_defaults (remember_checkbutton,  1, 2, 3, 4);
@@ -49,7 +63,7 @@ class AddPasswordDialog : Dialog
         ((Container) content_area).add (vbox);
 
         this.set_border_width (6);
-        this.set_resizable (false);
+        //this.set_resizable (false);
         this.show_all ();
     }