[PATCH f19-branch] Network spoke: add secret agent (static wep and wpa)

Vratislav Podzimek vpodzime at redhat.com
Tue Jun 4 12:26:33 UTC 2013


On Tue, 2013-06-04 at 11:47 +0200, Radek Vykydal wrote:
> Static WEP and WPA works, WPA Enterprise will come later.
> 
> I'd like to have it in F19.
> 
> http://rvykydal.fedorapeople.org/secret_agent_wpa.png
> 
> ---
>  pyanaconda/ui/gui/spokes/network.glade | 135 +++++++++++++++++++++
>  pyanaconda/ui/gui/spokes/network.py    | 208 ++++++++++++++++++++++++++++++---
>  2 files changed, 326 insertions(+), 17 deletions(-)
> 
> diff --git a/pyanaconda/ui/gui/spokes/network.glade b/pyanaconda/ui/gui/spokes/network.glade
> index fec6a6a..9d1b742 100644
> --- a/pyanaconda/ui/gui/spokes/network.glade
> +++ b/pyanaconda/ui/gui/spokes/network.glade
> @@ -2493,4 +2493,139 @@ updates available for you.</property>
>        </object>
>      </child>
>    </object>
> +  <object class="GtkDialog" id="secret_agent_dialog">
> +    <property name="can_focus">False</property>
> +    <property name="border_width">5</property>
> +    <property name="title" translatable="yes">Authentication</property>
> +    <property name="type_hint">dialog</property>
> +    <property name="decorated">False</property>
> +    <child internal-child="vbox">
> +      <object class="GtkBox" id="dialog_box">
> +        <property name="can_focus">False</property>
> +        <property name="orientation">vertical</property>
> +        <property name="spacing">5</property>
> +        <child internal-child="action_area">
> +          <object class="GtkButtonBox" id="dialog-action_area2">
> +            <property name="can_focus">False</property>
> +            <property name="layout_style">end</property>
> +            <child>
> +              <object class="GtkButton" id="button1">
> +                <property name="label">gtk-cancel</property>
> +                <property name="visible">True</property>
> +                <property name="can_focus">True</property>
> +                <property name="receives_default">True</property>
> +                <property name="use_stock">True</property>
> +                <property name="image_position">right</property>
> +              </object>
> +              <packing>
> +                <property name="expand">False</property>
> +                <property name="fill">True</property>
> +                <property name="position">0</property>
> +              </packing>
> +            </child>
> +            <child>
> +              <object class="GtkButton" id="connect_button">
> +                <property name="label">gtk-connect</property>
> +                <property name="visible">True</property>
> +                <property name="can_focus">True</property>
> +                <property name="receives_default">True</property>
> +                <property name="use_stock">True</property>
> +              </object>
> +              <packing>
> +                <property name="expand">False</property>
> +                <property name="fill">True</property>
> +                <property name="position">1</property>
> +              </packing>
> +            </child>
> +          </object>
> +          <packing>
> +            <property name="expand">False</property>
> +            <property name="fill">True</property>
> +            <property name="pack_type">end</property>
> +            <property name="position">0</property>
> +          </packing>
> +        </child>
> +        <child>
> +          <object class="GtkBox" id="box2">
> +            <property name="visible">True</property>
> +            <property name="can_focus">False</property>
> +            <property name="margin_left">6</property>
> +            <property name="margin_right">6</property>
> +            <property name="margin_top">6</property>
> +            <property name="margin_bottom">6</property>
> +            <child>
> +              <object class="GtkImage" id="image_password_dialog">
> +                <property name="visible">True</property>
> +                <property name="can_focus">False</property>
> +                <property name="valign">start</property>
> +                <property name="hexpand">True</property>
> +                <property name="xpad">15</property>
> +                <property name="stock">gtk-missing-image</property>
> +              </object>
> +              <packing>
> +                <property name="expand">False</property>
> +                <property name="fill">True</property>
> +                <property name="position">0</property>
> +              </packing>
> +            </child>
> +            <child>
> +              <object class="GtkBox" id="password_box">
> +                <property name="visible">True</property>
> +                <property name="can_focus">False</property>
> +                <property name="orientation">vertical</property>
> +                <child>
> +                  <object class="GtkLabel" id="label_title">
> +                    <property name="visible">True</property>
> +                    <property name="can_focus">False</property>
> +                    <property name="halign">start</property>
> +                    <property name="margin_bottom">6</property>
> +                    <property name="hexpand">True</property>
> +                    <property name="label" translatable="yes">&lt;b&gt;Authentication required by wireless network&lt;/b&gt;</property>
> +                    <property name="use_markup">True</property>
> +                  </object>
> +                  <packing>
> +                    <property name="expand">False</property>
> +                    <property name="fill">True</property>
> +                    <property name="padding">2</property>
> +                    <property name="position">0</property>
> +                  </packing>
> +                </child>
> +                <child>
> +                  <object class="GtkLabel" id="label_message">
> +                    <property name="visible">True</property>
> +                    <property name="can_focus">False</property>
> +                    <property name="halign">start</property>
> +                    <property name="xalign">0</property>
> +                    <property name="yalign">0</property>
> +                    <property name="label" translatable="yes">Passwords or encryption keys are required to access
> +the wireless network</property>
> +                  </object>
> +                  <packing>
> +                    <property name="expand">False</property>
> +                    <property name="fill">True</property>
> +                    <property name="padding">3</property>
> +                    <property name="position">1</property>
> +                  </packing>
> +                </child>
> +              </object>
> +              <packing>
> +                <property name="expand">False</property>
> +                <property name="fill">True</property>
> +                <property name="position">1</property>
> +              </packing>
> +            </child>
> +          </object>
> +          <packing>
> +            <property name="expand">False</property>
> +            <property name="fill">True</property>
> +            <property name="position">1</property>
> +          </packing>
> +        </child>
> +      </object>
> +    </child>
> +    <action-widgets>
> +      <action-widget response="0">button1</action-widget>
> +      <action-widget response="1">connect_button</action-widget>
> +    </action-widgets>
> +  </object>
>  </interface>
> diff --git a/pyanaconda/ui/gui/spokes/network.py b/pyanaconda/ui/gui/spokes/network.py
> index 432fc09..8e78823 100644
> --- a/pyanaconda/ui/gui/spokes/network.py
> +++ b/pyanaconda/ui/gui/spokes/network.py
> @@ -24,8 +24,6 @@
>  # - move callback connection to initialize?
>  # - Automatically reconnecting wifi after failure
>  #   https://bugzilla.redhat.com/show_bug.cgi?id=712778#c1
> -# - secrets agent - use nm_applet?
> -#   see we_dont_have_nm_applet_as_secrets_agent
>  # - callback on NM_CLIENT_ACTIVE_CONNECTIONS
>  # - support connection to hidden network (ap-other)
>  # - NMClient.CLIENT_WIRELESS_ENABLED callback (hw switch?) - test
> @@ -41,17 +39,19 @@ from pyanaconda.ui.gui import GUIObject
>  from pyanaconda.ui.gui.spokes import NormalSpoke, StandaloneSpoke
>  from pyanaconda.ui.gui.categories.software import SoftwareCategory
>  from pyanaconda.ui.gui.hubs.summary import SummaryHub
> -from pyanaconda.ui.gui.utils import gtk_call_once
> +from pyanaconda.ui.gui.utils import gtk_call_once, enlightbox
>  
>  from pyanaconda import network
>  from pyanaconda.nm import nm_activated_devices, nm_device_setting_value
>  
>  from gi.repository import GLib, GObject, Pango, Gio, NetworkManager, NMClient
>  import dbus
> +import dbus.service
>  import socket
>  import subprocess
>  import struct
>  import time
> +import string
>  from dbus.mainloop.glib import DBusGMainLoop
>  dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
>  
> @@ -69,6 +69,11 @@ NM_802_11_AP_FLAGS_PRIVACY = 0x1
>  NM_802_11_AP_SEC_NONE = 0x0
>  NM_802_11_AP_SEC_KEY_MGMT_802_1X = 0x200
>  DBUS_PROPS_IFACE = "org.freedesktop.DBus.Properties"
> +SECRET_AGENT_IFACE = 'org.freedesktop.NetworkManager.SecretAgent'
> +AGENT_MANAGER_IFACE = 'org.freedesktop.NetworkManager.AgentManager'
> +AGENT_MANAGER_PATH = "/org/freedesktop/NetworkManager/AgentManager"
> +
> +
>  
>  def getNMObjProperty(object, nm_iface_suffix, property):
>      props_iface = dbus.Interface(object, DBUS_PROPS_IFACE)
> @@ -118,10 +123,6 @@ configuration_of_disconnected_devices_allowed = True
>  # for installer
>  # https://bugzilla.redhat.com/show_bug.cgi?id=704119
>  
> -we_dont_have_nm_applet_as_secrets_agent = True
> -# so we have to disconnect from former ap before trying
> -# to connect to new one bound to fail due to no secrets
> -
>  __all__ = ["NetworkSpoke", "NetworkStandaloneSpoke"]
>  
>  class CellRendererSignal(Gtk.CellRendererPixbuf):
> @@ -404,12 +405,6 @@ class NetworkControlBox(object):
>  
>          log.info("network: access point changed: %s" % ssid_target)
>  
> -        if we_dont_have_nm_applet_as_secrets_agent:
> -            if self.find_active_connection_for_device(device):
> -                # TODO we should pass callback and block until really disconnected?
> -                # or is wireless reconnection stuff solved in NM? TEST!
> -                device.disconnect(None, None)
> -
>          con = self.find_connection_for_device(device, ssid_target)
>          if con:
>              self.client.activate_connection(con, device,
> @@ -962,13 +957,10 @@ class NetworkControlBox(object):
>          for ap in access_points:
>              ssid = ap.get_ssid()
>              if ssid in strongest_aps:
> -                #print "DBG: found %s duplicate" % ssid
>                  if ap.get_strength() > strongest_aps[ssid].get_strength():
>                      strongest_aps[ssid] = ap
> -                    #print "DBG: ...stronger"
>              else:
>                  strongest_aps[ssid] = ap
> -                #print "DBG: adding %s ap" % ssid
>  
>          return strongest_aps.values()
>  
> @@ -1077,6 +1069,186 @@ class NetworkControlBox(object):
>      def hostname(self, value):
>          self.entry_hostname.set_text(value)
>  
> +
> +class SecretAgentDialog(GUIObject):
> +    builderObjects = ["secret_agent_dialog"]
> +    mainWidgetName = "secret_agent_dialog"
> +    uiFile = "spokes/network.glade"
> +
> +    def __init__(self, *args, **kwargs):
> +        self._content = kwargs.pop('content', {})
> +        GUIObject.__init__(self, *args, **kwargs)
> +        img = self.builder.get_object("image_password_dialog")
> +        img.set_from_icon_name("dialog-password-symbolic", Gtk.IconSize.DIALOG)
> +        self.builder.get_object("label_message").set_text(self._content['message'])
> +        self.builder.get_object("label_title").set_use_markup(True)
> +        self.builder.get_object("label_title").set_markup("<b>%s</b>" % self._content['title'])
> +        self._connect_button = self.builder.get_object("connect_button")
> +
> +    def initialize(self):
> +        self._entries = {}
> +        grid = Gtk.Grid()
> +        grid.set_row_spacing(6)
> +        grid.set_column_spacing(6)
> +
> +        for row, secret in enumerate(self._content['secrets']):
> +            label = Gtk.Label(secret['label'])
> +            label.set_halign(Gtk.Align.START)
> +            entry = Gtk.Entry()
> +            entry.set_visibility(False)
> +            entry.set_hexpand(True)
> +            self._validate(entry, secret)
> +            entry.connect("changed", self._validate, secret)
> +            entry.connect("activate", self._password_entered_cb)
> +            self._entries[secret['key']] = entry
> +            label.set_use_underline(True)
> +            label.set_mnemonic_widget(entry)
> +            grid.attach(label, 0, row, 1, 1)
> +            grid.attach(entry, 1, row, 1, 1)
> +
> +        self.builder.get_object("password_box").add(grid)
> +
> +    def run(self):
> +        self.initialize()
> +        self.window.show_all()
> +        rc = self.window.run()
> +        for secret in self._content['secrets']:
> +            secret['value'] = self._entries[secret['key']].get_text()
> +        self.window.destroy()
> +        return rc
> +
> +    @property
> +    def valid(self):
> +        return all(secret['valid'] for secret in self._content['secrets'])
> +
> +    def _validate(self, entry, secret):
> +        secret['value'] = entry.get_text()
> +        if secret['validate']:
> +            secret['valid'] = secret['validate'](secret)
> +        else:
> +            secret['valid'] = len(secret['value']) > 0
> +        self._update_connect_button()
> +
> +    def _password_entered_cb(self, entry):
> +        if self._connect_button.get_sensitive() and self.valid:
> +            self.window.response(1)
> +
> +    def _update_connect_button(self):
> +        self._connect_button.set_sensitive(self.valid)
> +
> +secret_agent = None
> +
> +class NotAuthorizedException(dbus.DBusException):
> +    _dbus_error_name = SECRET_AGENT_IFACE + '.NotAuthorized'
> +
> +class SecretAgent(dbus.service.Object):
> +    def __init__(self, spoke):
> +        self._bus = dbus.SystemBus()
> +        self.spoke = spoke
> +        dbus.service.Object.__init__(self, self._bus, "/org/freedesktop/NetworkManager/SecretAgent")
> +
> +    @dbus.service.method(SECRET_AGENT_IFACE,
> +                         in_signature='a{sa{sv}}osasb',
> +                         out_signature='a{sa{sv}}',
> +                         sender_keyword='sender')
> +    def GetSecrets(self, connection_hash, connection_path, setting_name, hints, request_new, sender=None):
> +        if not sender:
> +            raise NotAuthorizedException("Internal error: couldn't get sender")
> +        uid = self._bus.get_unix_user(sender)
> +        if uid != 0:
> +            raise NotAuthorizedException("UID %d not authorized" % uid)
> +
> +        log.debug("Secrets requested path '%s' setting '%s' hints '%s' new %d" % (connection_path, setting_name, str(hints), request_new))
Please split this line and the one few lines below into two. Otherwise
this looks good to me, I'm just afraid that at some point in future we
would need to make the SecretAgent class independent on the UI code
(getting a callback for getting the info or something like that).

-- 
Vratislav Podzimek

Anaconda Rider | Red Hat, Inc. | Brno - Czech Republic



More information about the anaconda-patches mailing list