[gnome-boxes] unattended-setup-box: Don't cache passwords in plain text
- From: Debarshi Ray <debarshir src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-boxes] unattended-setup-box: Don't cache passwords in plain text
- Date: Mon, 30 Jan 2017 15:11:34 +0000 (UTC)
commit ac552985647ebb6d7ee924cd77f0b93df44b4ff0
Author: Debarshi Ray <debarshir gnome org>
Date: Tue Jan 24 17:51:44 2017 +0100
unattended-setup-box: Don't cache passwords in plain text
The user password specified during an express installation is cached
in plain text in ~/.config/gnome-boxes/unattended/setup-data.conf.
Instead, we should use the keyring - it's meant for this. As long as
the host user account has a password, the keyring will be encrypted
and protected in case the disk is stolen.
We store the password as a serialized GVariant dictionary because it
is more extensible than a simple string. In future we might want to
store multiple secrets for a particular media (eg., registration
passwords, product keys, etc.), and those can be accommodated by
specifying a different key in the dictionary.
Fallout from ae21e562515ab60d3279f182313e9a6c7be53abd
https://bugzilla.gnome.org/show_bug.cgi?id=777788
data/ui/unattended-setup-box.ui | 1 +
src/unattended-setup-box.vala | 84 +++++++++++++++++++++++++++++++++++++-
2 files changed, 82 insertions(+), 3 deletions(-)
---
diff --git a/data/ui/unattended-setup-box.ui b/data/ui/unattended-setup-box.ui
index 3f12160..3d11722 100644
--- a/data/ui/unattended-setup-box.ui
+++ b/data/ui/unattended-setup-box.ui
@@ -189,6 +189,7 @@
<property name="text"></property>
<property name="visible">True</property>
<property name="visibility">False</property>
+ <signal name="changed" handler="on_password_entry_changed"/>
<signal name="focus-out-event" handler="on_password_entry_focus_out"/>
<signal name="activate" handler="on_password_entry_activated"/>
</object>
diff --git a/src/unattended-setup-box.vala b/src/unattended-setup-box.vala
index b5d6967..61d70a8 100644
--- a/src/unattended-setup-box.vala
+++ b/src/unattended-setup-box.vala
@@ -97,7 +97,12 @@ private class Boxes.UnattendedSetupBox : Gtk.Box {
private string? product_key_format;
private string media_path;
+ private Cancellable cancellable = new Cancellable ();
private GLib.KeyFile keyfile;
+ private Secret.Schema secret_password_schema
+ = new Secret.Schema ("org.gnome.Boxes",
+ Secret.SchemaFlags.NONE,
+ "gnome-boxes-media-path", Secret.SchemaAttributeType.STRING);
public UnattendedSetupBox (InstallerMedia media, string? product_key_format, bool needs_internet) {
this.product_key_format = product_key_format;
@@ -114,9 +119,45 @@ private class Boxes.UnattendedSetupBox : Gtk.Box {
set_entry_text_from_key (username_entry, USERNAME_KEY, Environment.get_user_name ());
set_entry_text_from_key (password_entry, PASSWORD_KEY);
- if (password != "")
- password_notebook.next_page ();
set_entry_text_from_key (product_key_entry, PRODUCTKEY_KEY);
+
+ if (password != "") {
+ password_notebook.next_page ();
+ } else {
+ Secret.password_lookup.begin (secret_password_schema, cancellable, (obj, res) => {
+ try {
+ var credentials_str = Secret.password_lookup.end (res);
+ if (credentials_str == null || credentials_str == "")
+ return;
+
+ try {
+ var credentials_variant = GLib.Variant.parse (null, credentials_str, null, null);
+ string password_str;
+ if (!credentials_variant.lookup ("password", "s", out password_str))
+ throw new Boxes.Error.INVALID ("couldn't unpack a string for the 'password'
key");
+
+ if (password_str != null && password_str != "") {
+ password_entry.text = password_str;
+ password_notebook.next_page ();
+ }
+ } catch (GLib.Error error) {
+ warning ("Failed to parse password from the keyring: %s", error.message);
+ }
+ } catch (GLib.IOError.CANCELLED error) {
+ return;
+ } catch (GLib.Error error) {
+ warning ("Failed to lookup password for '%s' from the keyring: %s",
+ media_path,
+ error.message);
+ }
+ }, "gnome-boxes-media-path", media_path);
+ }
+
+ try {
+ keyfile.remove_key (media_path, PASSWORD_KEY);
+ } catch (GLib.Error error) {
+ debug ("Failed to remove key '%s' under '%s': %s", PASSWORD_KEY, media_path, error.message);
+ }
} catch (GLib.Error error) {
debug ("%s either doesn't already exist or we failed to load it: %s", KEY_FILE, error.message);
}
@@ -135,6 +176,15 @@ private class Boxes.UnattendedSetupBox : Gtk.Box {
express_toggle.bind_property ("active", child, "sensitive", BindingFlags.SYNC_CREATE);
}
+ public override void dispose () {
+ if (cancellable != null) {
+ cancellable.cancel ();
+ cancellable = null;
+ }
+
+ base.dispose ();
+ }
+
public void clean_up () {
NetworkMonitor.get_default ().network_changed.disconnect (update_express_toggle);
}
@@ -142,7 +192,6 @@ private class Boxes.UnattendedSetupBox : Gtk.Box {
public void save_settings () {
keyfile.set_boolean (media_path, EXPRESS_KEY, express_install);
keyfile.set_string (media_path, USERNAME_KEY, username);
- keyfile.set_string (media_path, PASSWORD_KEY, password);
keyfile.set_string (media_path, PRODUCTKEY_KEY, product_key);
var filename = get_user_unattended (KEY_FILE);
@@ -151,6 +200,29 @@ private class Boxes.UnattendedSetupBox : Gtk.Box {
} catch (GLib.Error error) {
debug ("Error saving settings for '%s': %s", media_path, error.message);
}
+
+ if (password != null && password != "") {
+ var variant_builder = new GLib.VariantBuilder (GLib.VariantType.VARDICT);
+ var password_variant = new GLib.Variant ("s", password);
+ variant_builder.add ("{sv}", "password", password_variant);
+
+ var credentials_variant = variant_builder.end ();
+ var credentials_str = credentials_variant.print (true);
+
+ var label = _("GNOME Boxes credentials for '%s'").printf (media_path);
+ Secret.password_store.begin (secret_password_schema,
+ Secret.COLLECTION_DEFAULT,
+ label,
+ credentials_str,
+ null,
+ (obj, res) => {
+ try {
+ Secret.password_store.end (res);
+ } catch (GLib.Error error) {
+ warning ("Failed to store password for '%s' in the keyring: %s", media_path,
error.message);
+ }
+ }, "gnome-boxes-media-path", media_path);
+ }
}
private void setup_express_toggle (bool live, bool needs_internet) {
@@ -212,6 +284,12 @@ private class Boxes.UnattendedSetupBox : Gtk.Box {
}
[GtkCallback]
+ private void on_password_entry_changed () {
+ cancellable.cancel ();
+ cancellable = new Cancellable ();
+ }
+
+ [GtkCallback]
private bool on_password_entry_focus_out () {
if (password_entry.text_length == 0)
password_notebook.prev_page ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]