[Dextrose] [Sugar-devel] [PATCH v2][sucrose-0.94][RFC] Add capability to connect to WPA/WPA2-Enterprise networks
Anish Mangal
anish at activitycentral.com
Fri Dec 9 10:08:57 EST 2011
On Fri 09 Dec 2011 06:31:51 PM IST, Peter Robinson wrote:
> This really needs to be ported to the master branch which now used
> NetworkManager 0.9
>
I guess there is great work being done by dsd et. al to get NM 0.9
stuff working with sugar/0.96+. I'd be happy to assist with reviewing
porting etc. if upstream thinks this a valuable addition for mainline.
To that end [cc+=erikos, dsd]
The patch however, is a departure from the current mainline efforts to
_integrate_ network settings between gnome and sugar. It is more on the
lines of 0.94 networking sugar code where sugar stores its own network
settings in connections.cfg
This feature is originally being developed for f14/0.94.1 based dx3
based on a request from OLPC-Australia. At this moment, I'd consider
trying to upstream this for the sucrose-0.94 branch.
Finally, I'd appreciate people testing and reviewing this patch, esp
with LEAP, since we're finding it difficult to get that test
environment up.
> Peter
>
> On Fri, Dec 9, 2011 at 11:27 AM, Anish Mangal <anish at activitycentral.com> wrote:
>> From: Ajay Garg <ajay at sugarlabs.org>
>>
>> As per user-workflow, there is no difference :-
>> ---------------------------------------------------------------
>>
>> 1a. The (WPA/WPA2-Enterprise) network-icon is available on the
>> neighbourhood-view.
>> 1b. Upon clicking the network-icon, a popup dialog appears, asking for
>> parameters.
>> 1c. Upon clicking ok, the connection is made (shown by the
>> 'Network-Connected'-icon in the tray).
>>
>> 2. If the connection is made successfully, the network-profile is saved
>> in "connections.cfg". From next reboot onwards, the connection is made
>> automatically.
>>
>> Configurations :-
>> ------------------------
>>
>> Following configurations have been tested to work :
>> 1. Tunnelled TLS (TTLS)
>> 2. Protected EAP (PEAP)
>>
>> Following configurations are still to be tested :
>> 1. LEAP (seems that it requires support from the access-point).
>> 2. TLS (the testing couldn't be done, even with nm-applet. Would
>> like to hear if anyone gets it working with nm-applet, since the
>> sugar-parameters-UI is modelled on nm-applet-UI.)
>>
>> The patch contains the UI-frontend code for entering all 4
>> configuration parameters (modelled on nm-applet's "Connect
>> to Hidden Wireless Network" -> "WPA/WPA2 Enterprise".
>>
>> Signed-off-by: Ajay Garg <ajay at activitycentral.com>
>> Tested-by: Anish Mangal <anish at activitycentral.com>
>> Signed-off-by: Anish Mangal <anish at activitycentral.com>
>> ---
>> src/jarabe/desktop/keydialog.py | 174 +++++++++++++++++++++++++-
>> src/jarabe/desktop/networkviews.py | 248 +++++++++++++++++++++++++++++++++++-
>> src/jarabe/model/network.py | 22 +++-
>> 3 files changed, 437 insertions(+), 7 deletions(-)
>>
>> diff --git a/src/jarabe/desktop/keydialog.py b/src/jarabe/desktop/keydialog.py
>> index c72f498..53745df 100644
>> --- a/src/jarabe/desktop/keydialog.py
>> +++ b/src/jarabe/desktop/keydialog.py
>> @@ -32,6 +32,10 @@ WEP_PASSPHRASE = 1
>> WEP_HEX = 2
>> WEP_ASCII = 3
>>
>> +SETTING_TYPE_STRING = 1
>> +SETTING_TYPE_LIST = 2
>> +
>> +
>>
>> def string_is_hex(key):
>> is_hex = True
>> @@ -120,6 +124,158 @@ class KeyDialog(gtk.Dialog):
>> return self._response
>>
>>
>> +# Plain Old Python Object (POPO)
>> +class NetworkParametersPOPO(gtk.HBox):
>> + def __init__(self, auth_param):
>> + gtk.HBox.__init__(self, homogeneous=True)
>> + self._key = auth_param._key_name
>> + self._label = gtk.Label(_(auth_param._key_label))
>> + self._key_type = auth_param._key_type
>> +
>> + # Decide, if we need to show a 'entry',
>> + # or a 'list-store'
>> + if len(auth_param._options) == 0:
>> + self._show_entry = True
>> + else:
>> + self._show_entry = False
>> +
>> + self.pack_start(self._label)
>> + self._label.show()
>> +
>> + if self._show_entry:
>> + self._entry = gtk.Entry()
>> + self.pack_start(self._entry)
>> + self._entry.show()
>> + else:
>> + self._option_store = gtk.ListStore(str, str)
>> + for option in auth_param._options:
>> + self._option_store.append(option)
>> +
>> + self._list_store_entry = auth_param._options[0][1]
>> + self._option_combo = gtk.ComboBox(self._option_store)
>> + cell = gtk.CellRendererText()
>> + self._option_combo.pack_start(cell, True)
>> + self._option_combo.add_attribute(cell, 'text', 0)
>> + self._option_combo.set_active(0)
>> + self._option_combo.connect('changed',
>> + self._option_combo_changed_cb)
>> + self.pack_start(self._option_combo)
>> + self.show()
>> + self._option_combo.show()
>> +
>> + def _option_combo_changed_cb(self, widget):
>> + it = self._option_combo.get_active_iter()
>> + (value, ) = self._option_store.get(it, 1)
>> + self._list_store_entry = value
>> +
>> + def _get_key(self):
>> + return self._key
>> +
>> + def _get_value(self):
>> + if self._show_entry:
>> + return self._entry.get_text()
>> + else:
>> + return self._list_store_entry
>> +
>> +
>> +class KeyValuesDialog(gtk.Dialog):
>> + def __init__(self, auth_lists, final_callback, uuid, settings):
>> + gtk.Dialog.__init__(self, flags=gtk.DIALOG_MODAL)
>> + self.set_title(_('Wireless Parameters required'))
>> +
>> + self._auth_lists = auth_lists
>> + self._final_callback = final_callback
>> + self._uuid = uuid
>> + self._settings = settings
>> +
>> + label = gtk.Label(_("Please enter parameters\n"))
>> + self.vbox.pack_start(label)
>> +
>> + self._auth_type_store = gtk.ListStore(str, str)
>> + for auth_list in self._auth_lists:
>> + self._auth_type_store.append([auth_list._auth_label,
>> + auth_list._auth_type])
>> +
>> + self._auth_type_combo = gtk.ComboBox(self._auth_type_store)
>> + cell = gtk.CellRendererText()
>> + self._auth_type_combo.pack_start(cell, True)
>> + self._auth_type_combo.add_attribute(cell, 'text', 0)
>> + self._auth_type_combo.set_active(0)
>> + self._auth_type_combo.connect('changed',
>> + self._auth_type_combo_changed_cb)
>> + self._auth_type_box = gtk.HBox(homogeneous=True)
>> + self._auth_label = gtk.Label(_('Authentication'))
>> + self._auth_type_box.pack_start(self._auth_label, expand=False)
>> + self._auth_type_box.pack_start(self._auth_type_combo,
>> + expand=False)
>> + self.vbox.pack_start(self._auth_type_box)
>> + self._auth_label.show()
>> + self._auth_type_combo.show()
>> +
>> + self.add_buttons(gtk.STOCK_OK, gtk.RESPONSE_OK)
>> + self.set_default_response(gtk.RESPONSE_OK)
>> + self.set_has_separator(True)
>> +
>> + self.connect('response', self._fetch_values)
>> +
>> + auth_type = self._auth_lists[0]._auth_type
>> + self._selected_auth_list = self._select_auth_list(auth_type)
>> + self._add_key_value('eap', auth_type)
>> + self._add_container_box()
>> +
>> + def _auth_type_combo_changed_cb(self, widget):
>> + it = self._auth_type_combo.get_active_iter()
>> + (auth_type, ) = self._auth_type_store.get(it, 1)
>> + self._selected_auth_list = self._select_auth_list(auth_type)
>> + self._add_key_value('eap', auth_type)
>> + self._reset()
>> +
>> + def _select_auth_list(self, auth_type):
>> + for auth_list in self._auth_lists:
>> + if auth_list._params_list[0]._options[0][1] == auth_type:
>> + return auth_list
>> +
>> + def _populate_auth_params(self, auth_list):
>> + for auth_param in auth_list._params_list[1:]:
>> + obj = NetworkParametersPOPO(auth_param)
>> + self._key_values_box.pack_start(obj)
>> + obj.show()
>> +
>> + def _reset(self):
>> + self.vbox.remove(self._key_values_box)
>> + self._add_container_box()
>> +
>> + def _add_container_box(self):
>> + self._key_values_box = gtk.VBox()
>> + self.vbox.pack_start(self._key_values_box)
>> + self._key_values_box.show()
>> + self._populate_auth_params(self._selected_auth_list)
>> +
>> + def _remove_all_params(self):
>> + self._key_values_box.remove_all()
>> +
>> + def _fetch_values(self, key_dialog, response_id):
>> + if response_id == gtk.RESPONSE_OK:
>> + for child in self._key_values_box.get_children():
>> + key = child._get_key()
>> + value = child._get_value()
>> + self._add_key_value(key, value)
>> +
>> + key_dialog.destroy()
>> + self._final_callback(self._uuid, self._settings,
>> + self._selected_auth_list)
>> +
>> + def _add_key_value(self, key, value):
>> + for auth_param in self._selected_auth_list._params_list:
>> + if auth_param._key_name == key:
>> + if auth_param._key_type == SETTING_TYPE_STRING:
>> + auth_param._value = value
>> + elif auth_param._key_type == SETTING_TYPE_LIST:
>> + values = []
>> + values.append(value)
>> + auth_param._value = values
>> +
>> +
>> class WEPKeyDialog(KeyDialog):
>> def __init__(self, ssid, flags, wpa_flags, rsn_flags, dev_caps, settings,
>> response):
>> @@ -218,7 +374,7 @@ class WEPKeyDialog(KeyDialog):
>> self.set_response_sensitive(gtk.RESPONSE_OK, valid)
>>
>>
>> -class WPAKeyDialog(KeyDialog):
>> +class WPAPersonalKeyDialog(KeyDialog):
>> def __init__(self, ssid, flags, wpa_flags, rsn_flags, dev_caps, settings,
>> response):
>> KeyDialog.__init__(self, ssid, flags, wpa_flags, rsn_flags,
>> @@ -296,14 +452,26 @@ def create(ssid, flags, wpa_flags, rsn_flags, dev_caps, settings, response):
>> rsn_flags == network.NM_802_11_AP_SEC_NONE:
>> key_dialog = WEPKeyDialog(ssid, flags, wpa_flags, rsn_flags,
>> dev_caps, settings, response)
>> - else:
>> - key_dialog = WPAKeyDialog(ssid, flags, wpa_flags, rsn_flags,
>> + elif (wpa_flags & network.NM_802_11_AP_SEC_KEY_MGMT_PSK) or \
>> + (rsn_flags & network.NM_802_11_AP_SEC_KEY_MGMT_PSK):
>> + key_dialog = WPAPersonalKeyDialog(ssid, flags, wpa_flags, rsn_flags,
>> dev_caps, settings, response)
>> + elif (wpa_flags & network.NM_802_11_AP_SEC_KEY_MGMT_802_1X) or \
>> + (rsn_flags & network.NM_802_11_AP_SEC_KEY_MGMT_802_1X):
>> + # nothing. All details are asked for WPA/WPA2-Enterprise
>> + # networks, before the conneection-activation is done.
>> + return
>>
>> key_dialog.connect('response', _key_dialog_response_cb)
>> key_dialog.show_all()
>>
>>
>> +def get_key_values(key_list, final_callback, uuid, settings):
>> + key_dialog = KeyValuesDialog(key_list, final_callback,
>> + uuid, settings)
>> + key_dialog.show_all()
>> +
>> +
>> def _key_dialog_response_cb(key_dialog, response_id):
>> response = key_dialog.get_response_object()
>> secrets = None
>> diff --git a/src/jarabe/desktop/networkviews.py b/src/jarabe/desktop/networkviews.py
>> index 2fb8593..738a142 100644
>> --- a/src/jarabe/desktop/networkviews.py
>> +++ b/src/jarabe/desktop/networkviews.py
>> @@ -22,6 +22,7 @@ import hashlib
>>
>> import dbus
>> import glib
>> +import string
>>
>> from sugar.graphics.icon import Icon
>> from sugar.graphics.xocolor import XoColor
>> @@ -56,6 +57,189 @@ _OLPC_MESH_ICON_NAME = 'network-mesh'
>>
>> _FILTERED_ALPHA = 0.33
>>
>> +SETTING_TYPE_STRING = 1
>> +SETTING_TYPE_LIST = 2
>> +
>> +
>> +class AuthenticationType:
>> + def __init__(self, auth_label, auth_type, params_list):
>> + self._auth_label = auth_label
>> + self._auth_type = auth_type
>> + self._params_list = params_list
>> +
>> +
>> +class AuthenticationParameter:
>> + def __init__(self, key_name, key_label, key_type,
>> + options):
>> + self._key_name = key_name
>> + self._key_label = key_label
>> + self._key_type = key_type
>> + self._options = options
>> + self._value = None
>> +
>> +AUTHENTICATION_LIST = \
>> + [
>> + AuthenticationType('TLS',
>> + 'tls',
>> + [
>> + AuthenticationParameter(
>> + 'eap',
>> + 'Authentication',
>> + SETTING_TYPE_LIST,
>> + [['TLS', 'tls']]
>> + ),
>> + AuthenticationParameter(
>> + 'identity',
>> + 'Identity',
>> + SETTING_TYPE_STRING,
>> + []
>> + ),
>> + AuthenticationParameter(
>> + 'client_cert',
>> + 'User certificate',
>> + SETTING_TYPE_STRING,
>> + []
>> + ),
>> + AuthenticationParameter(
>> + 'ca_cert',
>> + 'CA certificate',
>> + SETTING_TYPE_STRING,
>> + []
>> + ),
>> + AuthenticationParameter(
>> + 'private_key',
>> + 'Private key',
>> + SETTING_TYPE_STRING,
>> + []
>> + ),
>> + AuthenticationParameter(
>> + 'private_key_password',
>> + 'Private Key password',
>> + SETTING_TYPE_STRING,
>> + []
>> + )
>> + ]
>> + ),
>> + AuthenticationType('LEAP',
>> + 'leap',
>> + [
>> + AuthenticationParameter(
>> + 'eap',
>> + 'Authentication',
>> + SETTING_TYPE_LIST,
>> + [['LEAP', 'leap']]
>> + ),
>> + AuthenticationParameter(
>> + 'identity',
>> + 'Username',
>> + SETTING_TYPE_STRING,
>> + []
>> + ),
>> + AuthenticationParameter(
>> + 'password',
>> + 'Password',
>> + SETTING_TYPE_STRING,
>> + []
>> + )
>> + ]
>> + ),
>> + AuthenticationType('Tunnelled TLS',
>> + 'ttls',
>> + [
>> + AuthenticationParameter(
>> + 'eap',
>> + 'Authentication',
>> + SETTING_TYPE_LIST,
>> + [['Tunnelled TLS', 'ttls']]
>> + ),
>> + AuthenticationParameter(
>> + 'anonymous_identity',
>> + 'Anonymous identity',
>> + SETTING_TYPE_STRING,
>> + []
>> + ),
>> + AuthenticationParameter(
>> + 'ca_cert',
>> + 'CA certificate',
>> + SETTING_TYPE_STRING,
>> + []
>> + ),
>> + AuthenticationParameter(
>> + 'phase2_auth',
>> + 'Inner Authentication',
>> + SETTING_TYPE_STRING,
>> + [['PAP', 'pap'],
>> + ['MSCHAP', 'mschap'],
>> + ['MSCHAPv2', 'mschapv2'],
>> + ['CHAP', 'chap']]
>> + ),
>> + AuthenticationParameter(
>> + 'identity',
>> + 'Username',
>> + SETTING_TYPE_STRING,
>> + []
>> + ),
>> + AuthenticationParameter(
>> + 'password',
>> + 'Password',
>> + SETTING_TYPE_STRING,
>> + []
>> + )
>> + ]
>> + ),
>> + AuthenticationType('Protected EAP (PEAP)',
>> + 'peap',
>> + [
>> + AuthenticationParameter(
>> + 'eap',
>> + 'Authentication',
>> + SETTING_TYPE_LIST,
>> + [['Protected EAP (PEAP)', 'peap']]
>> + ),
>> + AuthenticationParameter(
>> + 'anonymous_identity',
>> + 'Anonymous identity',
>> + SETTING_TYPE_STRING,
>> + []
>> + ),
>> + AuthenticationParameter(
>> + 'ca_cert',
>> + 'CA certificate',
>> + SETTING_TYPE_STRING,
>> + []
>> + ),
>> + AuthenticationParameter(
>> + 'peap_version',
>> + 'PEAP version',
>> + SETTING_TYPE_STRING,
>> + [['Automatic', ''],
>> + ['Version 0', '0'],
>> + ['Version 1', '1']]
>> + ),
>> + AuthenticationParameter(
>> + 'phase2_auth',
>> + 'Inner Authentication',
>> + SETTING_TYPE_STRING,
>> + [['MSCHAPv2', 'mschapv2'],
>> + ['MD5', 'md5'],
>> + ['GTC', 'gtc']]
>> + ),
>> + AuthenticationParameter(
>> + 'identity',
>> + 'Username',
>> + SETTING_TYPE_STRING,
>> + []
>> + ),
>> + AuthenticationParameter(
>> + 'password',
>> + 'Password',
>> + SETTING_TYPE_STRING,
>> + []
>> + )
>> + ]
>> + )
>> + ]
>> +
>>
>> class WirelessNetworkView(CanvasPulsingIcon):
>> def __init__(self, initial_ap):
>> @@ -340,6 +524,62 @@ class WirelessNetworkView(CanvasPulsingIcon):
>> wireless_security.group = group
>> return wireless_security
>>
>> + if (self._rsn_flags & network.NM_802_11_AP_SEC_KEY_MGMT_802_1X) and \
>> + (self._device_caps & network.NM_802_11_DEVICE_CAP_RSN):
>> + # WPA2 Enterprise
>> + pairwise = self._add_ciphers_from_flags(self._rsn_flags, True)
>> + group = self._add_ciphers_from_flags(self._rsn_flags, False)
>> + wireless_security = WirelessSecurity()
>> + wireless_security.key_mgmt = 'wpa-eap'
>> + wireless_security.proto = 'rsn'
>> + wireless_security.pairwise = pairwise
>> + wireless_security.group = group
>> + return wireless_security
>> +
>> + if (self._wpa_flags & network.NM_802_11_AP_SEC_KEY_MGMT_802_1X) and \
>> + (self._device_caps & network.NM_802_11_DEVICE_CAP_WPA):
>> + # WPA Enterprise
>> + pairwise = self._add_ciphers_from_flags(self._wpa_flags, True)
>> + group = self._add_ciphers_from_flags(self._wpa_flags, False)
>> + wireless_security = WirelessSecurity()
>> + wireless_security.key_mgmt = 'wpa-eap'
>> + wireless_security.proto = 'wpa'
>> + wireless_security.pairwise = pairwise
>> + wireless_security.group = group
>> + return wireless_security
>> +
>> + def _enter_additional_settings_and_secrets_and_then_activate(self,
>> + uuid, settings, wireless_security):
>> + # this is valid, only for "ieee8021x" or "wpa-eap" key
>> + # management.
>> + if (wireless_security.key_mgmt == 'ieee8021x') or \
>> + (wireless_security.key_mgmt == 'wpa-eap'):
>> + keydialog.get_key_values(AUTHENTICATION_LIST,
>> + self.__add_and_activate_connection,
>> + uuid, settings)
>> + else:
>> + self.__add_and_activate_connection(uuid, settings)
>> +
>> + def __add_and_activate_connection(self, uuid, settings,
>> + additional_settings=None):
>> +
>> + if additional_settings is not None:
>> + key_value_dict = {}
>> + auth_params_list = additional_settings._params_list
>> +
>> + for auth_param in auth_params_list:
>> + key = auth_param._key_name
>> + value = auth_param._value
>> + print 'key == ' + key
>> + print 'value == '
>> + print value
>> + key_value_dict[key] = value
>> +
>> + settings.wpa_eap_setting = key_value_dict
>> +
>> + connection = network.add_connection(uuid, settings)
>> + self._activate_connection(connection)
>> +
>> def __connect_activate_cb(self, icon):
>> self._connect()
>>
>> @@ -350,8 +590,10 @@ class WirelessNetworkView(CanvasPulsingIcon):
>> connection = network.find_connection_by_ssid(self._name)
>> if connection is None:
>> settings = Settings()
>> + self._settings = settings
>> settings.connection.id = 'Auto ' + self._name
>> uuid = settings.connection.uuid = unique_id()
>> + self._uuid = uuid
>> settings.connection.type = '802-11-wireless'
>> settings.wireless.ssid = self._name
>>
>> @@ -370,8 +612,12 @@ class WirelessNetworkView(CanvasPulsingIcon):
>> if wireless_security is not None:
>> settings.wireless.security = '802-11-wireless-security'
>>
>> - connection = network.add_connection(uuid, settings)
>> + self._enter_additional_settings_and_secrets_and_then_activate(uuid,
>> + settings, wireless_security)
>> + else:
>> + self._activate_connection(connection)
>>
>> + def _activate_connection(self, connection):
>> obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
>> netmgr = dbus.Interface(obj, _NM_IFACE)
>>
>> diff --git a/src/jarabe/model/network.py b/src/jarabe/model/network.py
>> index f265ae4..2f8295e 100644
>> --- a/src/jarabe/model/network.py
>> +++ b/src/jarabe/model/network.py
>> @@ -418,6 +418,7 @@ class Settings(object):
>> self.connection = Connection()
>> self.ip4_config = None
>> self.wireless_security = None
>> + self.wpa_eap_setting = None
>>
>> if wireless_cfg is not None:
>> self.wireless = wireless_cfg
>> @@ -433,6 +434,10 @@ class Settings(object):
>> self.wireless_security.get_dict()
>> if self.ip4_config is not None:
>> settings['ipv4'] = self.ip4_config.get_dict()
>> + if self.wpa_eap_setting is not None:
>> + settings['802-1x'] = self.wpa_eap_setting
>> +
>> +
>> return settings
>>
>>
>> @@ -653,6 +658,9 @@ class NMSettingsConnection(dbus.service.Object):
>> if self._settings.wireless.security is not None:
>> config.set(identifier, 'security',
>> self._settings.wireless.security)
>> + if self._settings.wpa_eap_setting is not None:
>> + config.set(identifier, 'wpa_eap_setting',
>> + self._settings.wpa_eap_setting)
>> if self._secrets is not None:
>> if self._settings.wireless_security.key_mgmt == 'none':
>> config.set(identifier, 'key', self._secrets.wep_key)
>> @@ -895,13 +903,21 @@ def load_wifi_connections():
>> settings.wireless_security.key_mgmt = mgmt
>> security = config.get(section, 'security')
>> settings.wireless.security = security
>> - key = config.get(section, 'key')
>> if mgmt == 'none':
>> + key = config.get(section, 'key')
>> secrets.wep_key = key
>> auth_alg = config.get(section, 'auth-alg')
>> secrets.auth_alg = auth_alg
>> - elif mgmt == 'wpa-psk':
>> - secrets.psk = key
>> + elif (mgmt == 'wpa-psk') or (mgmt == 'wpa-eap'):
>> + if mgmt == 'wpa-psk':
>> + key = config.get(section, 'key')
>> + secrets.psk = key
>> + elif mgmt == 'wpa-eap':
>> + if config.has_option(section,
>> + 'wpa_eap_setting'):
>> + value = eval(config.get(section,
>> + 'wpa_eap_setting'))
>> + settings.wpa_eap_setting = value
>> if config.has_option(section, 'proto'):
>> value = config.get(section, 'proto')
>> settings.wireless_security.proto = value
>> --
>> 1.7.4.4
>>
>> _______________________________________________
>> Sugar-devel mailing list
>> Sugar-devel at lists.sugarlabs.org
>> http://lists.sugarlabs.org/listinfo/sugar-devel
Cheers,
Anish Mangal
Dextrose Project Manager
Activity Central
More information about the Dextrose
mailing list