Merge lp:~joergberroth/ubuntu-system-settings/wifi-802-1x-configurations into lp:ubuntu-system-settings

Proposed by JkB
Status: Merged
Approved by: Jonas G. Drange
Approved revision: 1415
Merged at revision: 1457
Proposed branch: lp:~joergberroth/ubuntu-system-settings/wifi-802-1x-configurations
Merge into: lp:ubuntu-system-settings
Diff against target: 3222 lines (+2597/-142)
13 files modified
plugins/wifi/CMakeLists.txt (+4/-0)
plugins/wifi/CertDialog.qml (+94/-0)
plugins/wifi/CertPicker.qml (+58/-0)
plugins/wifi/OtherNetwork.qml (+691/-43)
plugins/wifi/certhandler.cpp (+348/-0)
plugins/wifi/certhandler.h (+98/-0)
plugins/wifi/plugin.cpp (+5/-0)
plugins/wifi/wifidbushelper.cpp (+116/-16)
plugins/wifi/wifidbushelper.h (+1/-1)
tests/autopilot/ubuntu_system_settings/__init__.py (+125/-45)
tests/autopilot/ubuntu_system_settings/tests/__init__.py (+18/-9)
tests/autopilot/ubuntu_system_settings/tests/networkmanager.py (+960/-0)
tests/autopilot/ubuntu_system_settings/tests/test_wifi.py (+79/-28)
To merge this branch: bzr merge lp:~joergberroth/ubuntu-system-settings/wifi-802-1x-configurations
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing
Jonas G. Drange (community) Approve
Matthew Paul Thomas design Pending
Review via email: mp+261920@code.launchpad.net

This proposal supersedes a proposal from 2015-06-03.

Commit message

Added support for 802-1x wireless network configurations.

Description of the change

* missed an additional NUL-Termination for passing cert and key path. Prevented to successfully put them into nm-config using path-scheme.
Fine now.

Additionally:
As not all eap networks have cert files issued, one will be able to connect even without selecting one.
Maybe a security warning should be thrown in the dialog informing the user - if he sets certs option to None - that this is a lag in security (mitm attacks)

To post a comment you must log in.
Revision history for this message
Jonas G. Drange (jonas-drange) wrote : Posted in a previous version of this proposal

This is really great. Thanks for proposing this.

I've added some comments, but they're mostly about your decision to make the Dialog an ItemPage. If this is not crucial to the implementation of support for 802-1x, we need to revert it.

Also, if cert picking is not implemented, please remove all components that are unused. Please leave the UI bits in, but hide it with "visible: showAllUI". This way we can get strings translated.

Thanks again.

review: Needs Fixing
Revision history for this message
JkB (joergberroth) wrote : Posted in a previous version of this proposal

> This is really great. Thanks for proposing this.
>
> I've added some comments, but they're mostly about your decision to make the
> Dialog an ItemPage. If this is not crucial to the implementation of support
> for 802-1x, we need to revert it.
>
> Also, if cert picking is not implemented, please remove all components that
> are unused. Please leave the UI bits in, but hide it with "visible:
> showAllUI". This way we can get strings translated.
>
> Thanks again.

Hey, thanks a lot for for reviewing.

First I had the concerns about pushing it to an ItemPage, too. Then, after dealing with the variety of different configurations, I found there would be an advantage if one changes to ItemPage. There is no need for the ItemPage from implementation point of view but there are configurations for which the user has to be asked up to two different certificates and an additional private key (TLS) and there can be different types of path2 authentication types for the different WPA Enterprise configurations.
So if we want the user to be able two choose all the different types of configurations, it seems to me that a dialog would get quite overloaded with ui inputs. And correct me if I'm wrong but scrolling, which certainly would be needed, seems not to be provided for the dialogs.
At the moment there are some pages in the cellular settings (e.g. APN) where one switched to ItemPages, too. So from design point of view it would keep consistent.

Maybe, based on these points, we can quickly discuss this again before I revert the change.

All other comments are clear. I will consider for the next commit.
I think the file picker would make selecting certificates even more comfortable but I will remove it as proposed, so one can work on that later.

Thanks again.

Joerg

Revision history for this message
Matthew Paul Thomas (mpt) wrote : Posted in a previous version of this proposal

Thanks so much for working on this, Joerg!

Jonas is right, though, that the authentication UI does need to remain a dialog. The reason is that System Settings is just one of three -- and will eventually be just one of six -- different places that might launch the UI for entering Wi-Fi details. The first-run setup "Connect to Wi-Fi" screen, and the network indicator menu, should let you connect to all the same Wi-Fi networks that System Settings does, by putting up the same dialog. <https://wiki.ubuntu.com/Networking#wi-fi-authenticating>

When dialog contents are bigger than the available screen space, the body is supposed to scroll automatically, and apparently this has been implemented already (bug 1376763). If it's not working, please report a bug.

review: Needs Fixing (design)
Revision history for this message
JkB (joergberroth) wrote : Posted in a previous version of this proposal

Thanks for the review and the hints.
It was not clear from documentation for me. But the bug post made it.
I just reverted the page back to dialog.

Am 2015-04-27 um 13:04 schrieb Matthew Paul Thomas:
> Review: Needs Fixing design
>
> Thanks so much for working on this, Joerg!
>
> Jonas is right, though, that the authentication UI does need to remain a dialog. The reason is that System Settings is just one of three -- and will eventually be just one of six -- different places that might launch the UI for entering Wi-Fi details. The first-run setup "Connect to Wi-Fi" screen, and the network indicator menu, should let you connect to all the same Wi-Fi networks that System Settings does, by putting up the same dialog. <https://wiki.ubuntu.com/Networking#wi-fi-authenticating>
>
> When dialog contents are bigger than the available screen space, the body is supposed to scroll automatically, and apparently this has been implemented already (bug 1376763). If it's not working, please report a bug.
>

Revision history for this message
Matthew Paul Thomas (mpt) wrote : Posted in a previous version of this proposal

Thank you.

review: Abstain (design)
Revision history for this message
Marcus Tomlinson (marcustomlinson) wrote : Posted in a previous version of this proposal

Your code isn't compiling. There are some weird "!==" occurrences in 2 of your .cpp files. Rather hard to test your changes work when the project doesn't compile no? :P

review: Needs Fixing
Revision history for this message
Jonas G. Drange (jonas-drange) wrote : Posted in a previous version of this proposal

Getting [1] when trying to build. Could you fix those? Thanks.

[1] http://pastebin.ubuntu.com/10989993/

review: Needs Fixing
Revision history for this message
Matthew Paul Thomas (mpt) wrote : Posted in a previous version of this proposal

Yesterday, before I saw this new merge proposal, I was tackling the same question: "Where to store the cert files?" Also private key files and PAC files. On Ubuntu for PC, the current answer is in their own app, "Passwords and Keys". But on phones/tablets the overall system UI real estate is much smaller, so as with software updates and system version, this task fits best in System Settings.

This means the same conclusion (3) that you came to: storing the files in System Settings. "For this reason, System Settings should be set up as the default handler for certificates, private key files, and PAC files that you download or open, showing a confirmation dialog with info about the certificate/file and “Cancel” and “Save” buttons, and then lowering itself behind the previous app." <https://wiki.ubuntu.com/Networking#wi-fi-authentication-variations> I haven't designed those three dialogs in detail because I haven't yet found a reference for what data those files contain.

A later task will be to design+implement a way to remove previously-saved certificates/files inside System Settings.

Revision history for this message
Jonas G. Drange (jonas-drange) wrote : Posted in a previous version of this proposal

Thanks, Joerg. It builds and it looks good! I have a couple of questions and comments:

1. If file picker fails, I prefer that it was reverted to "None". What do you think?
2. Could you add some instructions on how to test this?
3. I don't quite understand the diff L98-200, why is the indentation changed?
4. L425, L465, L506, L559: Please use visible: showAllUI for things not yet implemented.
5. L431, L440, L482, L673, L675, L678, L869, L877, L885, L893, L901, L909: Extra space
6. L759: If it's not needed, please just remove it. If it's something we might have to do, maybe make it a TODO?

This would be difficult to test using autopilot, but we should try. I can help you, if you can inform me on what the most common WPA2 Enterprise network looks like, and what the user needs to do, using your UI, to connect to it.

Thanks again.

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
JkB (joergberroth) wrote : Posted in a previous version of this proposal
Download full text (3.5 KiB)

Jonas, thanks for reviewing.

First,
4.-6. To which diff/file do your line numbers refer to. I don't get them
aligned with my r1401 into r1435.

1. You are right. Also, if a cert is added, the added cert item should
be selected after closing the dialog. I will keep on working on that.

2. To fully test this, ideally, proper networks have to be available to
connect to. As they are not easy to set up or even seem to be hardware
dependent, one may think about if its possible to emulate the networks.
What I could test so far, besides the typical WPA and WEP, was a
TTLS/MSCHAP2 network. The TTLS is typically used for "eduroam",
available at most universities all over europe. They might differ in the
phase-2-authentication (inner authentication) type from university to
university.

If you just want to test the creation of the right configuration it
should be sufficient to check the configuration file for the network in
/userdata/system-data/etc/NetworkManager/system-connection/ and compare
them to example files. These files are created even if no network is
available. There was already an error handling integrated that prints
wpa_supplicant errors in the feedback dialog. So e.g. if your cert file
does not contain the content it should, it will be wpa_supplicant that
reports this.

I don't know what wifi infrastructures you have around, but I believe it
is hard to get everyone.
I've heard of wpa_supplicant being able to emulate different WPA
networks, but I had not have the time to look into that.

My connection test on a TTLS/MSCHAPv2 eduroam was established
successfully. Maybe it would be best to let people test it with there
networks.

Hence, for testing and maybe autopilot testing for an example connection
- lets take the TTLS/MSCHAPv2 - one has to go through the following steps:

1. type in network name (SSID)
2. select WPA Enterprise
3. select auth TTLS
4. select inner auth MSCHAPv2
5. CA certificate ( lets state that no one is installed) -> select choose...
6. use content hub to import a cert file (.pem supported at the moment)
7. content hub will import it to the Documents folder of
ubuntu-system-settings.
8. the file will be shown on the CertDialog and the user can decide to
save the file.
9. If that file is not empty, it will be moved to the wifi/ssl/certs/
folder. The data model will use the files in that folder to build the
itemselector.
10. Choose the right ca cert.
11. type in anonym identity, identity and Password.
12. then connect. If the network will not be found, an error message
will be thrown.

I do not know anything about autopilot testing so far. If you believe we
can get this running, I just could support you.

Thanks,
Joerg

Am 2015-06-05 um 14:11 schrieb Jonas G. Drange:
> Review: Needs Fixing
>
> Thanks, Joerg. It builds and it looks good! I have a couple of questions and comments:
>
> 1. If file picker fails, I prefer that it was reverted to "None". What do you think?
> 2. Could you add some instructions on how to test this?
> 3. I don't quite understand the diff L98-200, why is the indentation changed?
> 4. L425, L465, L506, L559: Please use visible: showAllUI for things not yet implemented.
> 5. L431, L440, L482, L673...

Read more...

Revision history for this message
Jonas G. Drange (jonas-drange) wrote : Posted in a previous version of this proposal

On 5 June 2015 at 20:57, JkB <email address hidden> wrote:

> Jonas, thanks for reviewing.
>
>
​Happy to!​

> First,
> 4.-6. To which diff/file do your line numbers refer to. I don't get them
> aligned with my r1401 into r1435.
>
>
​I meant the web diff [1]. I am not certain as to why I did not use the
inline comment system. Sorry!

[1]
https://code.launchpad.net/~joergberroth/ubuntu-system-settings/wifi-802-1x-configurations/+merge/261022/+preview-diff/629978/+files/preview.diff

> 1. You are right. Also, if a cert is added, the added cert item should
> be selected after closing the dialog. I will keep on working on that.
>
>
​Awesome.​

> 2. To fully test this,
> …
> "eduroam"
> ​ [is] ​
> available at most universities all over europe.

Me and my brother both have Ubuntu Phones and attend university, so we'll
give eduroam a go. Good idea!​

> If you just want to test the creation of the right configuration it
> should be sufficient to check the configuration file for the network in
> /userdata/system-data/etc/NetworkManager/system-connection/ and compare
> them to example files. These files are created even if no network is
> available.

​Grea​t. That means we can mock (imitate) NetworkManager and query it
directly over dbus.

> I don't know what wifi infrastructures you have around, but I believe it
> is hard to get everyone.
> I've heard of wpa_supplicant being able to emulate different WPA
> networks, but I had not have the time to look into that.
>

​I don't think that's necessary at this stage. WPA2 enterprise isn't
critical judging by the level of bug reporting.

> My connection test on a TTLS/MSCHAPv2 eduroam was established
> successfully. Maybe it would be best to let people test it with there
> networks.
>
>
​Agreed.​

> Hence, for testing and maybe autopilot testing for an example connection

​I can start this when I have free cycles.​

> I do not know anything about autopilot testing so far. If you believe we
> can get this running, I just could support you.
>
>
​No worries. I'll propose a branch against this branch.​

​Thanks,
Jonas​

Revision history for this message
JkB (joergberroth) wrote : Posted in a previous version of this proposal

Am 2015-06-05 um 22:51 schrieb Jonas G. Drange:
> On 5 June 2015 at 20:57, JkB <email address hidden> wrote:
>
>> First,
>> 4.-6. To which diff/file do your line numbers refer to. I don't get them
>> aligned with my r1401 into r1435.
>>
>>
> ​I meant the web diff [1]. I am not certain as to why I did not use the
> inline comment system. Sorry!
>
> [1]
> https://code.launchpad.net/~joergberroth/ubuntu-system-settings/wifi-802-1x-configurations/+merge/261022/+preview-diff/629978/+files/preview.diff
> ​
Checked that, but still don't get it, where is the offset?
>
>
>> If you just want to test the creation of the right configuration it
>> should be sufficient to check the configuration file for the network in
>> /userdata/system-data/etc/NetworkManager/system-connection/ and compare
>> them to example files. These files are created even if no network is
>> available.
>
>
> ​Grea​t. That means we can mock (imitate) NetworkManager and query it
> directly over dbus.

Yes, sounds like an idea!
>
>

Revision history for this message
Jonas G. Drange (jonas-drange) wrote :

Great. Only two minor comments. :) I have yet to test this on eduroam, but will hopefully get it tested this week.

review: Needs Information
1405. By JkB

* added QStandardPaths for cert handling
* improved getting secrets in Previous network to get wpa-eap passwords as well.
* restored .bzrignore

Revision history for this message
JkB (joergberroth) wrote :
Download full text (61.6 KiB)

Fixed that and also improved getting secrets for PreviousNetworks page.
Looking forward to your test results.
Thanks again.

Am 2015-06-15 um 15:33 schrieb Jonas G. Drange:
> Review: Needs Information
>
> Great. Only two minor comments. :) I have yet to test this on eduroam, but will hopefully get it tested this week.
>
> Diff comments:
>
>> === modified file '.bzrignore'
>> --- .bzrignore 2014-07-25 08:22:52 +0000
>> +++ .bzrignore 2015-06-15 00:18:56 +0000
>> @@ -1,22 +1,2 @@
>> -/build
>> -*.debhelper
>> -*.log
>> -*.moc
>> -CMakeLists.txt.user
>> -moc_*
>> -Makefile*
>> -tst_*
>> -lib/SystemSettings/SystemSettings.pc
>> -src/qrc_ui.cpp
>> -src/system-settings
>> -system-settings.pro.user
>> -/debian/files
>> -/debian/libsystemsettings-dev/
>> -/debian/libsystemsettings1/
>> -/debian/tmp/
>> -/debian/ubuntu-system-settings/
>> -/debian/ubuntu-system-settings-example/
>> -.cproject
>> -.project
>> -.settings
>> -__pycache__
>> +*.txt_testingjkb
>
> What warrants all these changes to the bzrignore?
>
>> +./CMakeLists.txt.user
>>
>> === modified file 'plugins/wifi/CMakeLists.txt'
>> --- plugins/wifi/CMakeLists.txt 2014-09-15 15:39:50 +0000
>> +++ plugins/wifi/CMakeLists.txt 2015-06-15 00:18:56 +0000
>> @@ -1,6 +1,8 @@
>> set(QML_SOURCES
>> AccessPoint.qml
>> BaseMenuItem.qml
>> +CertPicker.qml
>> +CertDialog.qml
>> Common.qml
>> DivMenuItem.qml
>> FramedMenuItem.qml
>> @@ -23,10 +25,12 @@
>> plugin.cpp
>> unitymenumodelstack.cpp
>> previousnetworkmodel.cpp
>> + certhandler.cpp
>> wifidbushelper.h
>> plugin.h
>> unitymenumodelstack.h
>> previousnetworkmodel.h
>> + certhandler.h
>> nm_manager_proxy.h
>> nm_settings_proxy.h
>> nm_settings_connection_proxy.h
>>
>> === added file 'plugins/wifi/CertDialog.qml'
>> --- plugins/wifi/CertDialog.qml 1970-01-01 00:00:00 +0000
>> +++ plugins/wifi/CertDialog.qml 2015-06-15 00:18:56 +0000
>> @@ -0,0 +1,92 @@
>> +import QtQuick 2.0
>> +import QtQuick.Layouts 1.1
>> +import Ubuntu.Components.Popups 0.1
>> +import Ubuntu.Components 0.1
>> +import Ubuntu.Components.ListItems 0.1 as ListItem
>> +import Ubuntu.SystemSettings.Wifi 1.0
>> +
>> +Component {
>> +
>> + Dialog {
>> + id: certDialog
>> +
>> + property var certType;
>> + property var fileName;
>> +
>> + signal updateSignal(var update);
>> +
>> + anchors.fill: parent
>> +
>> + title: {
>> + if (certType === 0){ // certificate
>> + {i18n.tr("Add certificate")+"?"};
>> + } else if (certType === 1){ // privatekey
>> + {i18n.tr("Add key")+"?"};
>> + } else if (certType === 2){ // pacFile
>> + {i18n.tr("Add pac file")+"?"};
>> + }
>> + }
>> +
>> + FileHandler {
>> + id: fileHandler
>> + }
>> +
>> + Label {
>> + id: certContentLabel
>> + text : {i18n.tr("Content")+":"}
>> + objectName: "certContentLabel"
>> + fontSize: "medium"
>> + font.bold: false
>> + }
>> +
>> + TextArea {
>> + id : certContent
>> + objectName: "certContent"
>> + readOnly: true...

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
1406. By JkB

merge with trunk

1407. By JkB

merged with jgdx merge proposal. Thanks a lot Jonas for the extensive format fixes!
+Also, considered some quickly managable FIXMEs from Jonas. Some stay.

Revision history for this message
Jonas G. Drange (jonas-drange) wrote :

Tried connecting to an eduroam network yesterday. I don't have a syslog, and the System Settings log looked normal. However, this [1] is what System Settings produced in /etc/NetworkManager/system-connections/eduroam. I am puzzled that there's a type=wifi entry in [connection], since there's no such type [2].

Sadly the eduroam connection failed. I followed normal eduroam connection settings (PEAP, mschapv2).

Creating the same connection using nm-applet, creates the following /etc/NetworkManager/system-connections/eduroam file [3].

[1] http://pastebin.ubuntu.com/11772095/
[2] https://developer.gnome.org/NetworkManager/stable/ref-settings.html
[3] http://pastebin.ubuntu.com/11772332/

review: Needs Information
Revision history for this message
JkB (joergberroth) wrote :

Thanks for testing this with peap.

First, the type String is set by nm after sending over the configuration
data with the original "802-11-wireless" string as type.
So this seems to be changed by nm. I have not had a closer look t this,
yet. But I think this does not matter, as for my eduroam network
(TTLS/MChapv2) it works.

In general:
Have you got the orange feedback text over the button row? What does it
tell?

If nm fails with the configuration it states a warning visible in the
system-settings log in .cache/upstart/.

And anyway,
I haven't yet spent a lot time on the peap configuration,
and it seems that I forgot to add the ca-cert integration for PEAP!

Don't you need the ca-cert for your eduroam (wherever this is) ?

And than there are two more points:
the peap-label check and the version check.
At the moment I am not sure what is really needed to ask the user, so I
will check that as well
and come back with a fix tonight.

Revision history for this message
Jonas G. Drange (jonas-drange) wrote :

On 25 June 2015 at 13:21, JkB <email address hidden> wrote:

> First, the type String is set by nm after sending over the configuration
> data with the original "802-11-wireless" string as type.
>

​I'll confirm this using autopilot testing. But we need to find and
eliminate the case in which 'wifi' is sent by the binding (if ever). I'll
try to discover this via testing.​

> as for my eduroam network
> ​ ​
> (TTLS/MChapv2) it works.
>

​It would be interesting to see this configuration if it works. What you
could do is to pastebin this file:

/etc/NetworkManager/system-connections/eduroam

Remove all private information before pasting :)​

In general:
> Have you got the orange feedback text over the button row? What does it
> tell?
>

​I did notice the feedback, but I saw in my syslog that it wouldn't
associate.​

If nm fails with the configuration it states a warning visible in the
> system-settings log in .cache/upstart/.
>

​Okay, will look there.​

> And anyway,
> I haven't yet spent a lot time on the peap configuration,
> and it seems that I forgot to add the ca-cert integration for PEAP!
>

​Looking forward to that :)​

> Don't you need the ca-cert for your eduroam (wherever this is) ?
>

​No, not according to the instructions on my Uni's site:
https://it.uib.no/en/How_to_connect_wireless_to_eduroam

> And than there are two more points:
> the peap-label check and the version check.
> At the moment I am not sure what is really needed to ask the user, so I
> will check that as well
> and come back with a fix tonight.

​Awesome!

1408. By JkB

* fixed wpa-eap/peap configurations.
* added "certificates recommended" security hint.

1409. By JkB

*merged with trunk

Revision history for this message
JkB (joergberroth) wrote :

Am 2015-06-25 um 15:06 schrieb Jonas G. Drange:

> ​It would be interesting to see this configuration if it works. What you
> could do is to pastebin this file:
>
This is the eduroam config written on connection on ubuntu phone:

http://paste.ubuntu.com/11776155/

Never recognized the change in labeling before, though.

>
>> Don't you need the ca-cert for your eduroam (wherever this is) ?
> ​No, not according to the instructions on my Uni's site:
> https://it.uib.no/en/How_to_connect_wireless_to_eduroam

Also, I added a hint in the dialog, that connecting to a network with
choosing a cert is more secure.

>> And than there are two more points:
>> the peap-label check and the version check.

I commited a fix against that. It would be great if you could test this
again.
Could be that the fault was in forcing "phase1-peaplabel" = 1. Hopefully.

Thanks.

Revision history for this message
Jonas G. Drange (jonas-drange) wrote :

On 26 June 2015 at 08:04, JkB <email address hidden> wrote:

> http://paste.ubuntu.com/11776155/
>

​If that works for you, let's assume that connection.type 'wifi' is valid,
even though it's not documented.

Also, I added a hint in the dialog, that connecting to a network with
> choosing a cert is more secure.
>

Okay, but we need to make sure design is involved, so if there's nothing in
the spec [1] about this, we have to create a bug against System Settings
which affects ubuntu-ux. What's the basis for this hint?​

> >> And than there are two more points:
> >> the peap-label check and the version check.
>
> I commited a fix against that. It would be great if you could test this
> again.

​Will do! I see that the nm-applet (Ubuntu Desktop's way of connecting to
hidden networks) does not force phase1-peaplabel=1, however, it does
include password-flags=1 instead of password-flags=2.​

​Here's [2] the work on autopilot tests for your branch​. There are some
notable changes that affects your branch, not directly related to autopilot
tests:

   - Auth methods and protocols are no longer translated (e.g. PEAP,
   MSCHAPv2, and so on.)
   - Your feedback change has been reverted for the following reasons:
      - It's in the spec [3].
      - The tests depend on the feedback existing in the text property of
      the Dialog.
      - The Dialog provides the 'text' property, so why would we not use it
      for feedback important to the user? :)
      - If visibility is a problem, we should to scroll to the top of the
      dialog. This is the pattern in other dialogs as well.
   - One fixme has been re-added, but I'll take care of it. :)

I need suggestions on what to test. What are other popular WPA2 enterprise
configurations? Do you have suggestions, Joerg?

Also, anything you'd like me to test?

Thanks,
Jonas.

​[1]
https://wiki.ubuntu.com/Networking#Authentication_variations.2C_certificates.2C_and_PAC_files

[2]
https://code.launchpad.net/~jonas-drange/ubuntu-system-settings/wifi-802-1x-configurations-tests/+merge/263092
​[3]
https://wiki.ubuntu.com/Networking?action=AttachFile&do=get&target=wi-fi-authentication-key-error.phone.png

Revision history for this message
JkB (joergberroth) wrote :
Download full text (3.2 KiB)

Am 2015-06-26 um 13:51 schrieb Jonas G. Drange:
> On 26 June 2015 at 08:04, JkB <email address hidden> wrote:

> ​If that works for you, let's assume that connection.type 'wifi' is valid,
> even though it's not documented.

Yes. And you'll see also for [wifi-security] one changed that from
[802-11-wireless-security]...

>
> Also, I added a hint in the dialog, that connecting to a network with
>> choosing a cert is more secure.
>>
>
> Okay, but we need to make sure design is involved, so if there's nothing in
> the spec [1] about this, we have to create a bug against System Settings
> which affects ubuntu-ux. What's the basis for this hint?​
You're right. I will comment it until than.
The idea behind this is, that without certification, the user can not be
sure that he is connecting to a real e.g. "eduroam" which could be a
security problem.
On the other side it's not up to the user to fix that but to the admin
that owns the network.
So, difficult.

>
>>>> And than there are two more points:
>>>> the peap-label check and the version check.
>>
>> I commited a fix against that. It would be great if you could test this
>> again.
>
>
> ​Will do! I see that the nm-applet (Ubuntu Desktop's way of connecting to
> hidden networks) does not force phase1-peaplabel=1, however, it does
> include password-flags=1 instead of password-flags=2.​
That's right.
I removed forcing peap-label and put in an itemselector for choosing
peap-version instead as this is more common.

About password-flags: [1]
password-flags=2 is issued if the password shall not be saved.

I left the flags out if pw is to be saved. defaults to 0.

>
>
> ​Here's [2] the work on autopilot tests for your branch​. There are some
Will have a look at this later.
> notable changes that affects your branch, not directly related to autopilot
> tests:
>
> - Auth methods and protocols are no longer translated (e.g. PEAP,
> MSCHAPv2, and so on.)

ok!

> - Your feedback change has been reverted for the following reasons:

> - If visibility is a problem, we should to scroll to the top of the
> dialog. This is the pattern in other dialogs as well.
That was the point I was thinking about. It is more user friendly to
have it appear right in sight over the "command" buttons.
But, you are right, scrolling would do in a way, too.
And as the tests already depend on that I will change it back.
Maybe one can think about this later.

> - One fixme has been re-added, but I'll take care of it. :)
I removed it, as I already translate it in the certhandler.cpp !
so if you add the translation in this file, we should remove it in the
handler. What is more common?
>
> I need suggestions on what to test. What are other popular WPA2 enterprise
> configurations? Do you have suggestions, Joerg?
I'm not a pro in that but during the last days ;-) I read of peap and
TLS being the most common. So, the TLS config would be a point to start.

>
> Also, anything you'd like me to test?
And as I have no auto tests, checking whether all the parameters are
sent and put in right into configuration would be great. I then would go
through all the config files created.

Really looking forward to your te...

Read more...

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1410. By JkB

merge jonas branch

1411. By JkB

merge with trunk

1412. By JkB

* set feedback back to original implementation

Revision history for this message
Jonas G. Drange (jonas-drange) wrote :

> >> I commited a fix against that. It would be great if you could test this
> >> again.

I have tested connecting to eduroam on both Mako (Nexus 4) and Meizu's phone—it works! :)

I feel confident we are ready to land this, however, I just proposed merging [1] into this branch. It fixes the last fixmes. :)

[1] https://code.launchpad.net/~jonas-drange/ubuntu-system-settings/wifi-802-1x-configurations-fixmes/+merge/263242

Revision history for this message
JkB (joergberroth) wrote :

Am 2015-06-29 um 16:05 schrieb Jonas G. Drange:
>>>> I commited a fix against that. It would be great if you could test this
>>>> again.
>
> I have tested connecting to eduroam on both Mako (Nexus 4) and Meizu's phone—it works! :)

Great! Have you tested using certificates for your connection as well?
>
> I feel confident we are ready to land this, however, I just proposed merging [1] into this branch. It fixes the last fixmes. :)
>

Ok. I will have a look at them tonight; It seems that I then can remove
translations in the certhandler.cpp itself.
Do you think it is really necessary to translate names (CommonName,
Organization) ?

Thanks.

> [1] https://code.launchpad.net/~jonas-drange/ubuntu-system-settings/wifi-802-1x-configurations-fixmes/+merge/263242
>

Revision history for this message
Matthew Paul Thomas (mpt) wrote :

"The idea behind this is, that without certification, the user can not be sure that he is connecting to a real e.g. "eduroam" which could be a security problem. On the other side it's not up to the user to fix that but to the admin that owns the network. So, difficult."

There is precedent for this: I specced that the dialog should warn that WEP networks are inherently insecure.

You seem to be talking about a different case, though, where connecting to a network without a certificate leaves you vulnerable to connecting accidentally to a different network with the same name later. But it's not clear to me how that problem is any worse for authentication types that allow certificates than for authentication types that don't. That's bug 1258496, which is a problem for any authentication type. If there's something that TLS/PEAP etc can do specifically for that, please comment in that bug report; or if you're talking about something different, report a separate bug.

Revision history for this message
Jonas G. Drange (jonas-drange) wrote :

On 29 June 2015 at 17:51, JkB <email address hidden> wrote:

> Great! Have you tested using certificates for your connection as well?
>

​No, I don't have this opportunity.​

> Ok. I will have a look at them tonight; It seems that I then can remove
> translations in the certhandler.cpp itself.
>

​No, “None” and “Choose” are still translated.​

> Do you think it is really necessary to translate names (CommonName,
> Organization) ?
>

​When we do i18n.tr("%1…").arg(Organization), we allow translators to
choose how this is translated, but Organization name just replaces %1 and
is not translated.​

So, in Norwegian, if we elided words using “–bork”, a translator just
changes “%1…” into “%1–bork”.

Thank you.

Revision history for this message
JkB (joergberroth) wrote :

> ​No, I don't have this opportunity.

According to a script, I found for your University?! there is a cert
chain in the script [1].
You could try this....

@mpt:
The problem I talked about is in a way about the man in the tent as
described in the bug.
To my understanding, the advantage of WPA Enterprise networks is that
you can be sure to connect to the right access point, if it carries a
valid certificate (or let's say it's way harder to build an "evil twin"
as you don't own the cert).

For example, the University of Bergen works with certificates [1], but
not as a must have [2]. There seems to be an older auth scheme as well.
Maybe
@Jonas can clarify this?
In general this is a IT department thing and the user only could ask for
it. Thats's why I also question providing a hint.

Nevertheless, suggesting the user to inform him/-herself about existing
certificates that could be used, increases security.

What do you think?

>
>
>> Ok. I will have a look at them tonight; It seems that I then can remove
>> translations in the certhandler.cpp itself.
>>
>
> ​No, “None” and “Choose” are still translated.​
Of course, yes.
I was thinking of two translations _("Private key") and _("Public key")
which are passed as quasi constants. But I see, they will be kept also,
well?

>
> So, in Norwegian, if we elided words using “–bork”, a translator just
> changes “%1…” into “%1–bork”.
ok. :-).

Thanks a lot.

[1] https://eduroam.no/connect/?institution=535;profile=1751;os=linux
[2] https://it.uib.no/en/Eduroam_for_Linux

1413. By JkB

merge Jonas fixmes

1414. By JkB

clear spaces

1415. By JkB

merge with trunk

Revision history for this message
Jonas G. Drange (jonas-drange) wrote :

>
> > ​No, I don't have this opportunity.
>
> According to a script, I found for your University?! there is a cert
> chain in the script [1].
>

​Oh, sorry! Great find, I'll give it a go tomorrow.

Revision history for this message
Jonas G. Drange (jonas-drange) wrote :

​I just made a successful connection to eduroam using the certificate provided by eduroam.

There was a lesser issue that the ItemSelector was had selectedIndex 0 after the .pem was added. This is due to bug [1] which will not be fixed by the UI toolkit. The real solution is to use a ListModel [2].

We can fix this in a subsequent branch, I don't think it's a show stopper at this point, as eduroam allows certificate-less connections.

[1] https://bugs.launchpad.net/ubuntu/+source/ubuntu-ui-toolkit/+bug/1421653
[2] ​http://qt-project.org/doc/qt-5/qml-qtqml-models-listmodel.html

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1416. By JkB

* multiple %1 args in i18n.tr all fall back to the first arg() provided.
Is this an individuell problem of my build?
If not we should consider this last commit.

1417. By JkB

* only show "using certificate.." hint if selected one == "None"

Revision history for this message
Jonas G. Drange (jonas-drange) wrote :

Thanks Joerg, for fixing the translation issues, as well as improving the cert ui. If there are no more critical issues in this branch, I want to land it as is—this means no more commits after this approve. :) This way we can get your branch into OTA5 (next system update).

review: Approve
Revision history for this message
JkB (joergberroth) wrote :

Am Donnerstag, 2. Juli 2015 00:29:27 CEST
> after this approve. :) This way we can get your branch into OTA5
> (next system update).
>
Thats it! Thanks a lot jonas!

--
Versandt, mit Dekko von meinem Ubuntu-Gerät

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/wifi/CMakeLists.txt'
2--- plugins/wifi/CMakeLists.txt 2014-09-15 15:39:50 +0000
3+++ plugins/wifi/CMakeLists.txt 2015-07-01 18:56:14 +0000
4@@ -1,6 +1,8 @@
5 set(QML_SOURCES
6 AccessPoint.qml
7 BaseMenuItem.qml
8+CertPicker.qml
9+CertDialog.qml
10 Common.qml
11 DivMenuItem.qml
12 FramedMenuItem.qml
13@@ -23,10 +25,12 @@
14 plugin.cpp
15 unitymenumodelstack.cpp
16 previousnetworkmodel.cpp
17+ certhandler.cpp
18 wifidbushelper.h
19 plugin.h
20 unitymenumodelstack.h
21 previousnetworkmodel.h
22+ certhandler.h
23 nm_manager_proxy.h
24 nm_settings_proxy.h
25 nm_settings_connection_proxy.h
26
27=== added file 'plugins/wifi/CertDialog.qml'
28--- plugins/wifi/CertDialog.qml 1970-01-01 00:00:00 +0000
29+++ plugins/wifi/CertDialog.qml 2015-07-01 18:56:14 +0000
30@@ -0,0 +1,94 @@
31+import QtQuick 2.0
32+import QtQuick.Layouts 1.1
33+import Ubuntu.Components.Popups 0.1
34+import Ubuntu.Components 0.1
35+import Ubuntu.Components.ListItems 0.1 as ListItem
36+import Ubuntu.SystemSettings.Wifi 1.0
37+
38+Component {
39+
40+ Dialog {
41+ id: certDialog
42+
43+ property var certType;
44+ property var fileName;
45+
46+ signal updateSignal(var update);
47+
48+ anchors.fill: parent
49+
50+ title: {
51+ if (certType === 0) { // certificate
52+ return i18n.tr("Add certificate?");
53+ } else if (certType === 1) { // privatekey
54+ return i18n.tr("Add key?");
55+ } else if (certType === 2) { // pacFile
56+ return i18n.tr("Add pac file?");
57+ }
58+ }
59+
60+ FileHandler {
61+ id: fileHandler
62+ }
63+
64+ Label {
65+ id: certContentLabel
66+ text : i18n.tr("Content:")
67+ objectName: "certContentLabel"
68+ fontSize: "medium"
69+ font.bold: false
70+ }
71+
72+ TextArea {
73+ id : certContent
74+ objectName: "certContent"
75+ readOnly: true
76+ width: parent.width
77+ autoSize: true
78+ maximumLineCount: 7
79+ placeholderText: i18n.tr("No data available.")
80+ text: fileHandler.getCertContent(certDialog.fileName).toString()
81+ }
82+
83+ RowLayout {
84+ id: buttonRow
85+ anchors {
86+ left: parent.left
87+ right: parent.right
88+ }
89+ spacing: units.gu(2)
90+ height: cancelButton.height
91+
92+ Button {
93+ id: cancelButton
94+ Layout.fillWidth: true
95+ text: i18n.tr("Cancel")
96+ onClicked: {
97+ fileHandler.removeFile(certDialog.fileName);
98+ PopupUtils.close(certDialog);
99+ }
100+ }
101+
102+ Button {
103+ id: saveButton
104+ text: i18n.tr("Save")
105+ Layout.fillWidth: true
106+ enabled: (certDialog.certContent.text !== "")
107+ onClicked: { if (certType === 0) { // certificate
108+ fileHandler.moveCertFile(certDialog.fileName);
109+ } else if (certType === 1) { // privatekey
110+ fileHandler.moveKeyFile(certDialog.fileName);
111+ } else if (certType === 2) { // pacFile
112+ fileHandler.movePacFile(certDialog.fileName);
113+ }
114+
115+ /* Just to be sure source file will be deleted if move was
116+ not successfull */
117+ fileHandler.removeFile(certDialog.fileName);
118+ certDialog.updateSignal(true);
119+ PopupUtils.close(certDialog);
120+ }
121+ }
122+ }
123+ }
124+}
125
126=== added file 'plugins/wifi/CertPicker.qml'
127--- plugins/wifi/CertPicker.qml 1970-01-01 00:00:00 +0000
128+++ plugins/wifi/CertPicker.qml 2015-07-01 18:56:14 +0000
129@@ -0,0 +1,58 @@
130+import QtQuick 2.0
131+import QtQuick.Layouts 1.1
132+import Ubuntu.Components 0.1
133+import Ubuntu.Components.Popups 0.1
134+import Ubuntu.Content 0.1
135+
136+PopupBase {
137+ id: picker
138+
139+ signal fileImportSignal (var file)
140+ property var activeTransfer
141+
142+ Rectangle {
143+ anchors.fill: parent
144+
145+ ContentTransferHint {
146+ id: transferHint
147+ anchors.fill: parent
148+ activeTransfer: picker.activeTransfer
149+ }
150+
151+ ContentStore {
152+ id: appStore
153+ scope: ContentScope.App
154+ }
155+
156+ ContentPeerPicker {
157+ id: peerPicker
158+ anchors.fill: parent
159+ visible: true
160+ contentType: ContentType.Documents
161+ handler: ContentHandler.Source
162+ onPeerSelected: {
163+ peer.selectionType = ContentTransfer.Single;
164+ picker.activeTransfer = peer.request(appStore);
165+ }
166+ onCancelPressed: PopupUtils.close(picker)
167+ }
168+ }
169+
170+ Connections {
171+ target: picker.activeTransfer ? picker.activeTransfer : null
172+ onStateChanged: {
173+ if (picker.activeTransfer.state === ContentTransfer.Charged) {
174+ if (picker.activeTransfer.items.length > 0) {
175+ var fileUrl = picker.activeTransfer.items[0].url;
176+ picker.fileImportSignal(
177+ fileUrl.toString().replace("file://", "")
178+ );
179+ PopupUtils.close(picker);
180+ }
181+ } else if (picker.activeTransfer.state === ContentTransfer.Aborted){
182+ picker.fileImportSignal(false);
183+ PopupUtils.close(picker);
184+ }
185+ }
186+ }
187+}
188
189=== modified file 'plugins/wifi/OtherNetwork.qml'
190--- plugins/wifi/OtherNetwork.qml 2015-01-09 08:47:53 +0000
191+++ plugins/wifi/OtherNetwork.qml 2015-07-01 18:56:14 +0000
192@@ -31,21 +31,53 @@
193 objectName: "otherNetworkDialog"
194 anchorToKeyboard: true
195
196- function settingsValid() {
197- if(networkname.length == 0) {
198+ function settingsValid () {
199+ if (networkname.length === 0) {
200 return false;
201 }
202- if(securityList.selectedIndex == 0) {
203+ if (securityList.selectedIndex === 0) {
204 return true
205 }
206- if(securityList.selectedIndex == 1) {
207- return password.length >= 8
208+ if (securityList.selectedIndex === 3) {
209+ // WEP
210+ return password.length === 5 ||
211+ password.length === 10 ||
212+ password.length === 13 ||
213+ password.length === 26;
214 }
215- // WEP
216- return password.length === 5 ||
217- password.length === 10 ||
218- password.length === 13 ||
219- password.length === 26;
220+ //WPA
221+ return password.length >= 8
222+ }
223+
224+ function filePicker (type) {
225+ var pickerDialog;
226+ var certDialog;
227+
228+ pickerDialog = PopupUtils.open(
229+ Qt.resolvedUrl("./CertPicker.qml")
230+ );
231+ pickerDialog.fileImportSignal.connect(function (file) {
232+ if (!file === false) {
233+ certDialogLoader.source = Qt.resolvedUrl(
234+ "./CertDialog.qml"
235+ );
236+ certDialog = PopupUtils.open(
237+ certDialogLoader.item, authListLabel, {
238+ fileName: file,
239+ certType: type
240+ }
241+ );
242+ certDialog.updateSignal.connect(function (update) {
243+ if (update && type === 0) {
244+ cacertListModel.dataupdate();
245+ } else if (update && type === 1) {
246+ privatekeyListModel.dataupdate();
247+ } else if (update && type === 2) {
248+ pacFileListModeL.dataupdate();
249+ }
250+ });
251+ }
252+ });
253 }
254
255 title: i18n.tr("Connect to Hidden Network")
256@@ -67,6 +99,14 @@
257 running: true
258 }
259 PropertyChanges {
260+ target: passwordRememberSwitch
261+ enabled: false
262+ }
263+ PropertyChanges {
264+ target: passwordRememberLabel
265+ opacity: 0.5
266+ }
267+ PropertyChanges {
268 target: passwordVisibleSwitch
269 enabled: false
270 }
271@@ -79,7 +119,103 @@
272 enabled: false
273 }
274 PropertyChanges {
275- target: passwordListLabel
276+ target: passwordLabel
277+ opacity: 0.5
278+ }
279+ PropertyChanges {
280+ target: username
281+ enabled: false
282+ }
283+ PropertyChanges {
284+ target: usernameLabel
285+ opacity: 0.5
286+ }
287+ PropertyChanges {
288+ target: anonymousIdentity
289+ enabled: false
290+ }
291+ PropertyChanges {
292+ target: anonymousIdentityLabel
293+ opacity: 0.5
294+ }
295+ PropertyChanges {
296+ target: peapVersionList
297+ enabled: false
298+ opacity: 0.5
299+ }
300+ PropertyChanges {
301+ target: peapVersionListLabel
302+ opacity: 0.5
303+ }
304+ PropertyChanges {
305+ target: pacProvisioningList
306+ enabled: false
307+ opacity: 0.5
308+ }
309+ PropertyChanges {
310+ target: pacProvisioningListLabel
311+ opacity: 0.5
312+ }
313+ PropertyChanges {
314+ target: pacFileSelector
315+ enabled: false
316+ opacity: 0.5
317+ }
318+ PropertyChanges {
319+ target: pacFileLabel
320+ opacity: 0.5
321+ }
322+ PropertyChanges {
323+ target: privateKeySelector
324+ enabled: false
325+ opacity: 0.5
326+ }
327+ PropertyChanges {
328+ target: privatekeyLabel
329+ opacity: 0.5
330+ }
331+ PropertyChanges {
332+ target: usercertSelector
333+ enabled: false
334+ opacity: 0.5
335+ }
336+ PropertyChanges {
337+ target: usercertLabel
338+ opacity: 0.5
339+ }
340+ PropertyChanges {
341+ target: cacertSelector
342+ enabled: false
343+ opacity: 0.5
344+ }
345+ PropertyChanges {
346+ target: cacertLabel
347+ opacity: 0.5
348+ }
349+ PropertyChanges {
350+ target: p2authList
351+ enabled: false
352+ opacity: 0.5
353+ }
354+ PropertyChanges {
355+ target: p2authListLabel
356+ opacity: 0.5
357+ }
358+ PropertyChanges {
359+ target: authList
360+ enabled: false
361+ opacity: 0.5
362+ }
363+ PropertyChanges {
364+ target: authListLabel
365+ opacity: 0.5
366+ }
367+ PropertyChanges {
368+ target: wepInsecureLabel
369+ opacity: 0.5
370+ }
371+ PropertyChanges {
372+ target: wepInsecureLabel
373 opacity: 0.5
374 }
375 PropertyChanges {
376@@ -117,10 +253,7 @@
377 target: successIndicator
378 running: true
379 }
380- PropertyChanges {
381- target: cancelButton
382- enabled: false
383- }
384+
385 PropertyChanges {
386 target: connectAction
387 enabled: false
388@@ -142,7 +275,7 @@
389 text : i18n.tr("Network name")
390 objectName: "networknameLabel"
391 fontSize: "medium"
392- font.bold: true
393+ font.bold: false
394 color: Theme.palette.selected.backgroundText
395 elide: Text.ElideRight
396 }
397@@ -150,6 +283,8 @@
398 TextField {
399 id : networkname
400 objectName: "networkname"
401+ width: parent.width
402+ placeholderText: i18n.tr("SSID")
403 inputMethodHints: Qt.ImhNoPredictiveText
404 Component.onCompleted: forceActiveFocus()
405 }
406@@ -159,7 +294,7 @@
407 text : i18n.tr("Security")
408 objectName: "securityListLabel"
409 fontSize: "medium"
410- font.bold: true
411+ font.bold: false
412 color: Theme.palette.selected.backgroundText
413 elide: Text.ElideRight
414 }
415@@ -167,18 +302,480 @@
416 ListItem.ItemSelector {
417 id: securityList
418 objectName: "securityList"
419- model: [i18n.tr("None"), // index: 0
420- i18n.tr("WPA & WPA2 Personal"), // index: 1
421- i18n.tr("WEP"), // index: 2
422- ]
423- }
424-
425- Label {
426- id: passwordListLabel
427- text : i18n.tr("Password")
428+ model: [i18n.tr("None"), // index: 0
429+ i18n.tr("WPA & WPA2 Personal"), // index: 1
430+ i18n.tr("WPA & WPA2 Enterprise"),// index: 2
431+ i18n.tr("WEP"), // index: 3
432+ i18n.tr("Dynamic WEP (802.1x)"), // index: 4
433+ i18n.tr("LEAP"), // index: 5
434+ ]
435+ selectedIndex: 1
436+ }
437+
438+ Label {
439+ id: wepInsecureLabel
440+ objectName: "wepInsecureLabel"
441+ color: "red"
442+ text: i18n.tr("This network is insecure.")
443+ visible: securityList.selectedIndex === 3
444+ }
445+
446+ Label {
447+ id: authListLabel
448+ text : i18n.tr("Authentication")
449+ objectName: "authListLabel"
450+ fontSize: "medium"
451+ font.bold: false
452+ color: Theme.palette.selected.backgroundText
453+ elide: Text.ElideRight
454+ visible: securityList.selectedIndex === 2 ||
455+ securityList.selectedIndex === 4
456+ }
457+
458+ ListItem.ItemSelector {
459+ id: authList
460+ objectName: "authList"
461+ model: ["TLS", // index: 0
462+ "TTLS", // index: 1
463+ "LEAP", // index: 2
464+ "FAST", // index: 3
465+ "PEAP", // index: 4
466+ ]
467+ visible: securityList.selectedIndex === 2 ||
468+ securityList.selectedIndex === 4
469+ }
470+
471+ Label {
472+ id: p2authListLabel
473+ text : i18n.tr("Inner authentication")
474+ objectName: "p2authLabel"
475+ fontSize: "medium"
476+ font.bold: false
477+ color: Theme.palette.selected.backgroundText
478+ elide: Text.ElideRight
479+ visible: (securityList.selectedIndex === 2 ||
480+ securityList.selectedIndex === 4 /* WPA or D-WEP */) &&
481+ (authList.selectedIndex === 1 ||
482+ authList.selectedIndex === 3 ||
483+ authList.selectedIndex === 4)
484+ }
485+
486+ ListItem.ItemSelector {
487+ id: p2authList
488+ objectName: "p2authList"
489+ width: parent.width
490+ model: ["PAP", // index: 0
491+ "MSCHAPv2", // index: 1
492+ "MSCHAP", // index: 2
493+ "CHAP", // index: 3
494+ "GTC", // index: 4
495+ "MD5" // index: 5
496+ ]
497+ visible: (securityList.selectedIndex === 2 ||
498+ securityList.selectedIndex === 4 /* WPA or D-WEP */) &&
499+ (authList.selectedIndex === 1 ||
500+ authList.selectedIndex === 3 ||
501+ authList.selectedIndex === 4)
502+ }
503+
504+ Label {
505+ id: cacertLabel
506+ text : i18n.tr("CA certificate")
507+ objectName: "cacertListLabel"
508+ fontSize: "medium"
509+ font.bold: false
510+ color: Theme.palette.selected.backgroundText
511+ visible: (securityList.selectedIndex === 2 ||
512+ securityList.selectedIndex === 4 /* WPA or D-WEP */) &&
513+ (authList.selectedIndex === 0 ||
514+ authList.selectedIndex === 1 ||
515+ authList.selectedIndex === 3 ||
516+ authList.selectedIndex === 4)
517+ }
518+
519+ ListItem.ItemSelector {
520+ id: cacertSelector
521+ anchors {
522+ left: parent.left
523+ right: parent.right
524+ }
525+ visible: (securityList.selectedIndex === 2 ||
526+ securityList.selectedIndex === 4 /* WPA or D-WEP */) &&
527+ (authList.selectedIndex === 0 ||
528+ authList.selectedIndex === 1 ||
529+ authList.selectedIndex === 3 ||
530+ authList.selectedIndex === 4)
531+ model: cacertListModel
532+ expanded: false
533+ delegate: certSelectorDelegate
534+ selectedIndex: 0
535+ property string cacertFileName: {
536+ if (selectedIndex !== 0 &&
537+ selectedIndex !== (cacertListModel.rowCount()-1)) {
538+ return cacertListModel.getfileName(selectedIndex);
539+ } else {
540+ return "";
541+ }
542+ }
543+
544+ onSelectedIndexChanged: {
545+ if (selectedIndex === cacertListModel.rowCount()-1) {
546+ selectedIndex = 0;
547+ otherNetworkDialog.filePicker(0); //Certificate
548+ }
549+ }
550+ }
551+
552+ Component {
553+ id: certSelectorDelegate
554+ OptionSelectorDelegate {
555+ text: {
556+ if (CommonName.length > 32) {
557+ /* TRANSLATORS: %1 is the name of a certificate file.
558+ The ellipsis indicates that the file name has been
559+ truncated to 30 characters. */
560+ return i18n.tr("%1…").arg(CommonName.substr(0,30));
561+ } else {
562+ return CommonName;
563+ }
564+ }
565+
566+ subText: {
567+ if (CommonName !== i18n.tr("None") &&
568+ CommonName !== i18n.tr("Choose…")) {
569+ if (Organization.length > 15) {
570+ /* TRANSLATORS: The first position is the name of
571+ the organization that has issued the certificate.
572+ The organization name has been truncated, as
573+ indicated by the ellipsis. The latter position is
574+ the expiry date of the certificate. */
575+ return i18n.tr("%1…, Exp.: %2").arg(
576+ Organization.substr(0,13)
577+ ).arg(expiryDate);
578+ } else {
579+ /* TRANSLATORS: The first position is the name of
580+ the organization that has issued the certificate.
581+ The latter position is the expiry date of the
582+ certificate. */
583+ return i18n.tr("%1, Exp.: %2").arg(Organization)
584+ .arg(expiryDate);
585+ }
586+ } else {
587+ return "";
588+ }
589+ }
590+ }
591+ }
592+
593+ CertificateListModel {
594+ id: cacertListModel
595+ }
596+
597+ Loader {
598+ id: certDialogLoader
599+ asynchronous: false
600+ }
601+
602+ Label {
603+ id: cacertHintLabel
604+ text : i18n.tr("Using certificates is recommend as it increases security.")
605+ wrapMode: Text.WordWrap
606+ opacity: 0.5
607+ objectName: "cacertHintLabel"
608+ fontSize: "small"
609+ font.bold: false
610+ color: Theme.palette.selected.backgroundText
611+ visible: (securityList.selectedIndex === 2 ||
612+ securityList.selectedIndex === 4 /* WPA or D-WEP */) &&
613+ (authList.selectedIndex === 0 ||
614+ authList.selectedIndex === 1 ||
615+ authList.selectedIndex === 3 ||
616+ authList.selectedIndex === 4) &&
617+ cacertSelector.selectedIndex === 0
618+ }
619+
620+ Label {
621+ id: usercertLabel
622+ text : i18n.tr("Client certificate")
623+ objectName: "usercertLabel"
624+ fontSize: "medium"
625+ font.bold: false
626+ color: Theme.palette.selected.backgroundText
627+ visible: (securityList.selectedIndex === 2 ||
628+ securityList.selectedIndex === 4) &&
629+ authList.selectedIndex === 0 // only for TLS
630+
631+ }
632+
633+ ListItem.ItemSelector {
634+ id: usercertSelector
635+ anchors {
636+ left: parent.left
637+ right: parent.right
638+ }
639+ visible: (securityList.selectedIndex === 2 ||
640+ securityList.selectedIndex === 4) &&
641+ authList.selectedIndex === 0 // only for TLS
642+ model: cacertListModel
643+ expanded: false
644+ delegate: certSelectorDelegate
645+ selectedIndex: 0
646+ property string usercertFileName: {
647+ if (selectedIndex !== 0 &&
648+ selectedIndex !== (model.rowCount()-1)) {
649+ return model.getfileName(selectedIndex);
650+ } else {
651+ return "";
652+ }
653+ }
654+ onSelectedIndexChanged: {
655+ if (selectedIndex === cacertListModel.rowCount()-1) {
656+ selectedIndex = 0;
657+ otherNetworkDialog.filePicker(0); //Certificate
658+ }
659+ }
660+ }
661+
662+ Label {
663+ id: privatekeyLabel
664+ text : i18n.tr("User private key")
665+ objectName: "userprivatekeyLabel"
666+ fontSize: "medium"
667+ font.bold: false
668+ color: Theme.palette.selected.backgroundText
669+ visible: (securityList.selectedIndex === 2 ||
670+ securityList.selectedIndex === 4) &&
671+ (authList.selectedIndex === 0) // only for TLS
672+ }
673+
674+ PrivatekeyListModel {
675+ id: privatekeyListModel
676+ }
677+
678+ Component{
679+ id: privatekeySelectorDelegate
680+ OptionSelectorDelegate {
681+ text: KeyName
682+
683+ subText: {
684+ if (KeyName !== i18n.tr("None") &&
685+ KeyName !== i18n.tr("Choose…")) {
686+ /* TRANSLATORS: The first position is the type of
687+ private key, second the key algorithm, and third the
688+ length of the key in bits. */
689+ return i18n.tr("%1, %2, %3 bit").arg(KeyType)
690+ .arg(KeyAlgorithm).arg(KeyLength);
691+ } else {
692+ return "";
693+ }
694+ }
695+ }
696+ }
697+
698+ ListItem.ItemSelector {
699+ id: privateKeySelector
700+ anchors {
701+ left: parent.left
702+ right: parent.right
703+ }
704+ visible: (securityList.selectedIndex === 2 ||
705+ securityList.selectedIndex === 4) &&
706+ (authList.selectedIndex === 0) // only for TLS
707+ model: privatekeyListModel
708+ expanded: false
709+ delegate: privatekeySelectorDelegate
710+ selectedIndex: 0
711+ property string privateKeyFileName: {
712+ if (selectedIndex !== 0 &&
713+ selectedIndex !==
714+ (model.rowCount()-1)) {
715+ return model.getfileName(
716+ selectedIndex
717+ );
718+ } else {
719+ return "";
720+ }
721+ }
722+ onSelectedIndexChanged: {
723+ if (selectedIndex === privatekeyListModel.rowCount()-1) {
724+ selectedIndex = 0;
725+ otherNetworkDialog.filePicker(1); //Key
726+ }
727+ }
728+ }
729+
730+ Label {
731+ id: pacFileLabel
732+ text : i18n.tr("Pac file")
733+ objectName: "pacFileLabel"
734+ fontSize: "medium"
735+ font.bold: false
736+ color: Theme.palette.selected.backgroundText
737+ visible: (securityList.selectedIndex === 2 ||
738+ securityList.selectedIndex === 4 /* WPA or D-WEP */) &&
739+ (authList.selectedIndex === 3)
740+ }
741+
742+ PacFileListModel {
743+ id: pacFileListModel
744+ }
745+
746+ Component{
747+ id: pacFileSelectorDelegate
748+ OptionSelectorDelegate { text: pacFileName; }
749+ }
750+
751+ ListItem.ItemSelector {
752+ id: pacFileSelector
753+ anchors {
754+ left: parent.left
755+ right: parent.right
756+ }
757+ visible: (securityList.selectedIndex === 2 ||
758+ securityList.selectedIndex === 4) &&
759+ (authList.selectedIndex === 3) // only for FAST
760+ model: pacFileListModel
761+ expanded: false
762+ delegate: pacFileSelectorDelegate
763+ selectedIndex: 0
764+ property string pacFileName: {
765+ if (selectedIndex !== 0 &&
766+ selectedIndex !== (pacFileListModel.rowCount()-1)) {
767+ return pacFileListModel.getfileName(selectedIndex);
768+ } else {
769+ return "";
770+ }
771+ }
772+ onSelectedIndexChanged: {
773+ if (selectedIndex === pacFileListModel.rowCount()-1) {
774+ selectedIndex = 0;
775+ otherNetworkDialog.filePicker(2); //PacFile
776+ }
777+ }
778+ }
779+
780+ Label {
781+ id: pacProvisioningListLabel
782+ text : i18n.tr("Pac provisioning")
783+ objectName: "pacProvisioningListLabel"
784+ fontSize: "medium"
785+ font.bold: false
786+ color: Theme.palette.selected.backgroundText
787+ elide: Text.ElideRight
788+ visible: (securityList.selectedIndex === 2 ||
789+ securityList.selectedIndex === 4) &&
790+ (authList.selectedIndex === 3)
791+ }
792+
793+ ListItem.ItemSelector {
794+ id: pacProvisioningList
795+ objectName: "pacProvisioningList"
796+ model: [i18n.tr("Disabled"), // index: 0
797+ i18n.tr("Anonymous"), // index: 1
798+ i18n.tr("Authenticated"), // index: 2
799+ i18n.tr("Both"), // index: 3
800+ ]
801+ selectedIndex: 1
802+ visible: (securityList.selectedIndex === 2 ||
803+ securityList.selectedIndex === 4) &&
804+ (authList.selectedIndex === 3)
805+ }
806+
807+ Label {
808+ id: peapVersionListLabel
809+ text : i18n.tr("PEAP version")
810+ objectName: "peapVersionListLabel"
811+ fontSize: "medium"
812+ font.bold: false
813+ color: Theme.palette.selected.backgroundText
814+ elide: Text.ElideRight
815+ visible: (securityList.selectedIndex === 2 ||
816+ securityList.selectedIndex === 4) &&
817+ (authList.selectedIndex === 4)
818+ }
819+
820+ ListItem.ItemSelector {
821+ id: peapVersionList
822+ objectName: "peapVersionList"
823+ model: [i18n.tr("Version 0"), // index: 0
824+ i18n.tr("Version 1"), // index: 1
825+ i18n.tr("Automatic"), // index: 2
826+ ]
827+ visible: (securityList.selectedIndex === 2 ||
828+ securityList.selectedIndex === 4) &&
829+ (authList.selectedIndex === 4)
830+ selectedIndex: 2
831+ }
832+
833+ Label {
834+ id: anonymousIdentityLabel
835+ text : i18n.tr("Anonymous identity")
836+ objectName: "anonymousIdentityLabel"
837+ fontSize: "medium"
838+ font.bold: false
839+ color: Theme.palette.selected.backgroundText
840+ visible: (securityList.selectedIndex === 2 &&
841+ authList.selectedIndex !== 2)
842+ }
843+
844+ TextField {
845+ id : anonymousIdentity
846+ objectName: "anonymousIdentity"
847+ width: parent.width
848+ visible: (securityList.selectedIndex === 2 &&
849+ authList.selectedIndex !== 2)
850+ inputMethodHints: Qt.ImhNoPredictiveText
851+ onAccepted: {
852+ connectAction.trigger()
853+ }
854+ }
855+
856+ Label {
857+ id: usernameLabel
858+ text : {
859+ if ((securityList.selectedIndex === 2 ||
860+ securityList.selectedIndex === 4) &&
861+ (authList.selectedIndex === 0 )) {
862+ return i18n.tr("Identity");
863+ } else {
864+ return i18n.tr("Username");
865+ }
866+ }
867+ objectName: "usernameLabel"
868+ fontSize: "medium"
869+ font.bold: false
870+ color: Theme.palette.selected.backgroundText
871+ elide: Text.ElideRight
872+ visible: (securityList.selectedIndex === 2 ||
873+ securityList.selectedIndex === 4 ||
874+ securityList.selectedIndex === 5)
875+ }
876+
877+ TextField {
878+ id : username
879+ objectName: "username"
880+ width: parent.width
881+ visible: (securityList.selectedIndex === 2 ||
882+ securityList.selectedIndex === 4 ||
883+ securityList.selectedIndex === 5)
884+ inputMethodHints: Qt.ImhNoPredictiveText
885+ onAccepted: connectAction.trigger()
886+ }
887+
888+ Label {
889+ id: passwordLabel
890+ text: {
891+ if ((securityList.selectedIndex === 2 ||
892+ securityList.selectedIndex === 4) &&
893+ (authList.selectedIndex === 0)) {
894+ return i18n.tr("Private key password");
895+ } else {
896+ return i18n.tr("Password");
897+ }
898+ }
899 objectName: "passwordListLabel"
900 fontSize: "medium"
901- font.bold: true
902+ font.bold: false
903 color: Theme.palette.selected.backgroundText
904 elide: Text.ElideRight
905 visible: securityList.selectedIndex !== 0
906@@ -187,16 +784,15 @@
907 TextField {
908 id : password
909 objectName: "password"
910+ width: parent.width
911 visible: securityList.selectedIndex !== 0
912 echoMode: passwordVisibleSwitch.checked ?
913- TextInput.Normal : TextInput.Password
914+ TextInput.Normal : TextInput.Password
915 inputMethodHints: Qt.ImhNoPredictiveText
916- onAccepted: {
917- connectAction.trigger();
918- }
919+ onAccepted: connectAction.trigger()
920 }
921
922- Row {
923+ Row {
924 id: passwordVisiblityRow
925 layoutDirection: Qt.LeftToRight
926 spacing: units.gu(2)
927@@ -222,7 +818,43 @@
928 }
929 onClicked: {
930 passwordVisibleSwitch.checked =
931- !passwordVisibleSwitch.checked
932+ !passwordVisibleSwitch.checked
933+ }
934+ }
935+ }
936+ }
937+
938+ Row {
939+ id: passwordRememberRow
940+ layoutDirection: Qt.LeftToRight
941+ spacing: units.gu(2)
942+ visible: ((securityList.selectedIndex === 2 ||
943+ securityList.selectedIndex === 4) &&
944+ (authList.selectedIndex === 1 ||
945+ authList.selectedIndex === 3 ||
946+ authList.selectedIndex === 4))
947+
948+ CheckBox {
949+ id: passwordRememberSwitch
950+ activeFocusOnPress: false
951+ }
952+
953+ Label {
954+ id: passwordRememberLabel
955+ text : i18n.tr("Remember password")
956+ objectName: "passwordRememberLabel"
957+ fontSize: "medium"
958+ color: Theme.palette.selected.backgroundText
959+ elide: Text.ElideRight
960+ height: passwordRememberSwitch.height
961+ verticalAlignment: Text.AlignVCenter
962+ MouseArea {
963+ anchors {
964+ fill: parent
965+ }
966+ onClicked: {
967+ passwordRememberSwitch.checked =
968+ !passwordRememberSwitch.checked
969 }
970 }
971 }
972@@ -289,7 +921,24 @@
973 DbusHelper.connect(
974 networkname.text,
975 securityList.selectedIndex,
976- password.text);
977+ authList.selectedIndex,
978+ [
979+ username.text,
980+ anonymousIdentity.text
981+ ],
982+ [
983+ password.text,
984+ passwordRememberSwitch.checked
985+ ],
986+ [
987+ cacertSelector.cacertFileName,
988+ usercertSelector.usercertFileName,
989+ privateKeySelector.privateKeyFileName,
990+ pacFileSelector.pacFileName,
991+ pacProvisioningList.selectedIndex.toString(),
992+ peapVersionList.selectedIndex.toString()
993+ ],
994+ p2authList.selectedIndex);
995 otherNetworkDialog.state = "CONNECTING";
996 }
997 }
998@@ -321,19 +970,18 @@
999 */
1000 if (otherNetworkDialog.state === "CONNECTING") {
1001 switch (newState) {
1002- case 120:
1003- feedback.text = common.reasonToString(reason);
1004- otherNetworkDialog.state = "FAILED";
1005- break;
1006- case 100:
1007- /* connection succeeded only if it was us that
1008+ case 120:
1009+ feedback.text = common.reasonToString(reason);
1010+ otherNetworkDialog.state = "FAILED";
1011+ break;
1012+ case 100:
1013+ /* connection succeeded only if it was us that
1014 created it */
1015- otherNetworkDialog.state = "SUCCEEDED";
1016- break;
1017+ otherNetworkDialog.state = "SUCCEEDED";
1018+ break;
1019 }
1020 }
1021 }
1022 }
1023 }
1024 }
1025-
1026
1027=== added file 'plugins/wifi/certhandler.cpp'
1028--- plugins/wifi/certhandler.cpp 1970-01-01 00:00:00 +0000
1029+++ plugins/wifi/certhandler.cpp 2015-07-01 18:56:14 +0000
1030@@ -0,0 +1,348 @@
1031+#include "certhandler.h"
1032+
1033+#include <QtQml>
1034+#include <QtQml/QQmlContext>
1035+#include <QtDebug>
1036+#include <QObject>
1037+#include <QSslCertificate>
1038+#include <QSslKey>
1039+#include <QAbstractListModel>
1040+#include <QDir>
1041+#include <QFile>
1042+
1043+
1044+QString appPath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
1045+#define CERTS_PATH appPath +"/wifi/ssl/certs/"
1046+#define KEYS_PATH appPath +"/wifi/ssl/private/"
1047+#define PACS_PATH appPath +"/wifi/ssl/pac/"
1048+
1049+#include <libintl.h>
1050+QString _(const char *text){
1051+ return QString::fromUtf8(dgettext(0, text));
1052+}
1053+
1054+QByteArray FileHandler::getCertContent(QString filename){
1055+ QFile file(filename);
1056+ if (!file.open(QIODevice::ReadOnly)) {
1057+ qWarning() << "Could not resolve File (" << filename << "): File does not exist or is empty." ;
1058+ return QByteArray();
1059+ }
1060+ else {
1061+ return file.readAll();
1062+ }
1063+}
1064+
1065+QString FileHandler::moveCertFile(QString filename){
1066+ QDir certPath(CERTS_PATH);
1067+ if (!certPath.exists(CERTS_PATH)){
1068+ certPath.mkpath(CERTS_PATH);
1069+ }
1070+ QFile file(filename);
1071+ QByteArray certificate = getCertContent(filename);
1072+ QList<QSslCertificate> SslCertificateList = QSslCertificate::fromData(certificate, QSsl::Pem);
1073+ if ( !SslCertificateList.isEmpty() ){
1074+ QStringList subject = SslCertificateList[0].subjectInfo(QSslCertificate::CommonName);
1075+ QString modFileName = CERTS_PATH+subject[0]+".pem";
1076+ if(file.rename(modFileName.replace(" ", "_"))){
1077+ return file.fileName();
1078+ } else {
1079+ return "";
1080+ }
1081+ }
1082+ return "";
1083+}
1084+
1085+QString FileHandler::moveKeyFile(QString filename){
1086+ QDir keyPath(KEYS_PATH);
1087+ if (!keyPath.exists(KEYS_PATH)){
1088+ keyPath.mkpath(KEYS_PATH);
1089+ }
1090+ QFile file(filename);
1091+ file.open(QIODevice::ReadOnly);
1092+ QSslKey checkKey(file.readAll(), QSsl::Rsa);
1093+ file.close();
1094+ if ( !checkKey.isNull() ){
1095+ QFileInfo fileInfo(file);
1096+ QString modFileName = KEYS_PATH + fileInfo.fileName().replace(" ", "_");
1097+ if(file.rename(modFileName)){
1098+ return file.fileName();
1099+ } else {
1100+ return "" ;
1101+ }
1102+ }
1103+ return "";
1104+}
1105+
1106+QString FileHandler::movePacFile(QString filename){
1107+ QDir keyPath(PACS_PATH);
1108+ if (!keyPath.exists(PACS_PATH)){
1109+ keyPath.mkpath(PACS_PATH);
1110+ }
1111+ QFile file(filename);
1112+ QFileInfo fileInfo(file);
1113+ QString modFileName = PACS_PATH + fileInfo.baseName().replace(" ", "_") + ".pac";
1114+ if(file.rename(modFileName)){
1115+ return file.fileName();
1116+ }
1117+ return "" ;
1118+}
1119+
1120+bool FileHandler::removeFile(QString filename){
1121+ QFile file(filename);
1122+ return file.remove();
1123+}
1124+
1125+struct CertificateListModel::Private {
1126+ QStringList data;
1127+};
1128+
1129+CertificateListModel::CertificateListModel(QObject *parent) : QAbstractListModel(parent) {
1130+ p = new CertificateListModel::Private();
1131+ QStringList nameFilter("*.pem");
1132+ QDir directory(CERTS_PATH);
1133+ QStringList files = directory.entryList(nameFilter);
1134+ files.sort(Qt::CaseInsensitive);
1135+ files.insert(0, _("None") );
1136+ files.append( _("Choose…") );
1137+ p->data = files;
1138+}
1139+
1140+CertificateListModel::~CertificateListModel() {
1141+ delete p;
1142+}
1143+
1144+QHash<int, QByteArray> CertificateListModel::roleNames() const {
1145+ QHash<int, QByteArray> roles;
1146+ roles[CNRole] = "CommonName";
1147+ roles[ORole] = "Organization";
1148+ roles[expDateRole] = "expiryDate";
1149+
1150+ //roles[certFileNameRole] = "certFileName";
1151+ //...more if needed see QSslCertificate::SubjectInfo
1152+ return roles;
1153+}
1154+
1155+int CertificateListModel::rowCount(const QModelIndex &/*parent*/) const {
1156+ return p->data.size();
1157+}
1158+
1159+QString CertificateListModel::getfileName(const int selectedIndex) const {
1160+ return CERTS_PATH + p->data[selectedIndex];
1161+}
1162+
1163+void CertificateListModel::dataupdate(){
1164+ beginResetModel();
1165+ p->data.clear();
1166+ QStringList nameFilter("*.pem");
1167+ QDir directory(CERTS_PATH);
1168+ QStringList files = directory.entryList(nameFilter);
1169+ files.sort(Qt::CaseInsensitive);
1170+ files.insert(0, _("None") );
1171+ files.append( _("Choose…") );
1172+ p->data = files;
1173+ endResetModel();
1174+}
1175+
1176+QVariant CertificateListModel::data(const QModelIndex &index, int role) const {
1177+ if(!index.isValid() || index.row() >= ( p->data.size()) ) {
1178+ return QVariant();
1179+ } else if (index.row() == 0){
1180+ const QString &row0 = p->data[index.row()];
1181+
1182+ switch(role) {
1183+ case CNRole : return row0;
1184+ case ORole : return "";
1185+ case expDateRole : return "";
1186+
1187+ }
1188+ } else if (index.row() == p->data.size()-1){
1189+ const QString &rowend = p->data[index.row()];
1190+
1191+ switch(role) {
1192+ case CNRole : return rowend;
1193+ case ORole : return "";
1194+ case expDateRole : return "";
1195+ }
1196+ }
1197+
1198+ const QString &row = CERTS_PATH+p->data[index.row()];
1199+ QList<QSslCertificate> certificate = QSslCertificate::fromPath(row, QSsl::Pem, QRegExp::Wildcard);
1200+
1201+ switch(role) {
1202+
1203+ case CNRole : return certificate[0].subjectInfo(QSslCertificate::CommonName)[0];
1204+ case ORole : return certificate[0].subjectInfo(QSslCertificate::Organization)[0];
1205+ case expDateRole : return certificate[0].expiryDate().toString("dd.MM.yyyy");
1206+
1207+ default : return QVariant();
1208+ }
1209+}
1210+
1211+/***************************************/
1212+
1213+struct PrivatekeyListModel::Private {
1214+ QStringList data;
1215+};
1216+
1217+PrivatekeyListModel::PrivatekeyListModel(QObject *parent) : QAbstractListModel(parent) {
1218+ p = new PrivatekeyListModel::Private();
1219+ QDir directory(KEYS_PATH);
1220+ QStringList files = directory.entryList(QDir::Files, QDir::Name);
1221+ files.sort(Qt::CaseInsensitive);
1222+ files.insert(0, _("None") );
1223+ files.append( _("Choose…") );
1224+ p->data = files;
1225+}
1226+
1227+PrivatekeyListModel::~PrivatekeyListModel() {
1228+ delete p;
1229+}
1230+
1231+QHash<int, QByteArray> PrivatekeyListModel::roleNames() const {
1232+ QHash<int, QByteArray> roles;
1233+ roles[keyName] = "KeyName";
1234+ roles[keyType] = "KeyType";
1235+ roles[keyAlgorithm] = "KeyAlgorithm";
1236+ roles[keyLength] = "KeyLength";
1237+ return roles;
1238+}
1239+
1240+int PrivatekeyListModel::rowCount(const QModelIndex &/*parent*/) const {
1241+ return p->data.size();
1242+}
1243+
1244+QString PrivatekeyListModel::getfileName(const int selectedIndex) const {
1245+ return KEYS_PATH + p->data[selectedIndex];
1246+}
1247+
1248+void PrivatekeyListModel::dataupdate(){
1249+ beginResetModel();
1250+ p->data.clear();
1251+ QDir directory(KEYS_PATH);
1252+ QStringList files = directory.entryList(QDir::Files, QDir::Name);
1253+ files.sort(Qt::CaseInsensitive);
1254+ files.insert(0, _("None") );
1255+ files.append( _("Choose…") );
1256+ p->data = files;
1257+ endResetModel();
1258+}
1259+
1260+QVariant PrivatekeyListModel::data(const QModelIndex &index, int role) const {
1261+ if(!index.isValid() || index.row() >= ( p->data.size()) ) {
1262+ return QVariant();
1263+ } else if (index.row() == 0){
1264+ const QString &row0 = p->data[index.row()];
1265+
1266+ switch(role) {
1267+ case keyName : return row0; // returns "None"
1268+ case keyType : return "";
1269+ case keyAlgorithm : return "";
1270+ case keyLength : return "";
1271+ }
1272+ } else if (index.row() == p->data.size()-1){
1273+ const QString &rowend = p->data[index.row()];
1274+
1275+ switch(role) {
1276+ case keyName : return rowend; // returns "Choose file...
1277+ case keyType : return "";
1278+ case keyAlgorithm : return "";
1279+ case keyLength : return "";
1280+ }
1281+ }
1282+
1283+ const QString &row = KEYS_PATH+p->data[index.row()];
1284+ QFile keyFile(row);
1285+ keyFile.open(QIODevice::ReadOnly);
1286+ QSslKey privateKey( keyFile.readAll(), QSsl::Rsa );
1287+ QString type;
1288+ if (privateKey.type() == 0){ type = _("Private key");}
1289+ else { type = _("Public key"); }
1290+
1291+ QString algorithm;
1292+ if (privateKey.algorithm() == 1) { algorithm = "RSA";}
1293+ else if (privateKey.algorithm() == 2){ algorithm = "DSA";}
1294+ else { algorithm = _("Opaque");}
1295+
1296+ QFileInfo keyFileInfo(keyFile);
1297+ switch(role) {
1298+
1299+ case keyName : return keyFileInfo.fileName();
1300+ case keyType : return type;
1301+ case keyAlgorithm : return algorithm;
1302+ case keyLength : return privateKey.length();
1303+
1304+ default : return QVariant();
1305+ }
1306+}
1307+
1308+/***************************************/
1309+
1310+struct PacFileListModel::Private {
1311+ QStringList data;
1312+};
1313+
1314+PacFileListModel::PacFileListModel(QObject *parent) : QAbstractListModel(parent) {
1315+ p = new PacFileListModel::Private();
1316+ QDir directory(PACS_PATH);
1317+ QStringList files = directory.entryList(QDir::Files, QDir::Name);
1318+ files.sort(Qt::CaseInsensitive);
1319+ files.insert(0, _("None") );
1320+ files.append( _("Choose…") );
1321+ p->data = files;
1322+}
1323+
1324+PacFileListModel::~PacFileListModel() {
1325+ delete p;
1326+}
1327+
1328+QHash<int, QByteArray> PacFileListModel::roleNames() const {
1329+ QHash<int, QByteArray> roles;
1330+ roles[pacFileName] = "pacFileName";
1331+ return roles;
1332+}
1333+
1334+int PacFileListModel::rowCount(const QModelIndex &/*parent*/) const {
1335+ return p->data.size();
1336+}
1337+
1338+QString PacFileListModel::getfileName(const int selectedIndex) const {
1339+ return PACS_PATH + p->data[selectedIndex];
1340+}
1341+
1342+void PacFileListModel::dataupdate(){
1343+ beginResetModel();
1344+ p->data.clear();
1345+ QDir directory(PACS_PATH);
1346+ QStringList files = directory.entryList(QDir::Files, QDir::Name);
1347+ files.sort(Qt::CaseInsensitive);
1348+ files.insert(0, _("None") );
1349+ files.append( _("Choose…") );
1350+ p->data = files;
1351+ endResetModel();
1352+}
1353+
1354+QVariant PacFileListModel::data(const QModelIndex &index, int role) const {
1355+ if(!index.isValid() || index.row() >= ( p->data.size()) ) {
1356+ return QVariant();
1357+ } else if (index.row() == 0){
1358+ const QString &row0 = p->data[index.row()];
1359+
1360+ switch(role) {
1361+ case pacFileName : return row0; // returns "None"
1362+ }
1363+ } else if (index.row() == p->data.size()-1){
1364+ const QString &rowend = p->data[index.row()];
1365+
1366+ switch(role) {
1367+ case pacFileName : return rowend; // returns "Choose file...
1368+ }
1369+ }
1370+
1371+ const QString &name = p->data[index.row()];
1372+ switch(role) {
1373+
1374+ case pacFileName : return name;
1375+
1376+ default : return QVariant();
1377+ }
1378+}
1379
1380=== added file 'plugins/wifi/certhandler.h'
1381--- plugins/wifi/certhandler.h 1970-01-01 00:00:00 +0000
1382+++ plugins/wifi/certhandler.h 2015-07-01 18:56:14 +0000
1383@@ -0,0 +1,98 @@
1384+#ifndef CERTHANDLER_H
1385+#define CERTHANDLER_H
1386+
1387+#include <QtQml>
1388+#include <QtQml/QQmlContext>
1389+#include <QObject>
1390+#include <QAbstractListModel>
1391+
1392+class FileHandler : public QObject
1393+{
1394+ Q_OBJECT
1395+public:
1396+ Q_INVOKABLE QByteArray getCertContent(QString filename);
1397+ Q_INVOKABLE QString moveCertFile(QString filename);
1398+ Q_INVOKABLE QString moveKeyFile(QString filename);
1399+ Q_INVOKABLE QString movePacFile(QString filename);
1400+ Q_INVOKABLE bool removeFile(QString filename);
1401+};
1402+
1403+
1404+
1405+class CertificateListModel : public QAbstractListModel
1406+{
1407+ Q_OBJECT
1408+
1409+public:
1410+ enum CertificateListRoles {
1411+ CNRole = Qt::UserRole + 1,
1412+ ORole,
1413+ expDateRole,
1414+ //certFileNameRole,
1415+ };
1416+
1417+ explicit CertificateListModel(QObject *parent = 0);
1418+ ~CertificateListModel();
1419+ QHash<int, QByteArray> roleNames() const;
1420+ Q_INVOKABLE int rowCount(const QModelIndex &parent = QModelIndex()) const;
1421+ Q_INVOKABLE QString getfileName(const int selectedIndex) const;
1422+ Q_INVOKABLE void dataupdate();
1423+ QVariant data(const QModelIndex &index, int role) const;
1424+
1425+private:
1426+ struct Private;
1427+ Private *p;
1428+
1429+};
1430+
1431+class PrivatekeyListModel : public QAbstractListModel
1432+{
1433+ Q_OBJECT
1434+
1435+public:
1436+ enum PrivatekeyListRoles {
1437+ keyName = Qt::UserRole + 1,
1438+ keyType,
1439+ keyAlgorithm,
1440+ keyLength,
1441+ };
1442+
1443+ explicit PrivatekeyListModel(QObject *parent = 0);
1444+ ~PrivatekeyListModel();
1445+ QHash<int, QByteArray> roleNames() const;
1446+ Q_INVOKABLE int rowCount(const QModelIndex &parent = QModelIndex()) const;
1447+ Q_INVOKABLE QString getfileName(const int selectedIndex) const;
1448+ Q_INVOKABLE void dataupdate();
1449+ QVariant data(const QModelIndex &index, int role) const;
1450+private:
1451+ struct Private;
1452+ Private *p;
1453+
1454+};
1455+
1456+class PacFileListModel : public QAbstractListModel
1457+{
1458+ Q_OBJECT
1459+
1460+public:
1461+ enum PacFileListRoles {
1462+ pacFileName = Qt::UserRole + 1,
1463+
1464+ };
1465+
1466+ explicit PacFileListModel(QObject *parent = 0);
1467+ ~PacFileListModel();
1468+ QHash<int, QByteArray> roleNames() const;
1469+ Q_INVOKABLE int rowCount(const QModelIndex &parent = QModelIndex()) const;
1470+ Q_INVOKABLE QString getfileName(const int selectedIndex) const;
1471+ Q_INVOKABLE void dataupdate();
1472+ QVariant data(const QModelIndex &index, int role) const;
1473+private:
1474+ struct Private;
1475+ Private *p;
1476+
1477+};
1478+
1479+
1480+#endif // CERTHANDLER_H
1481+
1482
1483=== modified file 'plugins/wifi/plugin.cpp'
1484--- plugins/wifi/plugin.cpp 2014-07-23 13:53:48 +0000
1485+++ plugins/wifi/plugin.cpp 2015-07-01 18:56:14 +0000
1486@@ -22,6 +22,7 @@
1487 #include "unitymenumodelstack.h"
1488 #include "wifidbushelper.h"
1489 #include "previousnetworkmodel.h"
1490+#include "certhandler.h"
1491
1492 namespace {
1493
1494@@ -45,6 +46,10 @@
1495 qmlRegisterType<UnityMenuModelStack>(uri, 1, 0, "UnityMenuModelStack");
1496 qmlRegisterSingletonType<WifiDbusHelper>(uri, 1, 0, "DbusHelper", dbusProvider);
1497 qmlRegisterType<PreviousNetworkModel>(uri, 1, 0, "PreviousNetworkModel");
1498+ qmlRegisterType<CertificateListModel>(uri, 1, 0, "CertificateListModel");
1499+ qmlRegisterType<PrivatekeyListModel>(uri, 1, 0, "PrivatekeyListModel");
1500+ qmlRegisterType<PacFileListModel>(uri, 1, 0, "PacFileListModel");
1501+ qmlRegisterType<FileHandler>(uri, 1, 0, "FileHandler");
1502 }
1503
1504 void BackendPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
1505
1506=== modified file 'plugins/wifi/wifidbushelper.cpp'
1507--- plugins/wifi/wifidbushelper.cpp 2015-04-07 20:45:40 +0000
1508+++ plugins/wifi/wifidbushelper.cpp 2015-07-01 18:56:14 +0000
1509@@ -40,14 +40,14 @@
1510 Q_DECLARE_METATYPE(ConfigurationData)
1511
1512 WifiDbusHelper::WifiDbusHelper(QObject *parent) : QObject(parent),
1513- m_systemBusConnection(QDBusConnection::systemBus())
1514+ m_systemBusConnection(QDBusConnection::systemBus())
1515 {
1516 qDBusRegisterMetaType<ConfigurationData>();
1517 }
1518
1519-void WifiDbusHelper::connect(QString ssid, int security, QString password)
1520+void WifiDbusHelper::connect(QString ssid, int security, int auth, QStringList usernames, QStringList password, QStringList certs, int p2auth)
1521 {
1522- if(security<0 || security>2) {
1523+ if((security<0 || security>5) || (auth<0 || auth>4) || (p2auth<0 || p2auth>5)) {
1524 qWarning() << "Qml and C++ have gotten out of sync. Can't connect.\n";
1525 return;
1526 }
1527@@ -68,26 +68,116 @@
1528 // security:
1529 // 0: None
1530 // 1: WPA & WPA2 Personal
1531- // 2: WEP
1532- if (security != 0) {
1533+ // 2: WPA Enterprise
1534+ // 3: WEP
1535+ // 4: Dynamic WEP
1536+ // 5: LEAP
1537+ if (security != 0) { // WPA Enterprise or Dynamic WEP
1538 wireless["security"] = QStringLiteral("802-11-wireless-security");
1539
1540 QVariantMap wireless_security;
1541
1542 if (security == 1) {
1543 wireless_security["key-mgmt"] = QStringLiteral("wpa-psk");
1544- wireless_security["psk"] = password;
1545- } else if (security == 2) {
1546+ wireless_security["psk"] = password[0];
1547+ } else if (security == 3) {
1548 wireless_security["key-mgmt"] = QStringLiteral("none");
1549 wireless_security["auth-alg"] = QStringLiteral("open");
1550- wireless_security["wep-key0"] = password;
1551+ wireless_security["wep-key0"] = password[0];
1552 wireless_security["wep-key-type"] = QVariant(uint(1));
1553+ } else if (security == 2) {
1554+ wireless_security["key-mgmt"] = QStringLiteral("wpa-eap");
1555+ } else if (security == 4) {
1556+ wireless_security["key-mgmt"] = QStringLiteral("ieee8021x");
1557+ /* leave disabled as hopefully not needed:
1558+ QStringList wep_pairwise, wep_group;
1559+ wep_pairwise[0] ="wep40"; wep_pairwise[1] ="wep104";
1560+ wep_group[0] ="wep40"; wep_group[1] ="wep104";
1561+ wireless_security["pairwise"] = wep_pairwise;
1562+ wireless_security["group"] = wep_group; */
1563+ } else if (security == 5) {
1564+ wireless_security["key-mgmt"] = QStringLiteral("ieee8021x");
1565+ wireless_security["auth-alg"] = QStringLiteral("leap");
1566+ wireless_security["leap-username"] = usernames[0];
1567+ wireless_security["leap-password"] = password[0];
1568 }
1569 configuration["802-11-wireless-security"] = wireless_security;
1570 }
1571
1572 configuration["802-11-wireless"] = wireless;
1573
1574+ if (security == 2 || security == 4){
1575+
1576+ QVariantMap wireless_802_1x;
1577+ // [802-1x]
1578+ /*TLS // index: 0
1579+ TTLS // index: 1
1580+ LEAP // index: 2
1581+ FAST // index: 3
1582+ PEAP // index: 4 */
1583+ wireless_802_1x["identity"] = usernames[0];
1584+ if (auth != 0) {
1585+ wireless_802_1x["password"] = password[0];
1586+ }
1587+
1588+ QByteArray cacert( "file://" + certs[0].toUtf8() + '\0');
1589+ QByteArray clientcert("file://" + certs[1].toUtf8() + '\0');
1590+ QByteArray privatekey("file://" + certs[2].toUtf8() + '\0');
1591+ QString pacFile( certs[3] );
1592+
1593+ if (auth == 0) { // TLS
1594+ wireless_802_1x["eap"] = QStringList("tls");
1595+ if (certs[0] != "") {wireless_802_1x["ca-cert"] = cacert;}
1596+ if (certs[1] != "") {wireless_802_1x["client-cert"] = clientcert;}
1597+ if (certs[2] != "") {wireless_802_1x["private-key"] = privatekey;}
1598+ wireless_802_1x["private-key-password"] = password[0];
1599+ } else if (auth == 1) { // TTLS
1600+ wireless_802_1x["eap"] = QStringList("ttls");
1601+ if (certs[0] != "") {wireless_802_1x["ca-cert"] = cacert;}
1602+ if (usernames[1] != "") {wireless_802_1x["anonymous-identity"] = usernames[1];}
1603+ if (password[1] == "false") {wireless_802_1x["password-flags"] = uint(2);}
1604+ } else if (auth == 2) { // LEAP
1605+ wireless_802_1x["eap"] = QStringList("leap");
1606+ } else if (auth == 3) { // FAST
1607+ wireless_802_1x["eap"] = QStringList("fast");
1608+ if (certs[0] != "") {wireless_802_1x["ca-cert"] = cacert;}
1609+ if (usernames[1] != "") {wireless_802_1x["anonymous-identity"] = usernames[1];}
1610+ if (password[1] == "false") {wireless_802_1x["password-flags"] = uint(2);}
1611+ if (certs[3] != "" ) {wireless_802_1x["pac-file"] = pacFile;}
1612+ wireless_802_1x["phase1-fast-provisioning"] = certs[4];
1613+ } else if (auth == 4) { // PEAP
1614+ wireless_802_1x["eap"] = QStringList("peap");
1615+ if (certs[0] != "") {wireless_802_1x["ca-cert"] = cacert;}
1616+ if (usernames[1] != "") {wireless_802_1x["anonymous-identity"] = usernames[1];}
1617+ if (password[1] == "false") {wireless_802_1x["password-flags"] = uint(2);}
1618+ if (certs[5] != "2") {wireless_802_1x["phase1-peapver"] = certs[5]; }
1619+ // wireless_802_1x["phase1-peaplabel"] = QString("1"); #jkb:let us unset this until problems are reported.
1620+ }
1621+
1622+ if (auth == 1 || auth == 3 || auth == 4 ){ // only for TTLS, FAST and PEAP
1623+ /* PAP // index: 0
1624+ MSCHAPv2 // index: 1
1625+ MSCHAP // index: 2
1626+ CHAP // index: 3
1627+ GTC // index: 4
1628+ MD5 // index: 5 */
1629+ if (p2auth == 0) {
1630+ wireless_802_1x["phase2-auth"] = QStringLiteral("pap");
1631+ } else if (p2auth == 1) {
1632+ wireless_802_1x["phase2-auth"] = QStringLiteral("mschapv2");
1633+ } else if (p2auth == 2) {
1634+ wireless_802_1x["phase2-auth"] = QStringLiteral("mschap");
1635+ } else if (p2auth == 3) {
1636+ wireless_802_1x["phase2-auth"] = QStringLiteral("chap");
1637+ } else if (p2auth == 4) {
1638+ wireless_802_1x["phase2-auth"] = QStringLiteral("gtc");
1639+ } else if (p2auth == 5) {
1640+ wireless_802_1x["phase2-auth"] = QStringLiteral("md5");
1641+ }
1642+ }
1643+ configuration["802-1x"] = wireless_802_1x;
1644+ }
1645+
1646 // find the first wlan adapter for now
1647 auto reply1 = mgr.GetDevices();
1648 reply1.waitForFinished();
1649@@ -184,9 +274,10 @@
1650 }
1651 }
1652
1653+
1654 void WifiDbusHelper::nmDeviceStateChanged(uint newState,
1655- uint oldState,
1656- uint reason)
1657+ uint oldState,
1658+ uint reason)
1659 {
1660 Q_UNUSED (oldState);
1661 Q_EMIT (deviceStateChanged(newState, reason));
1662@@ -329,15 +420,22 @@
1663 // If the connection has never been activated succesfully there is a
1664 // high chance that it has no stored secrects.
1665 if (timestamp != 0) {
1666- auto reply = m_iface.GetSecrets("802-11-wireless-security");
1667+
1668+ QString secretsType;
1669+ if (keymgmt == "wpa-psk" && authalg == "open") {
1670+ secretsType = "802-11-wireless-security";
1671+ } else if (keymgmt == "wpa-eap" || keymgmt == "ieee8021x") {
1672+ secretsType = "802-1x";
1673+ }
1674+
1675+ auto reply = m_iface.GetSecrets( secretsType );
1676 reply.waitForFinished();
1677 if(!reply.isValid()) {
1678 qWarning() << "Error querying secrects: " << reply.error().message() << "\n";
1679 return;
1680 }
1681 auto secrects = reply.value();
1682-
1683- auto match = secrects.find("802-11-wireless-security");
1684+ auto match = secrects.find( secretsType );
1685 if (match != secrects.end()) {
1686 auto secrects_security = *match;
1687
1688@@ -345,6 +443,8 @@
1689 password = secrects_security["wep-key0"].toString();
1690 } else if (keymgmt == "wpa-psk" && authalg == "open") {
1691 password = secrects_security["psk"].toString();
1692+ } else if (keymgmt == "wpa-eap" || keymgmt == "ieee8021x") {
1693+ password = secrects_security["password"].toString();
1694 } else {
1695 }
1696 }
1697@@ -390,7 +490,7 @@
1698 QList<QStringList> WifiDbusHelper::getPreviouslyConnectedWifiNetworks() {
1699 QList<QStringList> networks;
1700
1701- OrgFreedesktopNetworkManagerSettingsInterface foo
1702+ OrgFreedesktopNetworkManagerSettingsInterface foo
1703 (NM_SERVICE,
1704 "/org/freedesktop/NetworkManager/Settings",
1705 QDBusConnection::systemBus());
1706@@ -464,7 +564,7 @@
1707 auto ac_path_var = iface.property("ActiveConnection");
1708 if(!ac_path_var.isValid()) {
1709 qWarning() << __PRETTY_FUNCTION__ << ": Could not get active connection property from "
1710- << d.path() << ".\n";
1711+ << d.path() << ".\n";
1712 return true;
1713 }
1714 QString ac_path = ac_path_var.value<QDBusObjectPath>().path();
1715@@ -472,7 +572,7 @@
1716 auto conn_path_var = ac_iface.property("Connection");
1717 if(!conn_path_var.isValid()) {
1718 qWarning() << __PRETTY_FUNCTION__ << ": Could not get connection path property from "
1719- << ac_path << ".\n";
1720+ << ac_path << ".\n";
1721 return false;
1722 }
1723 forgetConnection(conn_path_var.value<QDBusObjectPath>().path());
1724
1725=== modified file 'plugins/wifi/wifidbushelper.h'
1726--- plugins/wifi/wifidbushelper.h 2014-10-10 14:10:52 +0000
1727+++ plugins/wifi/wifidbushelper.h 2015-07-01 18:56:14 +0000
1728@@ -37,7 +37,7 @@
1729 explicit WifiDbusHelper(QObject *parent = nullptr);
1730 ~WifiDbusHelper() {};
1731
1732- Q_INVOKABLE void connect(QString ssid, int security, QString password);
1733+ Q_INVOKABLE void connect(QString ssid, int security, int auth, QStringList usernames, QStringList password, QStringList certs, int p2auth);
1734 Q_INVOKABLE QList<QStringList> getPreviouslyConnectedWifiNetworks();
1735 Q_INVOKABLE void forgetConnection(const QString dbus_path);
1736 Q_INVOKABLE bool forgetActiveDevice();
1737
1738=== modified file 'tests/autopilot/ubuntu_system_settings/__init__.py'
1739--- tests/autopilot/ubuntu_system_settings/__init__.py 2015-05-28 14:09:07 +0000
1740+++ tests/autopilot/ubuntu_system_settings/__init__.py 2015-07-01 18:56:14 +0000
1741@@ -978,15 +978,23 @@
1742
1743 """
1744 @autopilot.logging.log_action(logger.debug)
1745- def connect_to_hidden_network(self, name, security="none", password=None,
1746- cancel=False, scroll_to_and_click=None):
1747- dialog = self._click_connect_to_hidden_network(scroll_to_and_click)
1748+ def connect_to_hidden_network(self, name, security='none', username=None,
1749+ password=None, auth=None, protocol=None,
1750+ cancel=False):
1751+ dialog = self._click_connect_to_hidden_network()
1752+ dialog._scroll_to_and_click = self._scroll_to_and_click
1753 dialog.enter_name(name)
1754+
1755 if security:
1756 dialog.set_security(security)
1757+ if auth:
1758+ dialog.set_auth(auth)
1759+ if protocol:
1760+ dialog.set_protocol(protocol)
1761+ if username:
1762+ dialog.enter_username(username)
1763 if password:
1764 dialog.enter_password(password)
1765-
1766 if cancel:
1767 dialog.cancel()
1768 return self
1769@@ -995,7 +1003,7 @@
1770 return dialog
1771
1772 @autopilot.logging.log_action(logger.debug)
1773- def _click_connect_to_hidden_network(self, scroll_to_and_click):
1774+ def _click_connect_to_hidden_network(self):
1775
1776 # we can't mock the qunitymenu items, so we
1777 # have to wait for them to be built
1778@@ -1003,16 +1011,13 @@
1779
1780 button = self.select_single('*',
1781 objectName='connectToHiddenNetwork')
1782- if (scroll_to_and_click):
1783- scroll_to_and_click(button)
1784- else:
1785- self.pointing_device.click_object(button)
1786+ self._scroll_to_and_click(button)
1787 return self.get_root_instance().wait_select_single(
1788 objectName='otherNetworkDialog')
1789
1790 @autopilot.logging.log_action(logger.debug)
1791- def go_to_previous_networks(self, scroll_to_and_click=None):
1792- return self._click_previous_network(scroll_to_and_click)
1793+ def go_to_previous_networks(self):
1794+ return self._click_previous_network()
1795
1796 """Removes previous network
1797
1798@@ -1022,14 +1027,14 @@
1799
1800 """
1801 @autopilot.logging.log_action(logger.debug)
1802- def remove_previous_network(self, ssid, scroll_to_and_click=None):
1803- page = self.go_to_previous_networks(scroll_to_and_click)
1804+ def remove_previous_network(self, ssid):
1805+ page = self.go_to_previous_networks()
1806 details = page.select_network(ssid)
1807 details.forget_network()
1808 return page
1809
1810 @autopilot.logging.log_action(logger.debug)
1811- def _click_previous_network(self, scroll_to_and_click):
1812+ def _click_previous_network(self):
1813
1814 # we can't mock the qunitymenu items, so we
1815 # have to wait for them to be built
1816@@ -1037,10 +1042,7 @@
1817
1818 button = self.select_single('*',
1819 objectName='previousNetwork')
1820- if (scroll_to_and_click):
1821- scroll_to_and_click(button)
1822- else:
1823- self.pointing_device.click_object(button)
1824+ self._scroll_to_and_click(button)
1825 return self.get_root_instance().wait_select_single(
1826 objectName='previousNetworksPage')
1827
1828@@ -1058,6 +1060,18 @@
1829 return True
1830 return False
1831
1832+ # FIXME: Use ListItem methods instead.
1833+ @autopilot.logging.log_action(logger.debug)
1834+ def _expand_list(self, list_name):
1835+ item_list = self.select_single(
1836+ '*', objectName=list_name)
1837+ active_child = item_list.select_single(
1838+ '*', objectName='listContainer')
1839+ self._scroll_to_and_click(active_child)
1840+ # wait for it to expand
1841+ sleep(0.5)
1842+ return item_list
1843+
1844 @autopilot.logging.log_action(logger.debug)
1845 def enter_name(self, name):
1846 self._enter_name(name)
1847@@ -1066,16 +1080,27 @@
1848 def _enter_name(self, name):
1849 namefield = self.select_single('TextField',
1850 objectName='networkname')
1851+ self._scroll_to_and_click(namefield)
1852 namefield.write(name)
1853
1854 @autopilot.logging.log_action(logger.debug)
1855+ def enter_username(self, username):
1856+ self._enter_username(username)
1857+
1858+ @autopilot.logging.log_action(logger.debug)
1859+ def _enter_username(self, username):
1860+ namefield = self.select_single('TextField',
1861+ objectName='username')
1862+ self._scroll_to_and_click(namefield)
1863+ namefield.write(username)
1864+
1865+ @autopilot.logging.log_action(logger.debug)
1866 def set_security(self, security):
1867 """Sets the hidden network's security
1868
1869- :param security: Either "none", "wpa" or "wep
1870+ :param security: Either 'none', 'wpa', 'wep', 'wpa-ep', 'dewp', 'leap'
1871
1872 :returns: None
1873-
1874 """
1875
1876 # We only set security if not none, since none is default
1877@@ -1083,35 +1108,28 @@
1878 self._set_security(security)
1879
1880 @autopilot.logging.log_action(logger.debug)
1881- def _expand_security_list(self):
1882- sec_list = self.select_single(
1883- '*', objectName='securityList')
1884- active_child = sec_list.select_single(
1885- '*', objectName='listContainer')
1886- self.pointing_device.click_object(active_child)
1887- # wait for it to expand
1888- sleep(0.5)
1889- return sec_list
1890-
1891- @autopilot.logging.log_action(logger.debug)
1892 def _set_security(self, security):
1893+ s_list = self._expand_list('securityList')
1894+ item = None
1895 if security == 'none':
1896- sec_list = self._expand_security_list()
1897- item = sec_list.wait_select_single('*',
1898- text=_('None'))
1899- self.pointing_device.click_object(item)
1900+ item = s_list.wait_select_single('*', text=_('None'))
1901 elif security == 'wpa':
1902- sec_list = self._expand_security_list()
1903- item = sec_list.wait_select_single('*',
1904- text=_('WPA & WPA2 Personal'))
1905- self.pointing_device.click_object(item)
1906+ item = s_list.wait_select_single('*',
1907+ text=_('WPA & WPA2 Personal'))
1908 elif security == 'wep':
1909- sec_list = self._expand_security_list()
1910- item = sec_list.wait_select_single('*',
1911- text=_('WEP'))
1912- self.pointing_device.click_object(item)
1913+ item = s_list.wait_select_single('*', text=_('WEP'))
1914+ elif security == 'wpa-ep':
1915+ item = s_list.wait_select_single('*',
1916+ text=_('WPA & WPA2 Enterprise'))
1917+ elif security == 'dwep':
1918+ item = s_list.wait_select_single('*',
1919+ text=_('Dynamic WEP (802.1x)'))
1920+ elif security == 'leap':
1921+ item = s_list.wait_select_single('*', text=_('LEAP'))
1922 elif security is not None:
1923 raise ValueError('security type %s is not valid' % security)
1924+
1925+ self.pointing_device.click_object(item)
1926 # wait for ui to change
1927 sleep(0.5)
1928
1929@@ -1123,16 +1141,78 @@
1930 def _enter_password(self, password):
1931 pwdfield = self.select_single('TextField',
1932 objectName='password')
1933+ self._scroll_to_and_click(pwdfield)
1934 pwdfield.write(password)
1935
1936 @autopilot.logging.log_action(logger.debug)
1937+ def set_protocol(self, protocol):
1938+ """Sets the hidden network's protocol.
1939+
1940+ :param protocol: Either 'pap', 'mschapv2', 'mschap', 'chap', 'gtc',
1941+ or 'md5'.
1942+ """
1943+ self._set_protocol(protocol)
1944+
1945+ @autopilot.logging.log_action(logger.debug)
1946+ def _set_protocol(self, protocol):
1947+ p_list = self._expand_list('p2authList')
1948+ item = None
1949+ if protocol == 'pap':
1950+ item = p_list.wait_select_single(text='PAP')
1951+ elif protocol == 'mschapv2':
1952+ item = p_list.wait_select_single(text='MSCHAPv2')
1953+ elif protocol == 'mschap':
1954+ item = p_list.wait_select_single(text='MSCHAP')
1955+ elif protocol == 'chap':
1956+ item = p_list.wait_select_single(text='CHAP')
1957+ elif protocol == 'gtc':
1958+ item = p_list.wait_select_single(text='GTC')
1959+ elif protocol == 'md5':
1960+ item = p_list.wait_select_single(text='MD5')
1961+ elif protocol is not None:
1962+ raise ValueError('protocol type %s is not valid' % protocol)
1963+
1964+ self.pointing_device.click_object(item)
1965+ # wait for ui to change
1966+ sleep(0.5)
1967+
1968+ @autopilot.logging.log_action(logger.debug)
1969+ def set_auth(self, auth):
1970+ """Sets the hidden network's protocol.
1971+
1972+ :param auth: Either 'tls', 'ttls', 'leap', 'fast' or 'peap'.
1973+ """
1974+ self._set_auth(auth)
1975+
1976+ @autopilot.logging.log_action(logger.debug)
1977+ def _set_auth(self, auth):
1978+ a_list = self._expand_list('authList')
1979+ item = None
1980+ if auth == 'tls':
1981+ item = a_list.wait_select_single(text='TLS')
1982+ elif auth == 'ttls':
1983+ item = a_list.wait_select_single(text='TTLS')
1984+ elif auth == 'leap':
1985+ item = a_list.wait_select_single(text='LEAP')
1986+ elif auth == 'fast':
1987+ item = a_list.wait_select_single(text='FAST')
1988+ elif auth == 'peap':
1989+ item = a_list.wait_select_single(text='PEAP')
1990+ elif auth is not None:
1991+ raise ValueError('auth type %s is not valid' % auth)
1992+
1993+ self.pointing_device.click_object(item)
1994+ # wait for ui to change
1995+ sleep(0.5)
1996+
1997+ @autopilot.logging.log_action(logger.debug)
1998 def cancel(self):
1999 self._click_cancel()
2000
2001 @autopilot.logging.log_action(logger.debug)
2002 def _click_cancel(self):
2003 button = self.select_single('Button', objectName='cancel')
2004- self.pointing_device.click_object(button)
2005+ self._scroll_to_and_click(button)
2006
2007 @autopilot.logging.log_action(logger.debug)
2008 def connect(self):
2009@@ -1141,7 +1221,7 @@
2010 @autopilot.logging.log_action(logger.debug)
2011 def _click_connect(self):
2012 button = self.select_single('Button', objectName='connect')
2013- self.pointing_device.click_object(button)
2014+ self._scroll_to_and_click(button)
2015
2016
2017 class PreviousNetworks(
2018
2019=== modified file 'tests/autopilot/ubuntu_system_settings/tests/__init__.py'
2020--- tests/autopilot/ubuntu_system_settings/tests/__init__.py 2015-05-15 12:47:14 +0000
2021+++ tests/autopilot/ubuntu_system_settings/tests/__init__.py 2015-07-01 18:56:14 +0000
2022@@ -863,9 +863,9 @@
2023 cls.start_system_bus()
2024 cls.dbus_con = cls.get_dbus(True)
2025 # Add a mock NetworkManager environment so we get consistent results
2026+ template = os.path.join(os.path.dirname(__file__), 'networkmanager.py')
2027 (cls.p_mock, cls.obj_nm) = cls.spawn_server_template(
2028- 'networkmanager', stdout=subprocess.PIPE)
2029- cls.dbusmock = dbus.Interface(cls.obj_nm, dbusmock.MOCK_IFACE)
2030+ template, stdout=subprocess.PIPE)
2031
2032 def setUp(self, panel=None):
2033 self.obj_nm.Reset()
2034@@ -874,19 +874,28 @@
2035 NM_SERVICE, self.device_path),
2036 dbusmock.MOCK_IFACE)
2037
2038- self.ap_mock = self.create_access_point('test_ap', 'test_ap')
2039+ self.ap_mock = self.create_access_point(
2040+ 'test_ap', 'test_ap',
2041+ security=NM80211ApSecurityFlags.NM_802_11_AP_SEC_KEY_MGMT_PSK
2042+ )
2043
2044 super(WifiBaseTestCase, self).setUp()
2045 self.wifi_page = self.main_view.go_to_wifi_page()
2046
2047- def create_access_point(self, name, ssid, secured=True):
2048-
2049- if secured:
2050- security = NM80211ApSecurityFlags.NM_802_11_AP_SEC_KEY_MGMT_PSK
2051- else:
2052+ def create_access_point(self, name, ssid, security=None):
2053+ """Creates access point.
2054+
2055+ :param name: Name of access point
2056+ :param ssid: SSID of access point
2057+ :param security: Either None, or a NM80211ApSecurityFlags
2058+
2059+ :returns: Access point
2060+
2061+ """
2062+ if security is None:
2063 security = NM80211ApSecurityFlags.NM_802_11_AP_SEC_NONE
2064
2065- return self.dbusmock.AddAccessPoint(
2066+ return self.obj_nm.AddAccessPoint(
2067 self.device_path, name, ssid, self.random_mac_address(),
2068 InfrastructureMode.NM_802_11_MODE_INFRA, 2425, 5400, 82, security)
2069
2070
2071=== added file 'tests/autopilot/ubuntu_system_settings/tests/networkmanager.py'
2072--- tests/autopilot/ubuntu_system_settings/tests/networkmanager.py 1970-01-01 00:00:00 +0000
2073+++ tests/autopilot/ubuntu_system_settings/tests/networkmanager.py 2015-07-01 18:56:14 +0000
2074@@ -0,0 +1,960 @@
2075+'''NetworkManager mock template
2076+
2077+This creates the expected methods and properties of the main
2078+org.freedesktop.NetworkManager object, but no devices. You can specify any
2079+property such as 'NetworkingEnabled', or 'WirelessEnabled' etc. in
2080+"parameters".
2081+'''
2082+
2083+# This program is free software; you can redistribute it and/or modify it under
2084+# the terms of the GNU Lesser General Public License as published by the Free
2085+# Software Foundation; either version 3 of the License, or (at your option) any
2086+# later version. See http://www.gnu.org/copyleft/lgpl.html for the full text
2087+# of the license.
2088+
2089+__author__ = 'Iftikhar Ahmad'
2090+__email__ = 'iftikhar.ahmad@canonical.com'
2091+__copyright__ = '(c) 2012 Canonical Ltd.'
2092+__license__ = 'LGPL 3+'
2093+
2094+import dbus
2095+import uuid
2096+import binascii
2097+
2098+from dbusmock import MOCK_IFACE
2099+import dbusmock
2100+
2101+
2102+BUS_NAME = 'org.freedesktop.NetworkManager'
2103+MAIN_OBJ = '/org/freedesktop/NetworkManager'
2104+MAIN_IFACE = 'org.freedesktop.NetworkManager'
2105+SETTINGS_OBJ = '/org/freedesktop/NetworkManager/Settings'
2106+SETTINGS_IFACE = 'org.freedesktop.NetworkManager.Settings'
2107+DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device'
2108+WIRELESS_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device.Wireless'
2109+ACCESS_POINT_IFACE = 'org.freedesktop.NetworkManager.AccessPoint'
2110+CSETTINGS_IFACE = 'org.freedesktop.NetworkManager.Settings.Connection'
2111+ACTIVE_CONNECTION_IFACE = 'org.freedesktop.NetworkManager.Connection.Active'
2112+ACTIVE_CONNECTION_PATH = '/org/freedesktop/NetworkManager/ActiveConnection/'
2113+SYSTEM_BUS = True
2114+
2115+
2116+class NMState:
2117+ '''Global state
2118+
2119+ As per https://developer.gnome.org/NetworkManager/unstable/spec.html
2120+ #type-NM_STATE
2121+ '''
2122+ NM_STATE_UNKNOWN = 0
2123+ NM_STATE_ASLEEP = 10
2124+ NM_STATE_DISCONNECTED = 20
2125+ NM_STATE_DISCONNECTING = 30
2126+ NM_STATE_CONNECTING = 40
2127+ NM_STATE_CONNECTED_LOCAL = 50
2128+ NM_STATE_CONNECTED_SITE = 60
2129+ NM_STATE_CONNECTED_GLOBAL = 70
2130+
2131+
2132+class NMConnectivityState:
2133+ '''Connectvity state
2134+
2135+ As per https://developer.gnome.org/NetworkManager/unstable/spec.html
2136+ #type-NM_CONNECTIVITY
2137+ '''
2138+ NM_CONNECTIVITY_UNKNOWN = 0
2139+ NM_CONNECTIVITY_NONE = 1
2140+ NM_CONNECTIVITY_PORTAL = 2
2141+ NM_CONNECTIVITY_LIMITED = 3
2142+ NM_CONNECTIVITY_FULL = 4
2143+
2144+
2145+class NMActiveConnectionState:
2146+ '''Active connection state
2147+
2148+ As per https://developer.gnome.org/NetworkManager/unstable/spec.html
2149+ #type-NM_ACTIVE_CONNECTION_STATE
2150+ '''
2151+ NM_ACTIVE_CONNECTION_STATE_UNKNOWN = 0
2152+ NM_ACTIVE_CONNECTION_STATE_ACTIVATING = 1
2153+ NM_ACTIVE_CONNECTION_STATE_ACTIVATED = 2
2154+ NM_ACTIVE_CONNECTION_STATE_DEACTIVATING = 3
2155+ NM_ACTIVE_CONNECTION_STATE_DEACTIVATED = 4
2156+
2157+
2158+class InfrastructureMode:
2159+ '''Infrastructure mode
2160+
2161+ As per https://developer.gnome.org/NetworkManager/unstable/spec.html
2162+ #type-NM_802_11_MODE
2163+ '''
2164+ NM_802_11_MODE_UNKNOWN = 0
2165+ NM_802_11_MODE_ADHOC = 1
2166+ NM_802_11_MODE_INFRA = 2
2167+ NM_802_11_MODE_AP = 3
2168+
2169+ NAME_MAP = {
2170+ NM_802_11_MODE_UNKNOWN: 'unknown',
2171+ NM_802_11_MODE_ADHOC: 'adhoc',
2172+ NM_802_11_MODE_INFRA: 'infrastructure',
2173+ NM_802_11_MODE_AP: 'access-point',
2174+ }
2175+
2176+
2177+class DeviceState:
2178+ '''Device states
2179+
2180+ As per https://developer.gnome.org/NetworkManager/unstable/spec.html
2181+ #type-NM_DEVICE_STATE
2182+ '''
2183+ UNKNOWN = 0
2184+ UNMANAGED = 10
2185+ UNAVAILABLE = 20
2186+ DISCONNECTED = 30
2187+ PREPARE = 40
2188+ CONFIG = 50
2189+ NEED_AUTH = 60
2190+ IP_CONFIG = 70
2191+ IP_CHECK = 80
2192+ SECONDARIES = 90
2193+ ACTIVATED = 100
2194+ DEACTIVATING = 110
2195+ FAILED = 120
2196+
2197+
2198+class NM80211ApSecurityFlags:
2199+ '''Security flags
2200+
2201+ As per https://developer.gnome.org/NetworkManager/unstable/spec.html
2202+ #type-NM_802_11_AP_SEC
2203+ '''
2204+ NM_802_11_AP_SEC_NONE = 0x00000000
2205+ NM_802_11_AP_SEC_PAIR_WEP40 = 0x00000001
2206+ NM_802_11_AP_SEC_PAIR_WEP104 = 0x00000002
2207+ NM_802_11_AP_SEC_PAIR_TKIP = 0x00000004
2208+ NM_802_11_AP_SEC_PAIR_CCMP = 0x00000008
2209+ NM_802_11_AP_SEC_GROUP_WEP40 = 0x00000010
2210+ NM_802_11_AP_SEC_GROUP_WEP104 = 0x00000020
2211+ NM_802_11_AP_SEC_GROUP_TKIP = 0x00000040
2212+ NM_802_11_AP_SEC_GROUP_CCMP = 0x00000080
2213+ NM_802_11_AP_SEC_KEY_MGMT_PSK = 0x00000100
2214+ NM_802_11_AP_SEC_KEY_MGMT_802_1X = 0x00000200
2215+
2216+ NAME_MAP = {
2217+ NM_802_11_AP_SEC_KEY_MGMT_PSK: {
2218+ 'key-mgmt': 'wpa-psk',
2219+ 'auth-alg': 'open'
2220+ },
2221+ NM_802_11_AP_SEC_KEY_MGMT_802_1X: {
2222+ 'key-mgmt': 'wpa-eap'
2223+ },
2224+ }
2225+
2226+
2227+class NM80211ApFlags:
2228+ '''Device flags
2229+
2230+ As per https://developer.gnome.org/NetworkManager/unstable/spec.html
2231+ #type-NM_802_11_AP_FLAGS
2232+ '''
2233+ NM_802_11_AP_FLAGS_NONE = 0x00000000
2234+ NM_802_11_AP_FLAGS_PRIVACY = 0x00000001
2235+
2236+
2237+def activate_connection(self, conn, dev, ap):
2238+ name = ap.rsplit('/', 1)[1]
2239+ RemoveActiveConnection(self, dev, ACTIVE_CONNECTION_PATH + name)
2240+
2241+ state = dbus.UInt32(
2242+ NMActiveConnectionState.NM_ACTIVE_CONNECTION_STATE_ACTIVATED
2243+ )
2244+ active_conn = dbus.ObjectPath(
2245+ AddActiveConnection(self, [dev], conn, ap, name, state)
2246+ )
2247+
2248+ return active_conn
2249+
2250+
2251+def deactivate_connection(self, active_conn_path):
2252+ NM = dbusmock.get_object(MAIN_OBJ)
2253+
2254+ for dev_path in NM.GetDevices():
2255+ RemoveActiveConnection(self, dev_path, active_conn_path)
2256+
2257+
2258+def add_and_activate_connection(self, conn_conf, dev, ap):
2259+ name = ap.rsplit('/', 1)[1]
2260+ RemoveWifiConnection(
2261+ self, dev, '/org/freedesktop/NetworkManager/Settings/' + name
2262+ )
2263+
2264+ raw_ssid = ''.join(
2265+ [chr(byte) for byte in conn_conf["802-11-wireless"]["ssid"]]
2266+ )
2267+ wifi_conn = dbus.ObjectPath(
2268+ AddWiFiConnection(self, dev, name, raw_ssid, "", conn_conf)
2269+ )
2270+
2271+ active_conn = activate_connection(self, wifi_conn, dev, ap)
2272+
2273+ return (wifi_conn, active_conn)
2274+
2275+
2276+def load(mock, parameters):
2277+ mock.activate_connection = activate_connection
2278+ mock.deactivate_connection = deactivate_connection
2279+ mock.add_and_activate_connection = add_and_activate_connection
2280+ mock.AddMethods(MAIN_IFACE, [
2281+ (
2282+ 'GetDevices', '', 'ao',
2283+ 'ret = [k for k in objects.keys() if "/Devices" in k]'
2284+ ),
2285+ ('GetPermissions', '', 'a{ss}', 'ret = {}'),
2286+ ('state', '', 'u', "ret = self.Get('%s', 'State')" % MAIN_IFACE),
2287+ (
2288+ 'CheckConnectivity', '', 'u',
2289+ "ret = self.Get('%s', 'Connectivity')" % MAIN_IFACE
2290+ ),
2291+ (
2292+ 'ActivateConnection', 'ooo', 'o',
2293+ "ret = self.activate_connection(self, args[0], args[1], args[2])"
2294+ ),
2295+ (
2296+ 'DeactivateConnection', 'o', '',
2297+ "self.deactivate_connection(self, args[0])"
2298+ ),
2299+ (
2300+ 'AddAndActivateConnection', 'a{sa{sv}}oo', 'oo',
2301+ "ret = self.add_and_activate_connection(" +
2302+ "self, args[0], args[1], args[2])"
2303+ ),
2304+ ])
2305+
2306+ mock.AddProperties(
2307+ '',
2308+ {
2309+ 'ActiveConnections': dbus.Array([], signature='o'),
2310+ 'Devices': dbus.Array([], signature='o'),
2311+ 'NetworkingEnabled': parameters.get('NetworkingEnabled', True),
2312+ 'Connectivity': parameters.get(
2313+ 'Connectivity',
2314+ dbus.UInt32(NMConnectivityState.NM_CONNECTIVITY_FULL)
2315+ ),
2316+ 'State': parameters.get(
2317+ 'State', dbus.UInt32(NMState.NM_STATE_CONNECTED_GLOBAL)
2318+ ),
2319+ 'Startup': False,
2320+ 'Version': parameters.get('Version', '0.9.6.0'),
2321+ 'WimaxEnabled': parameters.get('WimaxEnabled', True),
2322+ 'WimaxHardwareEnabled': parameters.get(
2323+ 'WimaxHardwareEnabled', True
2324+ ),
2325+ 'WirelessEnabled': parameters.get('WirelessEnabled', True),
2326+ 'WirelessHardwareEnabled': parameters.get(
2327+ 'WirelessHardwareEnabled', True
2328+ ),
2329+ 'WwanEnabled': parameters.get('WwanEnabled', False),
2330+ 'WwanHardwareEnabled': parameters.get('WwanHardwareEnabled', True)
2331+ }
2332+ )
2333+
2334+ settings_props = {'Hostname': 'hostname',
2335+ 'CanModify': True,
2336+ 'Connections': dbus.Array([], signature='o')}
2337+ settings_methods = [
2338+ (
2339+ 'ListConnections', '', 'ao',
2340+ "ret = self.Get('%s', 'Connections')" % SETTINGS_IFACE
2341+ ),
2342+ ('GetConnectionByUuid', 's', 'o', ''),
2343+ (
2344+ 'AddConnection', 'a{sa{sv}}', 'o',
2345+ 'ret = self.SettingsAddConnection(args[0])'
2346+ ),
2347+ ('SaveHostname', 's', '', '')
2348+ ]
2349+ mock.AddObject(SETTINGS_OBJ,
2350+ SETTINGS_IFACE,
2351+ settings_props,
2352+ settings_methods)
2353+
2354+
2355+@dbus.service.method(MOCK_IFACE,
2356+ in_signature='sssv', out_signature='')
2357+def SetProperty(self, path, iface, name, value):
2358+ obj = dbusmock.get_object(path)
2359+ obj.Set(iface, name, value)
2360+ obj.EmitSignal(iface, 'PropertiesChanged', 'a{sv}', [{name: value}])
2361+
2362+
2363+@dbus.service.method(MOCK_IFACE,
2364+ in_signature='u', out_signature='')
2365+def SetGlobalConnectionState(self, state):
2366+ self.SetProperty(
2367+ MAIN_OBJ, MAIN_IFACE, 'State',
2368+ dbus.UInt32(state, variant_level=1)
2369+ )
2370+ self.EmitSignal(MAIN_IFACE, 'StateChanged', 'u', [state])
2371+
2372+
2373+@dbus.service.method(MOCK_IFACE,
2374+ in_signature='u', out_signature='')
2375+def SetConnectivity(self, connectivity):
2376+ self.SetProperty(
2377+ MAIN_OBJ, MAIN_IFACE, 'Connectivity',
2378+ dbus.UInt32(connectivity, variant_level=1)
2379+ )
2380+
2381+
2382+@dbus.service.method(MOCK_IFACE,
2383+ in_signature='ss', out_signature='')
2384+def SetDeviceActive(self, device_path, active_connection_path):
2385+ dev_obj = dbusmock.get_object(device_path)
2386+ dev_obj.Set(
2387+ DEVICE_IFACE, 'ActiveConnection',
2388+ dbus.ObjectPath(active_connection_path)
2389+ )
2390+ old_state = dev_obj.Get(DEVICE_IFACE, 'State')
2391+ dev_obj.Set(DEVICE_IFACE, 'State', dbus.UInt32(DeviceState.ACTIVATED))
2392+
2393+ dev_obj.EmitSignal(
2394+ DEVICE_IFACE, 'StateChanged', 'uuu',
2395+ [
2396+ dbus.UInt32(DeviceState.ACTIVATED),
2397+ old_state,
2398+ dbus.UInt32(1)
2399+ ]
2400+ )
2401+
2402+
2403+@dbus.service.method(MOCK_IFACE,
2404+ in_signature='s', out_signature='')
2405+def SetDeviceDisconnected(self, device_path):
2406+ dev_obj = dbusmock.get_object(device_path)
2407+ dev_obj.Set(DEVICE_IFACE, 'ActiveConnection', dbus.ObjectPath('/'))
2408+ old_state = dev_obj.Get(DEVICE_IFACE, 'State')
2409+ dev_obj.Set(DEVICE_IFACE, 'State', dbus.UInt32(DeviceState.DISCONNECTED))
2410+
2411+ dev_obj.EmitSignal(
2412+ DEVICE_IFACE, 'StateChanged', 'uuu',
2413+ [
2414+ dbus.UInt32(DeviceState.DISCONNECTED),
2415+ old_state,
2416+ dbus.UInt32(1)
2417+ ]
2418+ )
2419+
2420+
2421+@dbus.service.method(MOCK_IFACE,
2422+ in_signature='ssi', out_signature='s')
2423+def AddEthernetDevice(self, device_name, iface_name, state):
2424+ '''Add an ethernet device.
2425+
2426+ You have to specify device_name, device interface name (e. g. eth0), and
2427+ state. You can use the predefined DeviceState values (e. g.
2428+ DeviceState.ACTIVATED) or supply a numeric value. For valid state values
2429+ please visit
2430+ http://projects.gnome.org/NetworkManager/developers/api/09/spec.html
2431+ #type-NM_DEVICE_STATE
2432+
2433+ Please note that this does not set any global properties.
2434+
2435+ Returns the new object path.
2436+ '''
2437+ path = '/org/freedesktop/NetworkManager/Devices/' + device_name
2438+ wired_props = {'Carrier': False,
2439+ 'HwAddress': dbus.String('78:DD:08:D2:3D:43'),
2440+ 'PermHwAddress': dbus.String('78:DD:08:D2:3D:43'),
2441+ 'Speed': dbus.UInt32(0)}
2442+ self.AddObject(path,
2443+ 'org.freedesktop.NetworkManager.Device.Wired',
2444+ wired_props,
2445+ [])
2446+
2447+ props = {'DeviceType': dbus.UInt32(1),
2448+ 'State': dbus.UInt32(state),
2449+ 'Interface': iface_name,
2450+ 'AvailableConnections': dbus.Array([], signature='o'),
2451+ 'IpInterface': ''}
2452+
2453+ obj = dbusmock.get_object(path)
2454+ obj.AddProperties(DEVICE_IFACE, props)
2455+
2456+ devices = self.Get(MAIN_IFACE, 'Devices')
2457+ devices.append(path)
2458+ self.Set(MAIN_IFACE, 'Devices', devices)
2459+
2460+ self.EmitSignal(
2461+ 'org.freedesktop.NetworkManager', 'DeviceAdded', 'o', [path]
2462+ )
2463+
2464+ return path
2465+
2466+
2467+@dbus.service.method(MOCK_IFACE,
2468+ in_signature='ssi', out_signature='s')
2469+def AddWiFiDevice(self, device_name, iface_name, state):
2470+ '''Add a WiFi Device.
2471+
2472+ You have to specify device_name, device interface name (e. g. wlan0) and
2473+ state. You can use the predefined DeviceState values (e. g.
2474+ DeviceState.ACTIVATED) or supply a numeric value. For valid state values,
2475+ please visit
2476+ http://projects.gnome.org/NetworkManager/developers/api/09/spec.html
2477+ #type-NM_DEVICE_STATE
2478+
2479+ Please note that this does not set any global properties.
2480+
2481+ Returns the new object path.
2482+ '''
2483+
2484+ path = '/org/freedesktop/NetworkManager/Devices/' + device_name
2485+ self.AddObject(path,
2486+ WIRELESS_DEVICE_IFACE,
2487+ {
2488+ 'HwAddress': dbus.String('11:22:33:44:55:66'),
2489+ 'PermHwAddress': dbus.String('11:22:33:44:55:66'),
2490+ 'Bitrate': dbus.UInt32(5400),
2491+ 'Mode': dbus.UInt32(2),
2492+ 'WirelessCapabilities': dbus.UInt32(255),
2493+ 'AccessPoints': dbus.Array([], signature='o'),
2494+ },
2495+ [
2496+ ('GetAccessPoints', '', 'ao',
2497+ 'ret = self.access_points'),
2498+ ('GetAllAccessPoints', '', 'ao',
2499+ 'ret = self.access_points'),
2500+ ('RequestScan', 'a{sv}', '', ''),
2501+ ])
2502+
2503+ dev_obj = dbusmock.get_object(path)
2504+ dev_obj.access_points = []
2505+ dev_obj.AddProperties(
2506+ DEVICE_IFACE,
2507+ {
2508+ 'ActiveConnection': dbus.ObjectPath('/'),
2509+ 'AvailableConnections': dbus.Array([], signature='o'),
2510+ 'AutoConnect': False,
2511+ 'Managed': True,
2512+ 'Driver': 'dbusmock',
2513+ 'DeviceType': dbus.UInt32(2),
2514+ 'State': dbus.UInt32(state),
2515+ 'Interface': iface_name,
2516+ 'IpInterface': iface_name,
2517+ }
2518+ )
2519+
2520+ devices = self.Get(MAIN_IFACE, 'Devices')
2521+ devices.append(path)
2522+ self.Set(MAIN_IFACE, 'Devices', devices)
2523+
2524+ self.EmitSignal(
2525+ 'org.freedesktop.NetworkManager', 'DeviceAdded', 'o', [path]
2526+ )
2527+
2528+ return path
2529+
2530+
2531+@dbus.service.method(MOCK_IFACE,
2532+ in_signature='ssssuuuyu', out_signature='s')
2533+def AddAccessPoint(self, dev_path, ap_name, ssid, hw_address,
2534+ mode, frequency, rate, strength, security):
2535+ '''Add an access point to an existing WiFi device.
2536+
2537+ You have to specify WiFi Device path, Access Point object name,
2538+ ssid, hw_address, mode, frequency, rate, strength and security.
2539+ For valid access point property values, please visit
2540+ http://projects.gnome.org/NetworkManager/developers/api/09/spec.html#
2541+ org.freedesktop.NetworkManager.AccessPoint
2542+
2543+ Please note that this does not set any global properties.
2544+
2545+ Returns the new object path.
2546+ '''
2547+ dev_obj = dbusmock.get_object(dev_path)
2548+ ap_path = '/org/freedesktop/NetworkManager/AccessPoint/' + ap_name
2549+ if ap_path in dev_obj.access_points:
2550+ raise dbus.exceptions.DBusException(
2551+ 'Access point %s on device %s already exists' % (ap_name,
2552+ dev_path),
2553+ name=MAIN_IFACE + '.AlreadyExists')
2554+
2555+ flags = NM80211ApFlags.NM_802_11_AP_FLAGS_PRIVACY
2556+ if security == NM80211ApSecurityFlags.NM_802_11_AP_SEC_NONE:
2557+ flags = NM80211ApFlags.NM_802_11_AP_FLAGS_NONE
2558+
2559+ self.AddObject(ap_path,
2560+ ACCESS_POINT_IFACE,
2561+ {'Ssid': dbus.ByteArray(ssid.encode('UTF-8')),
2562+ 'HwAddress': dbus.String(hw_address),
2563+ 'Flags': dbus.UInt32(flags),
2564+ 'LastSeen': dbus.Int32(1),
2565+ 'Frequency': dbus.UInt32(frequency),
2566+ 'MaxBitrate': dbus.UInt32(rate),
2567+ 'Mode': dbus.UInt32(mode),
2568+ 'RsnFlags': dbus.UInt32(security),
2569+ 'WpaFlags': dbus.UInt32(security),
2570+ 'Strength': dbus.Byte(strength)},
2571+ [])
2572+
2573+ dev_obj.access_points.append(ap_path)
2574+
2575+ aps = dev_obj.Get(WIRELESS_DEVICE_IFACE, 'AccessPoints')
2576+ aps.append(ap_path)
2577+ dev_obj.Set(WIRELESS_DEVICE_IFACE, 'AccessPoints', aps)
2578+
2579+ dev_obj.EmitSignal(
2580+ WIRELESS_DEVICE_IFACE, 'AccessPointAdded', 'o', [ap_path]
2581+ )
2582+
2583+ return ap_path
2584+
2585+
2586+@dbus.service.method(MOCK_IFACE,
2587+ in_signature='ssssa{sa{sv}}', out_signature='s')
2588+def AddWiFiConnection(self, dev_path, connection_name, ssid_name, key_mgmt,
2589+ config):
2590+ '''Add an available connection to an existing WiFi device and access point.
2591+
2592+ You have to specify WiFi Device path, Connection object name,
2593+ SSID and key management.
2594+
2595+ The SSID must match one of the previously created access points.
2596+
2597+ Please note that this does not set any global properties.
2598+
2599+ Returns the new object path.
2600+ '''
2601+
2602+ dev_obj = dbusmock.get_object(dev_path)
2603+ connection_path = '%s/%s' % (SETTINGS_OBJ, connection_name)
2604+ connections = dev_obj.Get(DEVICE_IFACE, 'AvailableConnections')
2605+
2606+ settings_obj = dbusmock.get_object(SETTINGS_OBJ)
2607+ main_connections = settings_obj.ListConnections()
2608+
2609+ ssid = ssid_name.encode('UTF-8')
2610+
2611+ # Find the access point by ssid
2612+ access_point = None
2613+ access_points = dev_obj.access_points
2614+ for ap_path in access_points:
2615+ ap = dbusmock.get_object(ap_path)
2616+ if ap.Get(ACCESS_POINT_IFACE, 'Ssid') == ssid:
2617+ access_point = ap
2618+ break
2619+
2620+ if not access_point:
2621+ raise dbus.exceptions.DBusException(
2622+ 'Access point with SSID [%s] could not be found' % (ssid_name),
2623+ name=MAIN_IFACE + '.DoesNotExist')
2624+
2625+ hw_address = access_point.Get(ACCESS_POINT_IFACE, 'HwAddress')
2626+ mode = access_point.Get(ACCESS_POINT_IFACE, 'Mode')
2627+ security = access_point.Get(ACCESS_POINT_IFACE, 'WpaFlags')
2628+
2629+ if connection_path in connections or connection_path in main_connections:
2630+ raise dbus.exceptions.DBusException(
2631+ 'Connection %s on device %s already exists' % (
2632+ connection_name, dev_path
2633+ ),
2634+ name=MAIN_IFACE + '.AlreadyExists')
2635+
2636+ # Parse mac address string into byte array
2637+ mac_bytes = binascii.unhexlify(hw_address.replace(':', ''))
2638+
2639+ settings = {
2640+ '802-11-wireless': {
2641+ 'seen-bssids': [hw_address],
2642+ 'ssid': dbus.ByteArray(ssid),
2643+ 'mac-address': dbus.ByteArray(mac_bytes),
2644+ 'mode': InfrastructureMode.NAME_MAP[mode]
2645+ },
2646+ 'connection': {
2647+ 'timestamp': dbus.UInt64(1374828522),
2648+ 'type': '802-11-wireless',
2649+ 'id': ssid_name,
2650+ 'uuid': str(uuid.uuid4())
2651+ },
2652+ }
2653+
2654+ if security != NM80211ApSecurityFlags.NM_802_11_AP_SEC_NONE:
2655+ settings['802-11-wireless']['security'] = '802-11-wireless-security'
2656+ settings['802-11-wireless-security'] = (
2657+ NM80211ApSecurityFlags.NAME_MAP[security])
2658+
2659+ if security == NM80211ApSecurityFlags.NM_802_11_AP_SEC_KEY_MGMT_802_1X:
2660+ settings['802-1x'] = config['802-1x']
2661+
2662+ self.AddObject(
2663+ connection_path,
2664+ CSETTINGS_IFACE,
2665+ {
2666+ 'Settings': dbus.Dictionary(settings, signature='sa{sv}'),
2667+ 'Secrets': dbus.Dictionary({}, signature='sa{sv}'),
2668+ },
2669+ [
2670+ (
2671+ 'Delete', '', '',
2672+ 'self.ConnectionDelete("%s")' % connection_path
2673+ ),
2674+ (
2675+ 'GetSettings', '', 'a{sa{sv}}',
2676+ "ret = self.Get('%s', 'Settings')" % CSETTINGS_IFACE
2677+ ),
2678+ (
2679+ 'GetSecrets', 's', 'a{sa{sv}}',
2680+ "ret = self.Get('%s', 'Secrets')" % CSETTINGS_IFACE
2681+ ),
2682+ (
2683+ 'Update', 'a{sa{sv}}', '',
2684+ 'self.ConnectionUpdate("%s", args[0])' % connection_path
2685+ ),
2686+ ]
2687+ )
2688+
2689+ connections.append(dbus.ObjectPath(connection_path))
2690+ dev_obj.Set(DEVICE_IFACE, 'AvailableConnections', connections)
2691+
2692+ main_connections.append(connection_path)
2693+ settings_obj.Set(SETTINGS_IFACE, 'Connections', main_connections)
2694+
2695+ settings_obj.EmitSignal(SETTINGS_IFACE, 'NewConnection', 'o', [ap_path])
2696+
2697+ return connection_path
2698+
2699+
2700+@dbus.service.method(MOCK_IFACE,
2701+ in_signature='assssu', out_signature='s')
2702+def AddActiveConnection(self, devices, connection_device, specific_object,
2703+ name, state):
2704+ '''Add an active connection to an existing WiFi device.
2705+
2706+ You have to a list of the involved WiFi devices, the connection path,
2707+ the access point path, ActiveConnection object name and connection
2708+ state.
2709+
2710+ Please note that this does not set any global properties.
2711+
2712+ Returns the new object path.
2713+ '''
2714+
2715+ conn_obj = dbusmock.get_object(connection_device)
2716+ settings = conn_obj.Get(CSETTINGS_IFACE, 'Settings')
2717+ conn_uuid = settings['connection']['uuid']
2718+
2719+ device_objects = [dbus.ObjectPath(dev) for dev in devices]
2720+
2721+ active_connection_path = ACTIVE_CONNECTION_PATH + name
2722+ self.AddObject(active_connection_path,
2723+ ACTIVE_CONNECTION_IFACE,
2724+ {
2725+ 'Devices': device_objects,
2726+ 'Default6': False,
2727+ 'Default': True,
2728+ 'Vpn': False,
2729+ 'Connection': dbus.ObjectPath(connection_device),
2730+ 'Master': dbus.ObjectPath('/'),
2731+ 'SpecificObject': dbus.ObjectPath(specific_object),
2732+ 'Uuid': conn_uuid,
2733+ 'State': state,
2734+ },
2735+ [])
2736+
2737+ for dev_path in devices:
2738+ self.SetDeviceActive(dev_path, active_connection_path)
2739+
2740+ active_connections = self.Get(MAIN_IFACE, 'ActiveConnections')
2741+ active_connections.append(dbus.ObjectPath(active_connection_path))
2742+ self.SetProperty(
2743+ MAIN_OBJ, MAIN_IFACE, 'ActiveConnections', active_connections
2744+ )
2745+
2746+ return active_connection_path
2747+
2748+
2749+@dbus.service.method(MOCK_IFACE,
2750+ in_signature='ss', out_signature='')
2751+def RemoveAccessPoint(self, dev_path, ap_path):
2752+ '''Remove the specified access point.
2753+
2754+ You have to specify the device to remove the access point from, and the
2755+ path of the access point.
2756+
2757+ Please note that this does not set any global properties.
2758+ '''
2759+
2760+ dev_obj = dbusmock.get_object(dev_path)
2761+
2762+ aps = dev_obj.Get(WIRELESS_DEVICE_IFACE, 'AccessPoints')
2763+ aps.remove(ap_path)
2764+ dev_obj.Set(WIRELESS_DEVICE_IFACE, 'AccessPoints', aps)
2765+
2766+ dev_obj.access_points.remove(ap_path)
2767+
2768+ dev_obj.EmitSignal(
2769+ WIRELESS_DEVICE_IFACE, 'AccessPointRemoved', 'o', [ap_path]
2770+ )
2771+
2772+ self.RemoveObject(ap_path)
2773+
2774+
2775+@dbus.service.method(MOCK_IFACE,
2776+ in_signature='ss', out_signature='')
2777+def RemoveWifiConnection(self, dev_path, connection_path):
2778+ '''Remove the specified WiFi connection.
2779+
2780+ You have to specify the device to remove the connection from, and the
2781+ path of the Connection.
2782+
2783+ Please note that this does not set any global properties.
2784+ '''
2785+
2786+ dev_obj = dbusmock.get_object(dev_path)
2787+ settings_obj = dbusmock.get_object(SETTINGS_OBJ)
2788+
2789+ connections = dev_obj.Get(DEVICE_IFACE, 'AvailableConnections')
2790+ main_connections = settings_obj.ListConnections()
2791+
2792+ if (connection_path not in connections and
2793+ connection_path not in main_connections):
2794+ return
2795+
2796+ connections.remove(dbus.ObjectPath(connection_path))
2797+ dev_obj.Set(DEVICE_IFACE, 'AvailableConnections', connections)
2798+
2799+ main_connections.remove(connection_path)
2800+ settings_obj.Set(SETTINGS_IFACE, 'Connections', main_connections)
2801+
2802+ settings_obj.EmitSignal(
2803+ SETTINGS_IFACE, 'ConnectionRemoved', 'o', [connection_path]
2804+ )
2805+
2806+ connection_obj = dbusmock.get_object(connection_path)
2807+ connection_obj.EmitSignal(CSETTINGS_IFACE, 'Removed', '', [])
2808+
2809+ self.RemoveObject(connection_path)
2810+
2811+
2812+@dbus.service.method(MOCK_IFACE,
2813+ in_signature='ss', out_signature='')
2814+def RemoveActiveConnection(self, dev_path, active_connection_path):
2815+ '''Remove the specified ActiveConnection.
2816+
2817+ You have to specify the device to remove the connection from, and the
2818+ path of the ActiveConnection.
2819+
2820+ Please note that this does not set any global properties.
2821+ '''
2822+ self.SetDeviceDisconnected(dev_path)
2823+
2824+ active_connections = self.Get(MAIN_IFACE, 'ActiveConnections')
2825+
2826+ if active_connection_path not in active_connections:
2827+ return
2828+
2829+ active_connections.remove(dbus.ObjectPath(active_connection_path))
2830+ self.SetProperty(
2831+ MAIN_OBJ, MAIN_IFACE, 'ActiveConnections', active_connections
2832+ )
2833+
2834+ self.RemoveObject(active_connection_path)
2835+
2836+
2837+@dbus.service.method(SETTINGS_IFACE,
2838+ in_signature='a{sa{sv}}', out_signature='o')
2839+def SettingsAddConnection(self, connection_settings):
2840+ '''Add a connection.
2841+
2842+ connection_settings is a String String Variant Map Map. See
2843+ https://developer.gnome.org/NetworkManager/0.9/spec.html
2844+ #type-String_String_Variant_Map_Map
2845+
2846+ If you omit uuid, this method adds one for you.
2847+ '''
2848+
2849+ if 'uuid' not in connection_settings['connection']:
2850+ connection_settings['connection']['uuid'] = str(uuid.uuid4())
2851+
2852+ NM = dbusmock.get_object(MAIN_OBJ)
2853+ settings_obj = dbusmock.get_object(SETTINGS_OBJ)
2854+ main_connections = settings_obj.ListConnections()
2855+
2856+ # Mimic how NM names connections
2857+ connection_name = str(len(main_connections))
2858+
2859+ connection_path = SETTINGS_OBJ + '/' + connection_name
2860+
2861+ if connection_path in main_connections:
2862+ raise dbus.exceptions.DBusException(
2863+ 'Connection %s already exists' % connection_path,
2864+ name=MAIN_IFACE + '.AlreadyExists',)
2865+
2866+ self.AddObject(
2867+ connection_path,
2868+ CSETTINGS_IFACE,
2869+ {
2870+ 'Settings': dbus.Dictionary(
2871+ connection_settings, signature='sa{sv}'
2872+ ),
2873+ 'Secrets': dbus.Dictionary({}, signature='sa{sv}'),
2874+ },
2875+ [
2876+ ('Delete', '', '', 'self.ConnectionDelete("%s")' %
2877+ connection_path),
2878+ (
2879+ 'GetSettings', '', 'a{sa{sv}}',
2880+ "ret = self.Get('%s', 'Settings')" % CSETTINGS_IFACE
2881+ ),
2882+ (
2883+ 'GetSecrets', 's', 'a{sa{sv}}',
2884+ "ret = self.Get('%s', 'Secrets')" % CSETTINGS_IFACE
2885+ ),
2886+ (
2887+ 'Update', 'a{sa{sv}}', '',
2888+ 'self.ConnectionUpdate("%s", args[0])' % connection_path
2889+ ),
2890+ ]
2891+ )
2892+
2893+ main_connections.append(connection_path)
2894+ settings_obj.Set(SETTINGS_IFACE, 'Connections', main_connections)
2895+
2896+ settings_obj.EmitSignal(
2897+ SETTINGS_IFACE, 'NewConnection', 'o', [connection_path]
2898+ )
2899+
2900+ auto_connect = False
2901+ if 'autoconnect' in connection_settings['connection']:
2902+ auto_connect = connection_settings['connection']['autoconnect']
2903+
2904+ if auto_connect:
2905+ dev = None
2906+ devices = NM.GetDevices()
2907+
2908+ # Grab the first device.
2909+ if len(devices) > 0:
2910+ dev = devices[0]
2911+
2912+ if dev:
2913+ activate_connection(NM, connection_path, dev, connection_path)
2914+
2915+ return connection_path
2916+
2917+
2918+@dbus.service.method(CSETTINGS_IFACE,
2919+ in_signature='oa{sa{sv}}', out_signature='')
2920+def ConnectionUpdate(self, connection_path, settings):
2921+ '''Update settings on a connection.
2922+
2923+ settings is a String String Variant Map Map. See
2924+ https://developer.gnome.org/NetworkManager/0.9/spec.html
2925+ #type-String_String_Variant_Map_Map
2926+ '''
2927+ NM = dbusmock.get_object(MAIN_OBJ)
2928+ settings_obj = dbusmock.get_object(SETTINGS_OBJ)
2929+ conn_obj = dbusmock.get_object(connection_path)
2930+
2931+ main_connections = settings_obj.ListConnections()
2932+
2933+ if connection_path not in main_connections:
2934+ raise dbus.exceptions.DBusException(
2935+ 'Connection %s does not exist' % connection_path,
2936+ name=MAIN_IFACE + '.DoesNotExist',)
2937+
2938+ conn_settings = conn_obj.Get(CSETTINGS_IFACE, 'Settings')
2939+ changed_settings = {}
2940+ for key, value in settings.items():
2941+ for k, v in value.items():
2942+ changed_settings[k] = v
2943+
2944+ if key not in conn_settings:
2945+ conn_settings[key] = dbus.Dictionary({}, signature='sv')
2946+
2947+ conn_settings[key][k] = v
2948+
2949+ conn_obj.Set(CSETTINGS_IFACE, 'Settings', conn_settings)
2950+
2951+ settings_obj.EmitSignal(
2952+ CSETTINGS_IFACE, 'PropertiesChanged', 'a{sv}', [changed_settings]
2953+ )
2954+ settings_obj.EmitSignal(CSETTINGS_IFACE, 'Updated', '', [])
2955+
2956+ auto_connect = False
2957+ if 'autoconnect' in settings['connection']:
2958+ auto_connect = settings['connection']['autoconnect']
2959+
2960+ if auto_connect:
2961+ dev = None
2962+ devices = NM.GetDevices()
2963+
2964+ # Grab the first device.
2965+ if len(devices) > 0:
2966+ dev = devices[0]
2967+
2968+ if dev:
2969+ activate_connection(NM, connection_path, dev, connection_path)
2970+
2971+ return connection_path
2972+
2973+
2974+@dbus.service.method(CSETTINGS_IFACE,
2975+ in_signature='o', out_signature='')
2976+def ConnectionDelete(self, connection_path):
2977+ '''Deletes a connection.
2978+
2979+ This also
2980+ * removes the deleted connection from any device,
2981+ * removes any active connection(s) it might be associated with,
2982+ * removes it from the Settings interface,
2983+ * as well as deletes the object from the mock.
2984+
2985+ Note: If this was the only active connection, we change the global
2986+ connection state.
2987+ '''
2988+ NM = dbusmock.get_object(MAIN_OBJ)
2989+ settings_obj = dbusmock.get_object(SETTINGS_OBJ)
2990+
2991+ # Find the associated active connection(s).
2992+ active_connections = NM.Get(MAIN_IFACE, 'ActiveConnections')
2993+ associated_active_connections = []
2994+ for ac in active_connections:
2995+ ac_obj = dbusmock.get_object(ac)
2996+ ac_con = ac_obj.Get(ACTIVE_CONNECTION_IFACE, 'Connection')
2997+ if ac_con == connection_path:
2998+ associated_active_connections.append(ac)
2999+
3000+ # We found that the connection we are deleting are associated to all
3001+ # active connections and subsequently set the global state to
3002+ # disconnected.
3003+ if len(active_connections) == len(associated_active_connections):
3004+ self.SetGlobalConnectionState(NMState.NM_STATE_DISCONNECTED)
3005+
3006+ # Remove the connection from all associated devices.
3007+ # We also remove all associated active connections.
3008+ for dev_path in NM.GetDevices():
3009+ dev_obj = dbusmock.get_object(dev_path)
3010+ connections = dev_obj.Get(DEVICE_IFACE, 'AvailableConnections')
3011+
3012+ for ac in associated_active_connections:
3013+ NM.RemoveActiveConnection(dev_path, ac)
3014+
3015+ if connection_path not in connections:
3016+ continue
3017+
3018+ connections.remove(dbus.ObjectPath(connection_path))
3019+ dev_obj.Set(DEVICE_IFACE, 'AvailableConnections', connections)
3020+
3021+ # Remove the connection from the settings interface
3022+ main_connections = settings_obj.ListConnections()
3023+ if connection_path not in main_connections:
3024+ return
3025+ main_connections.remove(connection_path)
3026+ settings_obj.Set(SETTINGS_IFACE, 'Connections', main_connections)
3027+ settings_obj.EmitSignal(
3028+ SETTINGS_IFACE, 'ConnectionRemoved', 'o', [connection_path]
3029+ )
3030+
3031+ # Remove the connection from the mock
3032+ connection_obj = dbusmock.get_object(connection_path)
3033+ connection_obj.EmitSignal(CSETTINGS_IFACE, 'Removed', '', [])
3034+ self.RemoveObject(connection_path)
3035
3036=== modified file 'tests/autopilot/ubuntu_system_settings/tests/test_wifi.py'
3037--- tests/autopilot/ubuntu_system_settings/tests/test_wifi.py 2015-04-08 12:15:56 +0000
3038+++ tests/autopilot/ubuntu_system_settings/tests/test_wifi.py 2015-07-01 18:56:14 +0000
3039@@ -6,8 +6,13 @@
3040 # by the Free Software Foundation.
3041
3042 from __future__ import absolute_import
3043+
3044+import dbus
3045+
3046 from autopilot.matchers import Eventually
3047-from dbusmock.templates.networkmanager import DEVICE_IFACE
3048+from dbusmock.templates.networkmanager import (
3049+ DEVICE_IFACE, NM80211ApSecurityFlags
3050+)
3051 from testtools.matchers import Equals
3052 from time import sleep
3053 from ubuntu_system_settings.tests import WifiBaseTestCase
3054@@ -18,6 +23,12 @@
3055 class WifiTestCase(WifiBaseTestCase):
3056 """Tests for Language Page"""
3057
3058+ def setUp(self):
3059+ super(WifiTestCase, self).setUp()
3060+
3061+ self.wifi_page._scroll_to_and_click = \
3062+ self.main_view.scroll_to_and_click
3063+
3064 def test_wifi_page_title_is_correct(self):
3065 """Checks whether Wifi page is available"""
3066 self.assertThat(
3067@@ -32,14 +43,62 @@
3068 self.wifi_page.enable_wireless()
3069 dialog = self.wifi_page.connect_to_hidden_network(
3070 'test_ap',
3071- scroll_to_and_click=self.main_view
3072- .scroll_to_and_click)
3073-
3074- # allow backend to set up listeners
3075- sleep(0.3)
3076-
3077- if dialog:
3078- dialog.wait_until_destroyed()
3079+ password='abcdefgh',)
3080+
3081+ # allow backend to set up listeners
3082+ sleep(0.3)
3083+
3084+ if dialog:
3085+ dialog.wait_until_destroyed()
3086+
3087+ def test_connect_to_eduroam(self):
3088+ if not self.wifi_page.have_wireless():
3089+ self.skipTest('Cannot test wireless since it cannot be enabled')
3090+ self.addCleanup(
3091+ self.wifi_page._set_wireless, self.wifi_page.get_wireless())
3092+ self.wifi_page.enable_wireless()
3093+ self.create_access_point(
3094+ 'eduroam', 'eduroam',
3095+ security=NM80211ApSecurityFlags.NM_802_11_AP_SEC_KEY_MGMT_802_1X
3096+ )
3097+
3098+ dialog = self.wifi_page.connect_to_hidden_network(
3099+ 'eduroam',
3100+ username='student',
3101+ password='abcdefgh',
3102+ security='wpa-ep',
3103+ auth='peap',
3104+ protocol='mschapv2',
3105+ )
3106+
3107+ # allow backend to set up listeners
3108+ sleep(0.3)
3109+
3110+ if dialog:
3111+ dialog.wait_until_destroyed()
3112+
3113+ dev = dbus.Interface(self.dbus_con.get_object(
3114+ 'org.freedesktop.NetworkManager', self.device_path),
3115+ 'org.freedesktop.DBus.Properties')
3116+
3117+ conn_obj = dev.Get(
3118+ 'org.freedesktop.NetworkManager.Device', 'AvailableConnections'
3119+ )[0]
3120+ conn = dbus.Interface(self.dbus_con.get_object(
3121+ 'org.freedesktop.NetworkManager', conn_obj),
3122+ 'org.freedesktop.NetworkManager.Settings.Connection')
3123+
3124+ conn_settings = conn.GetSettings()
3125+ wconn = conn_settings['connection']
3126+ w802_11_sec = conn_settings['802-11-wireless-security']
3127+ w802_1x = conn_settings['802-1x']
3128+
3129+ self.assertEquals(wconn['type'], '802-11-wireless')
3130+ self.assertEquals(w802_11_sec['key-mgmt'], 'wpa-eap')
3131+ self.assertIn('peap', w802_1x['eap'])
3132+ self.assertEquals(w802_1x['identity'], 'student')
3133+ self.assertEquals(w802_1x['password'], 'abcdefgh')
3134+ self.assertEquals(w802_1x['phase2-auth'], 'mschapv2')
3135
3136 def test_connect_to_nonexistant_hidden_network(self):
3137 if not self.wifi_page.have_wireless():
3138@@ -49,8 +108,8 @@
3139 self.wifi_page.enable_wireless()
3140 dialog = self.wifi_page.connect_to_hidden_network(
3141 'n/a',
3142- scroll_to_and_click=self.main_view
3143- .scroll_to_and_click)
3144+ password='abcdefgh',
3145+ )
3146
3147 # allow backend to set up listeners
3148 sleep(0.3)
3149@@ -84,8 +143,7 @@
3150 self.wifi_page.enable_wireless()
3151 dialog = self.wifi_page.connect_to_hidden_network(
3152 'test_ap', security='wpa', password='abcdefgh',
3153- scroll_to_and_click=self.main_view
3154- .scroll_to_and_click)
3155+ )
3156
3157 # allow backend to set up listeners
3158 sleep(0.3)
3159@@ -102,9 +160,10 @@
3160 self.wifi_page._set_wireless, self.wifi_page.get_wireless())
3161 self.wifi_page.enable_wireless()
3162 dialog = self.wifi_page.connect_to_hidden_network(
3163- 'test_ap', security='wpa', password='abcdefgh',
3164- scroll_to_and_click=self.main_view
3165- .scroll_to_and_click)
3166+ 'test_ap',
3167+ security='wpa',
3168+ password='abcdefgh',
3169+ )
3170
3171 # allow backend to set up listeners
3172 sleep(0.3)
3173@@ -120,10 +179,7 @@
3174 self.addCleanup(
3175 self.wifi_page._set_wireless, self.wifi_page.get_wireless())
3176 self.wifi_page.enable_wireless()
3177- dialog = self.wifi_page.connect_to_hidden_network(
3178- 'foo',
3179- scroll_to_and_click=self.main_view
3180- .scroll_to_and_click)
3181+ dialog = self.wifi_page.connect_to_hidden_network('foo',)
3182
3183 # allow backend to set up listeners
3184 sleep(0.3)
3185@@ -131,8 +187,7 @@
3186 dialog.cancel()
3187
3188 self.assertThat(
3189- lambda:
3190- len(self.active_connection_mock.GetMethodCalls('Delete')),
3191+ lambda: len(self.active_connection_mock.GetMethodCalls('Delete')),
3192 Eventually(Equals(1)))
3193
3194 def test_connect_to_hidden_network_dialog_visibility(self):
3195@@ -148,8 +203,6 @@
3196 Eventually(Equals(False)), 'other net dialog not hidden')
3197
3198 def test_remove_previous_network(self):
3199- click_method = self.main_view.scroll_to_and_click
3200-
3201 access_points = ['Series of Tubes', 'dev/null', 'Mi-Fi',
3202 'MonkeySphere']
3203
3204@@ -158,16 +211,14 @@
3205 self.dbusmock.AddWiFiConnection(
3206 self.device_path, 'Mock_Con%d' % idx, ssid, '')
3207
3208- self.wifi_page.remove_previous_network(
3209- access_points[0], scroll_to_and_click=click_method)
3210+ self.wifi_page.remove_previous_network(access_points[0],)
3211
3212 self.main_view.go_back()
3213
3214 # wait for ui to update
3215 sleep(2)
3216
3217- self.wifi_page.remove_previous_network(
3218- access_points[2], scroll_to_and_click=click_method)
3219+ self.wifi_page.remove_previous_network(access_points[2],)
3220
3221 # We cannot make any assertions, because connection deletion
3222 # is currently not supported.

Subscribers

People subscribed via source and target branches