[libnma/lr/wireless-security: 5/7] nmaws



commit 137f815c589ff82826624028af865024a59100ca
Author: Lubomir Rintel <lkundrak v3 sk>
Date:   Tue Oct 22 06:52:27 2019 +0200

    nmaws

 Makefile.am                      |  67 ++++-
 src/libnma.ver                   |  21 ++
 src/nma-ws/meson.build           |  75 +++++
 src/nma-ws/nma-eap-fast.c        | 439 +++++++++++++++++++++++++++++
 src/nma-ws/nma-eap-fast.h        |  21 ++
 src/nma-ws/nma-eap-fast.ui       | 183 ++++++++++++
 src/nma-ws/nma-eap-leap.c        | 255 +++++++++++++++++
 src/nma-ws/nma-eap-leap.h        |  19 ++
 src/nma-ws/nma-eap-leap.ui       |  99 +++++++
 src/nma-ws/nma-eap-peap.c        | 498 ++++++++++++++++++++++++++++++++
 src/nma-ws/nma-eap-peap.h        |  20 ++
 src/nma-ws/nma-eap-peap.ui       | 215 ++++++++++++++
 src/nma-ws/nma-eap-simple.c      | 483 +++++++++++++++++++++++++++++++
 src/nma-ws/nma-eap-simple.h      |  49 ++++
 src/nma-ws/nma-eap-simple.ui     | 158 +++++++++++
 src/nma-ws/nma-eap-tls.c         | 517 ++++++++++++++++++++++++++++++++++
 src/nma-ws/nma-eap-tls.h         |  20 ++
 src/nma-ws/nma-eap-tls.ui        | 106 +++++++
 src/nma-ws/nma-eap-ttls.c        | 535 +++++++++++++++++++++++++++++++++++
 src/nma-ws/nma-eap-ttls.h        |  20 ++
 src/nma-ws/nma-eap-ttls.ui       | 165 +++++++++++
 src/nma-ws/nma-eap.c             | 431 ++++++++++++++++++++++++++++
 src/nma-ws/nma-eap.h             | 120 ++++++++
 src/nma-ws/nma-ws-dynamic-wep.c  | 117 ++++++++
 src/nma-ws/nma-ws-dynamic-wep.h  |  17 ++
 src/nma-ws/nma-ws-dynamic-wep.ui |  87 ++++++
 src/nma-ws/nma-ws-leap.c         | 205 ++++++++++++++
 src/nma-ws/nma-ws-leap.h         |  15 +
 src/nma-ws/nma-ws-leap.ui        | 100 +++++++
 src/nma-ws/nma-ws-sae.c          | 202 +++++++++++++
 src/nma-ws/nma-ws-sae.h          |  16 ++
 src/nma-ws/nma-ws-sae.ui         |  98 +++++++
 src/nma-ws/nma-ws-wep-key.c      | 353 +++++++++++++++++++++++
 src/nma-ws/nma-ws-wep-key.h      |  18 ++
 src/nma-ws/nma-ws-wep-key.ui     | 172 ++++++++++++
 src/nma-ws/nma-ws-wpa-eap.c      | 119 ++++++++
 src/nma-ws/nma-ws-wpa-eap.h      |  18 ++
 src/nma-ws/nma-ws-wpa-eap.ui     |  87 ++++++
 src/nma-ws/nma-ws-wpa-psk.c      | 218 ++++++++++++++
 src/nma-ws/nma-ws-wpa-psk.h      |  15 +
 src/nma-ws/nma-ws-wpa-psk.ui     |  98 +++++++
 src/nma-ws/nma-ws.c              | 593 +++++++++++++++++++++++++++++++++++++++
 src/nma-ws/nma-ws.h              | 135 +++++++++
 src/nma.gresource.xml            |  12 +
 44 files changed, 7208 insertions(+), 3 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index cd0b51f5..3cd1082d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -284,7 +284,22 @@ libnma_h_pub = \
        src/nma-ui-utils.h \
        src/nma-cert-chooser.h \
        src/nma-bar-code-widget.h \
-       src/nma-bar-code.h
+       src/nma-bar-code.h \
+       \
+       src/nma-ws/nma-ws-dynamic-wep.h \
+       src/nma-ws/nma-ws-leap.h \
+       src/nma-ws/nma-ws-sae.h \
+       src/nma-ws/nma-ws-wep-key.h \
+       src/nma-ws/nma-ws-wpa-eap.h \
+       src/nma-ws/nma-ws-wpa-psk.h \
+       src/nma-ws/nma-eap-fast.h \
+       src/nma-ws/nma-eap.h \
+       src/nma-ws/nma-eap-leap.h \
+       src/nma-ws/nma-eap-peap.h \
+       src/nma-ws/nma-eap-simple.h \
+       src/nma-ws/nma-eap-tls.h \
+       src/nma-ws/nma-eap-ttls.h \
+       src/nma-ws/nma-ws.h
 
 libnma_c_real = \
        src/nma-wifi-dialog.c \
@@ -296,7 +311,36 @@ libnma_c_real = \
        src/nma-cert-chooser.c \
        src/nma-file-cert-chooser.c \
        src/nma-bar-code-widget.c \
-       src/nma-bar-code.c
+       src/nma-bar-code.c \
+       \
+       src/nma-ws/nma-ws.h \
+       src/nma-ws/nma-ws.c \
+       src/nma-ws/nma-ws-sae.h \
+       src/nma-ws/nma-ws-sae.c \
+       src/nma-ws/nma-ws-wep-key.h \
+       src/nma-ws/nma-ws-wep-key.c \
+       src/nma-ws/nma-ws-wpa-psk.h \
+       src/nma-ws/nma-ws-wpa-psk.c \
+       src/nma-ws/nma-ws-leap.h \
+       src/nma-ws/nma-ws-leap.c \
+       src/nma-ws/nma-ws-wpa-eap.h \
+       src/nma-ws/nma-ws-wpa-eap.c \
+       src/nma-ws/nma-ws-dynamic-wep.h \
+       src/nma-ws/nma-ws-dynamic-wep.c \
+       src/nma-ws/nma-eap.h \
+       src/nma-ws/nma-eap.c \
+       src/nma-ws/nma-eap-tls.h \
+       src/nma-ws/nma-eap-tls.c \
+       src/nma-ws/nma-eap-leap.h \
+       src/nma-ws/nma-eap-leap.c \
+       src/nma-ws/nma-eap-fast.h \
+       src/nma-ws/nma-eap-fast.c \
+       src/nma-ws/nma-eap-ttls.h \
+       src/nma-ws/nma-eap-ttls.c \
+       src/nma-ws/nma-eap-peap.h \
+       src/nma-ws/nma-eap-peap.c \
+       src/nma-ws/nma-eap-simple.h \
+       src/nma-ws/nma-eap-simple.c
 
 EXTRA_DIST += \
        src/qrcodegen.c \
@@ -456,6 +500,8 @@ src_tests_wireless_security_CPPFLAGS = \
        $(LIBNM_CFLAGS) \
        "-I$(srcdir)/shared/" \
        "-I$(srcdir)/src" \
+       "-I$(srcdir)/src/wireless-security" \
+       "-I$(srcdir)/src/nma-ws" \
        -Isrc
 
 src_tests_wireless_security_LDADD = \
@@ -563,6 +609,7 @@ src_libnma_gtk4_la_CFLAGS = \
        "-I$(srcdir)/shared" \
        "-I$(srcdir)/src/utils" \
        "-I$(srcdir)/src/wireless-security" \
+       "-I$(srcdir)/src/nma-ws" \
        "-I$(srcdir)/src" \
        -Isrc \
        $(GTK4_CFLAGS) \
@@ -763,7 +810,21 @@ EXTRA_DIST += \
        src/nma-vpn-password-dialog.ui \
        src/nma.gresource.xml \
        src/meson.build \
-       src/tests/meson.build
+       src/tests/meson.build \
+       \
+       src/nma-ws/nma-eap-fast.ui \
+       src/nma-ws/nma-eap-leap.ui \
+       src/nma-ws/nma-eap-peap.ui \
+       src/nma-ws/nma-eap-simple.ui \
+       src/nma-ws/nma-eap-tls.ui \
+       src/nma-ws/nma-eap-ttls.ui \
+       src/nma-ws/nma-ws-dynamic-wep.ui \
+       src/nma-ws/nma-ws-leap.ui \
+       src/nma-ws/nma-ws-sae.ui \
+       src/nma-ws/nma-ws-wep-key.ui \
+       src/nma-ws/nma-ws-wpa-eap.ui \
+       src/nma-ws/nma-ws-wpa-psk.ui \
+       src/nma-ws/meson.build
 
 ###############################################################################
 
diff --git a/src/libnma.ver b/src/libnma.ver
index 9b263d9c..7b25e9c8 100644
--- a/src/libnma.ver
+++ b/src/libnma.ver
@@ -112,3 +112,24 @@ libnma_1_8_22 {
        nma_bar_code_widget_get_type;
        nma_bar_code_widget_new;
 } libnma_1_8_12;
+
+libnma_1_8_28 {
+       nma_eap_get_type;
+       nma_eap_method_ca_cert_ignore_load;
+       nma_eap_method_ca_cert_ignore_save;
+       nma_ws_802_1x_fill_connection;
+       nma_ws_add_to_size_group;
+       nma_ws_adhoc_compatible;
+       nma_ws_dynamic_wep_new;
+       nma_ws_fill_connection;
+       nma_ws_get_type;
+       nma_ws_get_widget;
+       nma_ws_leap_new;
+       nma_ws_sae_new;
+       nma_ws_set_changed_notify;
+       nma_ws_unref;
+       nma_ws_validate;
+       nma_ws_wep_key_new;
+       nma_ws_wpa_eap_new;
+       nma_ws_wpa_psk_new;
+} libnma_1_8_22;
diff --git a/src/nma-ws/meson.build b/src/nma-ws/meson.build
new file mode 100644
index 00000000..a577962d
--- /dev/null
+++ b/src/nma-ws/meson.build
@@ -0,0 +1,75 @@
+nma_ws_inc = include_directories('.')
+
+sources = [version_header] + files(
+  'nma-eap.c',
+  'nma-eap-fast.c',
+  'nma-eap-leap.c',
+  'nma-eap-peap.c',
+  'nma-eap-simple.c',
+  'nma-eap-tls.c',
+  'nma-eap-ttls.c',
+  'helpers.c',
+  'wireless-security.c',
+  'ws-dynamic-wep.c',
+  'ws-leap.c',
+  'ws-sae.c',
+  'ws-wep-key.c',
+  'ws-wpa-eap.c',
+  'ws-wpa-psk.c'
+)
+
+resource_data = files(
+  'nma-eap-fast.ui',
+  'nma-eap-leap.ui',
+  'nma-eap-peap.ui',
+  'nma-eap-simple.ui',
+  'nma-eap-tls.ui',
+  'nma-eap-ttls.ui',
+  'ws-dynamic-wep.ui',
+  'ws-leap.ui',
+  'ws-sae.ui',
+  'ws-wep-key.ui',
+  'ws-wpa-eap.ui',
+  'ws-wpa-psk.ui'
+)
+
+sources += gnome.compile_resources(
+  'ws-resources',
+  'ws.gresource.xml',
+  dependencies: resource_data
+)
+
+incs = [
+  top_inc,
+  shared_inc,
+  src_inc
+]
+
+deps = [
+  gtk_dep,
+  libnm_dep,
+  libutils_libnm_dep
+]
+
+libnma_ws_libnm = static_library(
+  'wireless-security-libnm',
+  sources: sources,
+  include_directories: incs,
+  dependencies: deps
+)
+
+if enable_libnma_gtk4
+  deps = [
+    gtk4_dep,
+    libnm_dep,
+    libutils_libnm_dep
+  ]
+
+  libnma_ws_libnma_gtk4 = static_library(
+    'wireless-security-libnma-gtk4',
+    sources: sources,
+    include_directories: incs,
+    dependencies: deps,
+    c_args: cflags
+  )
+endif
diff --git a/src/nma-ws/nma-eap-fast.c b/src/nma-ws/nma-eap-fast.c
new file mode 100644
index 00000000..1ee93e49
--- /dev/null
+++ b/src/nma-ws/nma-eap-fast.c
@@ -0,0 +1,439 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * EAP-FAST authentication method (RFC4851)
+ *
+ * Copyright 2012 - 2019 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+#include "nma-private.h"
+
+#include <ctype.h>
+#include <string.h>
+
+#include "nma-eap.h"
+#include "nma-ws.h"
+#include "utils.h"
+#include "helpers.h"
+
+#define I_NAME_COLUMN   0
+#define I_METHOD_COLUMN 1
+
+struct _NMAEapFAST {
+       NMAEap parent;
+
+       const char *password_flags_name;
+       GtkSizeGroup *size_group;
+       NMAWs *sec_parent;
+       gboolean is_editor;
+};
+
+static void
+destroy (NMAEap *parent)
+{
+       NMAEapFAST *method = (NMAEapFAST *) parent;
+
+       if (method->size_group)
+               g_object_unref (method->size_group);
+}
+
+static gboolean
+validate (NMAEap *parent, GError **error)
+{
+       GtkWidget *widget;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       NMAEap *eap = NULL;
+       const char *file;
+       gboolean provisioning;
+       gboolean valid = TRUE;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_provision_checkbutton"));
+       g_assert (widget);
+       provisioning = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_file_button"));
+       g_assert (widget);
+       file = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
+       if (!provisioning && !file) {
+               widget_set_error (widget);
+               g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("missing EAP-FAST PAC file"));
+               valid = FALSE;
+       } else
+               widget_unset_error (widget);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_inner_auth_combo"));
+       g_assert (widget);
+       model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
+       gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter);
+       gtk_tree_model_get (model, &iter, I_METHOD_COLUMN, &eap, -1);
+       g_assert (eap);
+       valid = nma_eap_validate (eap, valid ? error : NULL) && valid;
+       nma_eap_unref (eap);
+       return valid;
+}
+
+static void
+add_to_size_group (NMAEap *parent, GtkSizeGroup *group)
+{
+       NMAEapFAST *method = (NMAEapFAST *) parent;
+       GtkWidget *widget;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       NMAEap *eap;
+
+       if (method->size_group)
+               g_object_unref (method->size_group);
+       method->size_group = g_object_ref (group);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_anon_identity_label"));
+       g_assert (widget);
+       gtk_size_group_add_widget (group, widget);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_file_label"));
+       g_assert (widget);
+       gtk_size_group_add_widget (group, widget);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_provision_checkbutton"));
+       g_assert (widget);
+       gtk_size_group_add_widget (group, widget);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_inner_auth_label"));
+       g_assert (widget);
+       gtk_size_group_add_widget (group, widget);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_inner_auth_combo"));
+       g_assert (widget);
+
+       model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
+       gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter);
+       gtk_tree_model_get (model, &iter, I_METHOD_COLUMN, &eap, -1);
+       g_assert (eap);
+       nma_eap_add_to_size_group (eap, group);
+       nma_eap_unref (eap);
+}
+
+static void
+fill_connection (NMAEap *parent, NMConnection *connection)
+{
+       NMSetting8021x *s_8021x;
+       GtkWidget *widget;
+       const char *text;
+       char *filename;
+       NMAEap *eap = NULL;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       gboolean enabled;
+       int pac_provisioning = 0;
+
+       s_8021x = nm_connection_get_setting_802_1x (connection);
+       g_assert (s_8021x);
+
+       nm_setting_802_1x_add_eap_method (s_8021x, "fast");
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_anon_identity_entry"));
+       g_assert (widget);
+       text = gtk_editable_get_text (GTK_EDITABLE (widget));
+       if (text && strlen (text))
+               g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, text, NULL);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_file_button"));
+       g_assert (widget);
+       filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
+       g_object_set (s_8021x, NM_SETTING_802_1X_PAC_FILE, filename, NULL);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_provision_checkbutton"));
+       enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+
+       if (!enabled)
+               g_object_set (G_OBJECT (s_8021x), NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING, "0", NULL);
+       else {
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, 
"eap_fast_pac_provision_combo"));
+               pac_provisioning = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
+
+               switch (pac_provisioning) {
+               case 0:  /* Anonymous */
+                       g_object_set (G_OBJECT (s_8021x), NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING, "1", 
NULL);
+                       break;
+               case 1:  /* Authenticated */
+                       g_object_set (G_OBJECT (s_8021x), NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING, "2", 
NULL);
+                       break;
+               case 2:  /* Both - anonymous and authenticated */
+                       g_object_set (G_OBJECT (s_8021x), NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING, "3", 
NULL);
+                       break;
+               default: /* Should not happen */
+                       g_object_set (G_OBJECT (s_8021x), NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING, "1", 
NULL);
+                       break;
+               }
+       }
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_inner_auth_combo"));
+       model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
+       gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter);
+       gtk_tree_model_get (model, &iter, I_METHOD_COLUMN, &eap, -1);
+       g_assert (eap);
+
+       nma_eap_fill_connection (eap, connection);
+       nma_eap_unref (eap);
+}
+
+static void
+inner_auth_combo_changed_cb (GtkWidget *combo, gpointer user_data)
+{
+       NMAEap *parent = (NMAEap *) user_data;
+       NMAEapFAST *method = (NMAEapFAST *) parent;
+       GtkWidget *vbox;
+       NMAEap *eap = NULL;
+       GList *elt, *children;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       GtkWidget *eap_widget;
+
+       vbox = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_inner_auth_vbox"));
+       g_assert (vbox);
+
+       /* Remove any previous wireless security widgets */
+       children = gtk_container_get_children (GTK_CONTAINER (vbox));
+       for (elt = children; elt; elt = g_list_next (elt))
+               gtk_container_remove (GTK_CONTAINER (vbox), GTK_WIDGET (elt->data));
+       g_list_free (children);
+
+       model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
+       gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter);
+       gtk_tree_model_get (model, &iter, I_METHOD_COLUMN, &eap, -1);
+       g_assert (eap);
+
+       eap_widget = nma_eap_get_widget (eap);
+       g_assert (eap_widget);
+       gtk_widget_unparent (eap_widget);
+
+       if (method->size_group)
+               nma_eap_add_to_size_group (eap, method->size_group);
+       gtk_container_add (GTK_CONTAINER (vbox), eap_widget);
+
+       nma_eap_unref (eap);
+
+       nma_ws_changed_cb (combo, method->sec_parent);
+}
+
+static GtkWidget *
+inner_auth_combo_init (NMAEapFAST *method,
+                       NMConnection *connection,
+                       NMSetting8021x *s_8021x,
+                       gboolean secrets_only)
+{
+       NMAEap *parent = (NMAEap *) method;
+       GtkWidget *combo;
+       GtkListStore *auth_model;
+       GtkTreeIter iter;
+       NMAEapSimple *em_gtc;
+       NMAEapSimple *em_mschap_v2;
+       guint32 active = 0;
+       const char *phase2_auth = NULL;
+       NMAEapSimpleFlags simple_flags;
+
+       auth_model = gtk_list_store_new (2, G_TYPE_STRING, nma_eap_get_type ());
+
+       if (s_8021x) {
+               if (nm_setting_802_1x_get_phase2_auth (s_8021x))
+                       phase2_auth = nm_setting_802_1x_get_phase2_auth (s_8021x);
+               else if (nm_setting_802_1x_get_phase2_autheap (s_8021x))
+                       phase2_auth = nm_setting_802_1x_get_phase2_autheap (s_8021x);
+       }
+
+       simple_flags = NMA_EAP_SIMPLE_FLAG_PHASE2;
+       if (method->is_editor)
+               simple_flags |= NMA_EAP_SIMPLE_FLAG_IS_EDITOR;
+       if (secrets_only)
+               simple_flags |= NMA_EAP_SIMPLE_FLAG_SECRETS_ONLY;
+
+       em_gtc = nma_eap_simple_new (method->sec_parent,
+                                       connection,
+                                       NMA_EAP_SIMPLE_TYPE_GTC,
+                                       simple_flags,
+                                       NULL);
+       gtk_list_store_append (auth_model, &iter);
+       gtk_list_store_set (auth_model, &iter,
+                           I_NAME_COLUMN, _("GTC"),
+                           I_METHOD_COLUMN, em_gtc,
+                           -1);
+       nma_eap_unref (NMA_EAP (em_gtc));
+
+       /* Check for defaulting to GTC */
+       if (phase2_auth && !strcasecmp (phase2_auth, "gtc"))
+               active = 0;
+
+       em_mschap_v2 = nma_eap_simple_new (method->sec_parent,
+                                             connection,
+                                             NMA_EAP_SIMPLE_TYPE_MSCHAP_V2,
+                                             simple_flags,
+                                             NULL);
+       gtk_list_store_append (auth_model, &iter);
+       gtk_list_store_set (auth_model, &iter,
+                           I_NAME_COLUMN, _("MSCHAPv2"),
+                           I_METHOD_COLUMN, em_mschap_v2,
+                           -1);
+       nma_eap_unref (NMA_EAP (em_mschap_v2));
+
+       /* Check for defaulting to MSCHAPv2 */
+       if (phase2_auth && !strcasecmp (phase2_auth, "mschapv2"))
+               active = 1;
+
+       combo = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_inner_auth_combo"));
+       g_assert (combo);
+
+       gtk_combo_box_set_model (GTK_COMBO_BOX (combo), GTK_TREE_MODEL (auth_model));
+       g_object_unref (G_OBJECT (auth_model));
+       gtk_combo_box_set_active (GTK_COMBO_BOX (combo), active);
+
+       g_signal_connect (G_OBJECT (combo), "changed",
+                         (GCallback) inner_auth_combo_changed_cb,
+                         method);
+       return combo;
+}
+
+static void
+update_secrets (NMAEap *parent, NMConnection *connection)
+{
+       nma_eap_phase2_update_secrets_helper (parent,
+                                             connection,
+                                             "eap_fast_inner_auth_combo",
+                                             I_METHOD_COLUMN);
+}
+
+static void
+pac_toggled_cb (GtkWidget *widget, gpointer user_data)
+{
+       NMAEap *parent = (NMAEap *) user_data;
+       NMAEapFAST *method = (NMAEapFAST *) parent;
+       gboolean enabled = FALSE;
+       GtkWidget *provision_combo;
+
+       provision_combo = GTK_WIDGET (gtk_builder_get_object (parent->builder, 
"eap_fast_pac_provision_combo"));
+       g_return_if_fail (provision_combo);
+
+       enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+
+       gtk_widget_set_sensitive (provision_combo, enabled);
+
+       nma_ws_changed_cb (widget, method->sec_parent);
+}
+
+NMAEapFAST *
+nma_eap_fast_new (NMAWs *ws_parent,
+                  NMConnection *connection,
+                  gboolean is_editor,
+                  gboolean secrets_only)
+{
+       NMAEap *parent;
+       NMAEapFAST *method;
+       GtkWidget *widget;
+       GtkFileFilter *filter;
+       NMSetting8021x *s_8021x = NULL;
+       const char *filename;
+       gboolean provisioning_enabled = TRUE;
+
+       parent = nma_eap_init (sizeof (NMAEapFAST),
+                              validate,
+                              add_to_size_group,
+                              fill_connection,
+                              update_secrets,
+                              destroy,
+                              "/org/gnome/libnma/nma-eap-fast.ui",
+                              "eap_fast_notebook",
+                              "eap_fast_anon_identity_entry",
+                              FALSE);
+       if (!parent)
+               return NULL;
+
+       method = (NMAEapFAST *) parent;
+       method->password_flags_name = NM_SETTING_802_1X_PASSWORD;
+       method->sec_parent = ws_parent;
+       method->is_editor = is_editor;
+
+       if (connection)
+               s_8021x = nm_connection_get_setting_802_1x (connection);
+
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_provision_combo"));
+       g_assert (widget);
+       gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
+       if (s_8021x) {
+               const char *fast_prov;
+
+               fast_prov = nm_setting_802_1x_get_phase1_fast_provisioning (s_8021x);
+               if (fast_prov) {
+                       if (!strcmp (fast_prov, "0"))
+                               provisioning_enabled = FALSE;
+                       else if (!strcmp (fast_prov, "1"))
+                               gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
+                       else if (!strcmp (fast_prov, "2"))
+                               gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 1);
+                       else if (!strcmp (fast_prov, "3"))
+                               gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 2);
+               }
+       }
+       gtk_widget_set_sensitive (widget, provisioning_enabled);
+       g_signal_connect (G_OBJECT (widget), "changed",
+                         (GCallback) nma_ws_changed_cb,
+                         ws_parent);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_provision_checkbutton"));
+       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), provisioning_enabled);
+       g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (pac_toggled_cb), parent);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_anon_identity_entry"));
+       if (s_8021x && nm_setting_802_1x_get_anonymous_identity (s_8021x))
+               gtk_editable_set_text (GTK_EDITABLE (widget), nm_setting_802_1x_get_anonymous_identity 
(s_8021x));
+       g_signal_connect (G_OBJECT (widget), "changed",
+                         (GCallback) nma_ws_changed_cb,
+                         ws_parent);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_file_button"));
+       g_assert (widget);
+       gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (widget), TRUE);
+       gtk_file_chooser_button_set_title (GTK_FILE_CHOOSER_BUTTON (widget),
+                                          _("Choose a PAC file"));
+       g_signal_connect (G_OBJECT (widget), "selection-changed",
+                         (GCallback) nma_ws_changed_cb,
+                         ws_parent);
+
+       filter = gtk_file_filter_new ();
+       gtk_file_filter_add_pattern (filter, "*.pac");
+       gtk_file_filter_set_name (filter, _("PAC files (*.pac)"));
+       gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (widget), filter);
+       filter = gtk_file_filter_new ();
+       gtk_file_filter_add_pattern (filter, "*");
+       gtk_file_filter_set_name (filter, _("All files"));
+       gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (widget), filter);
+
+       if (connection && s_8021x) {
+               filename = nm_setting_802_1x_get_pac_file (s_8021x);
+               if (filename)
+                       gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget), filename);
+       }
+
+       widget = inner_auth_combo_init (method, connection, s_8021x, secrets_only);
+       inner_auth_combo_changed_cb (widget, (gpointer) method);
+
+       if (secrets_only) {
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, 
"eap_fast_anon_identity_label"));
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, 
"eap_fast_anon_identity_entry"));
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, 
"eap_fast_pac_provision_checkbutton"));
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, 
"eap_fast_pac_provision_combo"));
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_file_label"));
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_file_button"));
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_inner_auth_label"));
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_inner_auth_combo"));
+               gtk_widget_hide (widget);
+       }
+
+       return method;
+}
+
diff --git a/src/nma-ws/nma-eap-fast.h b/src/nma-ws/nma-eap-fast.h
new file mode 100644
index 00000000..a1ece4df
--- /dev/null
+++ b/src/nma-ws/nma-eap-fast.h
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * EAP-FAST authentication method (RFC4851)
+ *
+ * Copyright 2012 - 2019 Red Hat, Inc.
+ */
+
+#ifndef NMA_EAP_FAST_H
+#define NMA_EAP_FAST_H
+
+#include "nma-ws.h"
+
+typedef struct _NMAEapFAST NMAEapFAST;
+
+NMAEapFAST *nma_eap_fast_new (NMAWs *ws_parent,
+                              NMConnection *connection,
+                              gboolean is_editor,
+                              gboolean secrets_only);
+
+#endif /* NMA_EAP_FAST_H */
+
diff --git a/src/nma-ws/nma-eap-fast.ui b/src/nma-ws/nma-eap-fast.ui
new file mode 100644
index 00000000..774a0921
--- /dev/null
+++ b/src/nma-ws/nma-eap-fast.ui
@@ -0,0 +1,183 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface domain="nm-applet">
+  <requires lib="gtk+" version="3.10"/>
+  <object class="GtkListStore" id="model8">
+    <columns>
+      <!-- column-name gchararray -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0"> </col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkListStore" id="model9">
+    <columns>
+      <!-- column-name gchararray -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">Anonymous</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Authenticated</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Both</col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkNotebook" id="eap_fast_notebook">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="show_tabs">False</property>
+    <property name="show_border">False</property>
+    <child>
+      <object class="GtkGrid" id="table13">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="row_spacing">6</property>
+        <property name="column_spacing">6</property>
+        <child>
+          <object class="GtkLabel" id="eap_fast_anon_identity_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Anony_mous identity</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">eap_fast_anon_identity_entry</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="eap_fast_anon_identity_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+            <property name="activates_default">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="eap_fast_pac_file_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">PAC _file</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">eap_fast_pac_file_button</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkFileChooserButton" id="eap_fast_pac_file_button">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox" id="eap_fast_inner_auth_vbox">
+            <property name="orientation">vertical</property>
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">4</property>
+            <property name="width">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="eap_fast_inner_auth_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">_Inner authentication</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">eap_fast_inner_auth_combo</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">3</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkComboBox" id="eap_fast_inner_auth_combo">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="model">model8</property>
+            <child>
+              <object class="GtkCellRendererText" id="renderer8"/>
+              <attributes>
+                <attribute name="text">0</attribute>
+              </attributes>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">3</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="eap_fast_pac_provision_checkbutton">
+            <property name="label" translatable="yes">Allow automatic PAC pro_visioning</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="use_underline">True</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkComboBox" id="eap_fast_pac_provision_combo">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="model">model9</property>
+            <child>
+              <object class="GtkCellRendererText" id="renderer9"/>
+              <attributes>
+                <attribute name="text">0</attribute>
+              </attributes>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <child type="tab">
+      <object class="GtkLabel" id="label61">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+      </object>
+      <packing>
+        <property name="tab_fill">False</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/src/nma-ws/nma-eap-leap.c b/src/nma-ws/nma-eap-leap.c
new file mode 100644
index 00000000..6d316edb
--- /dev/null
+++ b/src/nma-ws/nma-eap-leap.c
@@ -0,0 +1,255 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+#include "nma-private.h"
+
+#include <ctype.h>
+#include <string.h>
+
+#include "nma-eap.h"
+#include "nma-ws.h"
+#include "helpers.h"
+#include "nma-ui-utils.h"
+#include "utils.h"
+
+struct _NMAEapLEAP {
+       NMAEap parent;
+
+       NMAWs *ws_parent;
+
+       gboolean editing_connection;
+
+       const char *password_flags_name;
+       GtkEntry *username_entry;
+       GtkEntry *password_entry;
+       GtkToggleButton *show_password;
+};
+
+static void
+show_toggled_cb (GtkToggleButton *button, NMAEapLEAP *method)
+{
+       gboolean visible;
+
+       visible = gtk_toggle_button_get_active (button);
+       gtk_entry_set_visibility (method->password_entry, visible);
+}
+
+static gboolean
+validate (NMAEap *parent, GError **error)
+{
+       NMAEapLEAP *method = (NMAEapLEAP *)parent;
+       const char *text;
+       gboolean ret = TRUE;
+
+       text = gtk_editable_get_text (GTK_EDITABLE (method->username_entry));
+       if (!text || !strlen (text)) {
+               widget_set_error (GTK_WIDGET (method->username_entry));
+               g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("missing EAP-LEAP username"));
+               ret = FALSE;
+       } else
+               widget_unset_error (GTK_WIDGET (method->username_entry));
+
+       text = gtk_editable_get_text (GTK_EDITABLE (method->password_entry));
+       if (!text || !strlen (text)) {
+               widget_set_error (GTK_WIDGET (method->password_entry));
+               if (ret) {
+                       g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("missing EAP-LEAP 
password"));
+                       ret = FALSE;
+               }
+       } else
+               widget_unset_error (GTK_WIDGET (method->password_entry));
+
+       return ret;
+}
+
+static void
+add_to_size_group (NMAEap *parent, GtkSizeGroup *group)
+{
+       GtkWidget *widget;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_leap_username_label"));
+       g_assert (widget);
+       gtk_size_group_add_widget (group, widget);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_leap_password_label"));
+       g_assert (widget);
+       gtk_size_group_add_widget (group, widget);
+}
+
+static void
+fill_connection (NMAEap *parent, NMConnection *connection)
+{
+       NMAEapLEAP *method = (NMAEapLEAP *) parent;
+       NMSetting8021x *s_8021x;
+       NMSettingSecretFlags secret_flags;
+       GtkWidget *passwd_entry;
+
+       s_8021x = nm_connection_get_setting_802_1x (connection);
+       g_assert (s_8021x);
+
+       nm_setting_802_1x_add_eap_method (s_8021x, "leap");
+
+       g_object_set (s_8021x,
+                     NM_SETTING_802_1X_IDENTITY, gtk_editable_get_text (GTK_EDITABLE 
(method->username_entry)),
+                     NM_SETTING_802_1X_PASSWORD, gtk_editable_get_text (GTK_EDITABLE 
(method->password_entry)),
+                     NULL);
+
+       passwd_entry = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_leap_password_entry"));
+       g_assert (passwd_entry);
+
+       /* Save 802.1X password flags to the connection */
+       secret_flags = nma_utils_menu_to_secret_flags (passwd_entry);
+       nm_setting_set_secret_flags (NM_SETTING (s_8021x), method->password_flags_name,
+                                    secret_flags, NULL);
+
+       /* Update secret flags and popup when editing the connection */
+       if (method->editing_connection)
+               nma_utils_update_password_storage (passwd_entry, secret_flags,
+                                                  NM_SETTING (s_8021x), method->password_flags_name);
+}
+
+static void
+update_secrets (NMAEap *parent, NMConnection *connection)
+{
+       helper_fill_secret_entry (connection,
+                                 parent->builder,
+                                 "eap_leap_password_entry",
+                                 NM_TYPE_SETTING_802_1X,
+                                 (HelperSecretFunc) nm_setting_802_1x_get_password);
+}
+
+/* Set the UI fields for user, password and show_password to the
+ * values as provided by method->ws_parent. */
+static void
+set_userpass_ui (NMAEapLEAP *method)
+{
+       if (method->ws_parent->username) {
+               gtk_editable_set_text (GTK_EDITABLE (method->username_entry),
+                                      method->ws_parent->username);
+       } else {
+               gtk_editable_set_text (GTK_EDITABLE (method->username_entry), "");
+       }
+
+       if (method->ws_parent->password && !method->ws_parent->always_ask) {
+               gtk_editable_set_text (GTK_EDITABLE (method->password_entry),
+                                      method->ws_parent->password);
+       } else {
+               gtk_editable_set_text (GTK_EDITABLE (method->password_entry), "");
+       }
+
+       gtk_toggle_button_set_active (method->show_password, method->ws_parent->show_password);
+}
+
+static void
+widgets_realized (GtkWidget *widget, NMAEapLEAP *method)
+{
+       set_userpass_ui (method);
+}
+
+static void
+widgets_unrealized (GtkWidget *widget, NMAEapLEAP *method)
+{
+       nma_ws_set_userpass (method->ws_parent,
+                            gtk_editable_get_text (GTK_EDITABLE (method->username_entry)),
+                            gtk_editable_get_text (GTK_EDITABLE (method->password_entry)),
+                            (gboolean) -1,
+                            gtk_toggle_button_get_active (method->show_password));
+}
+
+static void
+destroy (NMAEap *parent)
+{
+       NMAEapLEAP *method = (NMAEapLEAP *) parent;
+       GtkWidget *widget;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_leap_notebook"));
+       g_assert (widget);
+       g_signal_handlers_disconnect_by_data (widget, method);
+
+       g_signal_handlers_disconnect_by_data (method->username_entry, method->ws_parent);
+       g_signal_handlers_disconnect_by_data (method->password_entry, method->ws_parent);
+       g_signal_handlers_disconnect_by_data (method->show_password, method);
+}
+
+NMAEapLEAP *
+nma_eap_leap_new (NMAWs *ws_parent,
+                     NMConnection *connection,
+                     gboolean secrets_only)
+{
+       NMAEapLEAP *method;
+       NMAEap *parent;
+       GtkWidget *widget;
+       NMSetting8021x *s_8021x = NULL;
+
+       parent = nma_eap_init (sizeof (NMAEapLEAP),
+                              validate,
+                              add_to_size_group,
+                              fill_connection,
+                              update_secrets,
+                              destroy,
+                              "/org/gnome/libnma/nma-eap-leap.ui",
+                              "eap_leap_notebook",
+                              "eap_leap_username_entry",
+                              FALSE);
+       if (!parent)
+               return NULL;
+
+       method = (NMAEapLEAP *) parent;
+       method->password_flags_name = NM_SETTING_802_1X_PASSWORD;
+       method->editing_connection = secrets_only ? FALSE : TRUE;
+       method->ws_parent = ws_parent;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_leap_notebook"));
+       g_assert (widget);
+       g_signal_connect (G_OBJECT (widget), "realize",
+                         (GCallback) widgets_realized,
+                         method);
+       g_signal_connect (G_OBJECT (widget), "unrealize",
+                         (GCallback) widgets_unrealized,
+                         method);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_leap_username_entry"));
+       g_assert (widget);
+       method->username_entry = GTK_ENTRY (widget);
+       g_signal_connect (G_OBJECT (widget), "changed",
+                         (GCallback) nma_ws_changed_cb,
+                         ws_parent);
+
+       if (secrets_only)
+               gtk_widget_set_sensitive (widget, FALSE);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_leap_password_entry"));
+       g_assert (widget);
+       method->password_entry = GTK_ENTRY (widget);
+       g_signal_connect (G_OBJECT (widget), "changed",
+                         (GCallback) nma_ws_changed_cb,
+                         ws_parent);
+
+       /* Create password-storage popup menu for password entry under entry's secondary icon */
+       if (connection)
+               s_8021x = nm_connection_get_setting_802_1x (connection);
+       nma_utils_setup_password_storage (widget, 0, (NMSetting *) s_8021x, method->password_flags_name,
+                                         FALSE, secrets_only);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "show_checkbutton_eapleap"));
+       g_assert (widget);
+       method->show_password = GTK_TOGGLE_BUTTON (widget);
+       g_signal_connect (G_OBJECT (widget), "toggled",
+                         (GCallback) show_toggled_cb,
+                         parent);
+
+       /* Initialize the UI fields with the security settings from method->ws_parent.
+        * This will be done again when the widget gets realized. It must be done here as well,
+        * because the outer dialog will ask to 'validate' the connection before the security tab
+        * is shown/realized (to enable the 'Apply' button).
+        * As 'validate' accesses the contents of the UI fields, they must be initialized now, even
+        * if the widgets are not yet visible. */
+       set_userpass_ui (method);
+
+       return method;
+}
diff --git a/src/nma-ws/nma-eap-leap.h b/src/nma-ws/nma-eap-leap.h
new file mode 100644
index 00000000..738cf20a
--- /dev/null
+++ b/src/nma-ws/nma-eap-leap.h
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#ifndef NMA_EAP_LEAP_H
+#define NMA_EAP_LEAP_H
+
+#include "nma-ws.h"
+
+typedef struct _NMAEapLEAP NMAEapLEAP;
+
+NMAEapLEAP *nma_eap_leap_new (NMAWs *ws_parent,
+                              NMConnection *connection,
+                              gboolean secrets_only);
+
+#endif /* NMA_EAP_LEAP_H */
diff --git a/src/nma-ws/nma-eap-leap.ui b/src/nma-ws/nma-eap-leap.ui
new file mode 100644
index 00000000..8b33b820
--- /dev/null
+++ b/src/nma-ws/nma-eap-leap.ui
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface domain="nm-applet">
+  <requires lib="gtk+" version="3.10"/>
+  <object class="GtkNotebook" id="eap_leap_notebook">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="show_tabs">False</property>
+    <property name="show_border">False</property>
+    <child>
+      <object class="GtkGrid" id="table9">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="valign">start</property>
+        <property name="row_spacing">6</property>
+        <property name="column_spacing">6</property>
+        <child>
+          <object class="GtkLabel" id="eap_leap_username_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">_Username</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">eap_leap_username_entry</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="eap_leap_password_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">_Password</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">eap_leap_password_entry</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="eap_leap_password_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+            <property name="visibility">False</property>
+            <property name="activates_default">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="show_checkbutton_eapleap">
+            <property name="label" translatable="yes">Sho_w password</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="hexpand">True</property>
+            <property name="use_underline">True</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="eap_leap_username_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+      </object>
+    </child>
+    <child type="tab">
+      <object class="GtkLabel" id="label43">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+      </object>
+      <packing>
+        <property name="tab_fill">False</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/src/nma-ws/nma-eap-peap.c b/src/nma-ws/nma-eap-peap.c
new file mode 100644
index 00000000..f89187c0
--- /dev/null
+++ b/src/nma-ws/nma-eap-peap.c
@@ -0,0 +1,498 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+#include "nma-private.h"
+
+#include <ctype.h>
+#include <string.h>
+
+#include "nma-eap.h"
+#include "nma-ws.h"
+#include "nma-cert-chooser.h"
+#include "utils.h"
+
+#define I_NAME_COLUMN   0
+#define I_METHOD_COLUMN 1
+
+struct _NMAEapPEAP {
+       NMAEap parent;
+
+       const char *password_flags_name;
+       GtkSizeGroup *size_group;
+       NMAWs *sec_parent;
+       gboolean is_editor;
+       GtkWidget *ca_cert_chooser;
+};
+
+static void
+destroy (NMAEap *parent)
+{
+       NMAEapPEAP *method = (NMAEapPEAP *) parent;
+
+       if (method->size_group)
+               g_object_unref (method->size_group);
+}
+
+static gboolean
+validate (NMAEap *parent, GError **error)
+{
+       NMAEapPEAP *method = (NMAEapPEAP *) parent;
+       GtkWidget *widget;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       NMAEap *eap = NULL;
+       gboolean valid = FALSE;
+
+       if (   gtk_widget_get_sensitive (method->ca_cert_chooser)
+           && !nma_cert_chooser_validate (NMA_CERT_CHOOSER (method->ca_cert_chooser), error))
+               return FALSE;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_inner_auth_combo"));
+       g_assert (widget);
+
+       model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
+       gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter);
+       gtk_tree_model_get (model, &iter, I_METHOD_COLUMN, &eap, -1);
+       g_assert (eap);
+       valid = nma_eap_validate (eap, error);
+       nma_eap_unref (eap);
+       return valid;
+}
+
+static void
+ca_cert_not_required_toggled (GtkWidget *button, gpointer user_data)
+{
+       NMAEapPEAP *method = (NMAEapPEAP *) user_data;
+
+       gtk_widget_set_sensitive (method->ca_cert_chooser,
+                                 !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)));
+}
+
+static void
+add_to_size_group (NMAEap *parent, GtkSizeGroup *group)
+{
+       NMAEapPEAP *method = (NMAEapPEAP *) parent;
+       GtkWidget *widget;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       NMAEap *eap;
+
+       if (method->size_group)
+               g_object_unref (method->size_group);
+       method->size_group = g_object_ref (group);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_anon_identity_label"));
+       g_assert (widget);
+       gtk_size_group_add_widget (group, widget);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_domain_label"));
+       g_assert (widget);
+       gtk_size_group_add_widget (group, widget);
+
+       nma_cert_chooser_add_to_size_group (NMA_CERT_CHOOSER (method->ca_cert_chooser), group);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_version_label"));
+       g_assert (widget);
+       gtk_size_group_add_widget (group, widget);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_inner_auth_label"));
+       g_assert (widget);
+       gtk_size_group_add_widget (group, widget);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_inner_auth_combo"));
+       g_assert (widget);
+
+       model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
+       gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter);
+       gtk_tree_model_get (model, &iter, I_METHOD_COLUMN, &eap, -1);
+       g_assert (eap);
+       nma_eap_add_to_size_group (eap, group);
+       nma_eap_unref (eap);
+}
+
+static void
+fill_connection (NMAEap *parent, NMConnection *connection)
+{
+       NMAEapPEAP *method = (NMAEapPEAP *) parent;
+       NMSetting8021x *s_8021x;
+       NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+       GtkWidget *widget;
+       const char *text;
+       char *value = NULL;
+       NMAEap *eap = NULL;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       int peapver_active = 0;
+       GError *error = NULL;
+       gboolean ca_cert_error = FALSE;
+       NMSetting8021xCKScheme scheme = NM_SETTING_802_1X_CK_SCHEME_UNKNOWN;
+#if LIBNM_BUILD
+       NMSettingSecretFlags secret_flags;
+#endif
+
+       s_8021x = nm_connection_get_setting_802_1x (connection);
+       g_assert (s_8021x);
+
+       nm_setting_802_1x_add_eap_method (s_8021x, "peap");
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_anon_identity_entry"));
+       g_assert (widget);
+       text = gtk_editable_get_text (GTK_EDITABLE (widget));
+       if (text && strlen (text))
+               g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, text, NULL);
+
+#if LIBNM_BUILD
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_domain_entry"));
+       g_assert (widget);
+       text = gtk_editable_get_text (GTK_EDITABLE (widget));
+       if (text && strlen (text))
+               g_object_set (s_8021x, NM_SETTING_802_1X_DOMAIN_SUFFIX_MATCH, text, NULL);
+#endif
+
+#if LIBNM_BUILD
+/* libnm-glib doesn't support this. */
+       /* Save CA certificate PIN and its flags to the connection */
+       secret_flags = nma_cert_chooser_get_cert_password_flags (NMA_CERT_CHOOSER (method->ca_cert_chooser));
+       nm_setting_set_secret_flags (NM_SETTING (s_8021x), NM_SETTING_802_1X_CA_CERT_PASSWORD,
+                                    secret_flags, NULL);
+       if (method->is_editor) {
+               /* Update secret flags and popup when editing the connection */
+               nma_cert_chooser_update_cert_password_storage (NMA_CERT_CHOOSER (method->ca_cert_chooser),
+                                                              secret_flags, NM_SETTING (s_8021x),
+                                                              NM_SETTING_802_1X_CA_CERT_PASSWORD);
+               g_object_set (s_8021x, NM_SETTING_802_1X_CA_CERT_PASSWORD,
+                             nma_cert_chooser_get_cert_password (NMA_CERT_CHOOSER (method->ca_cert_chooser)),
+                             NULL);
+       }
+#endif
+
+       /* TLS CA certificate */
+       if (gtk_widget_get_sensitive (method->ca_cert_chooser))
+               value = nma_cert_chooser_get_cert (NMA_CERT_CHOOSER (method->ca_cert_chooser), &scheme);
+       format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+       if (!nm_setting_802_1x_set_ca_cert (s_8021x, value, scheme, &format, &error)) {
+               g_warning ("Couldn't read CA certificate '%s': %s", value, error ? error->message : 
"(unknown)");
+               g_clear_error (&error);
+               ca_cert_error = TRUE;
+       }
+       nma_eap_ca_cert_ignore_set (parent, connection, value, ca_cert_error);
+       g_free (value);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_version_combo"));
+       peapver_active = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
+       switch (peapver_active) {
+       case 1:  /* PEAP v0 */
+               g_object_set (G_OBJECT (s_8021x), NM_SETTING_802_1X_PHASE1_PEAPVER, "0", NULL);
+               break;
+       case 2:  /* PEAP v1 */
+               g_object_set (G_OBJECT (s_8021x), NM_SETTING_802_1X_PHASE1_PEAPVER, "1", NULL);
+               break;
+       default: /* Automatic */
+               g_object_set (G_OBJECT (s_8021x), NM_SETTING_802_1X_PHASE1_PEAPVER, NULL, NULL);
+               break;
+       }
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_inner_auth_combo"));
+       model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
+       gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter);
+       gtk_tree_model_get (model, &iter, I_METHOD_COLUMN, &eap, -1);
+       g_assert (eap);
+
+       nma_eap_fill_connection (eap, connection);
+       nma_eap_unref (eap);
+}
+static void
+inner_auth_combo_changed_cb (GtkWidget *combo, gpointer user_data)
+{
+       NMAEap *parent = (NMAEap *) user_data;
+       NMAEapPEAP *method = (NMAEapPEAP *) parent;
+       GtkWidget *vbox;
+       NMAEap *eap = NULL;
+       GList *elt, *children;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       GtkWidget *eap_widget;
+
+       vbox = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_inner_auth_vbox"));
+       g_assert (vbox);
+
+       /* Remove any previous wireless security widgets */
+       children = gtk_container_get_children (GTK_CONTAINER (vbox));
+       for (elt = children; elt; elt = g_list_next (elt))
+               gtk_container_remove (GTK_CONTAINER (vbox), GTK_WIDGET (elt->data));
+
+       model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
+       gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter);
+       gtk_tree_model_get (model, &iter, I_METHOD_COLUMN, &eap, -1);
+       g_assert (eap);
+
+       eap_widget = nma_eap_get_widget (eap);
+       g_assert (eap_widget);
+       gtk_widget_unparent (eap_widget);
+
+       if (method->size_group)
+               nma_eap_add_to_size_group (eap, method->size_group);
+       gtk_container_add (GTK_CONTAINER (vbox), eap_widget);
+
+       nma_eap_unref (eap);
+
+       nma_ws_changed_cb (combo, method->sec_parent);
+}
+
+static GtkWidget *
+inner_auth_combo_init (NMAEapPEAP *method,
+                       NMConnection *connection,
+                       NMSetting8021x *s_8021x,
+                       gboolean secrets_only)
+{
+       NMAEap *parent = (NMAEap *) method;
+       GtkWidget *combo;
+       GtkListStore *auth_model;
+       GtkTreeIter iter;
+       NMAEapSimple *em_mschap_v2;
+       NMAEapSimple *em_md5;
+       NMAEapSimple *em_gtc;
+       guint32 active = 0;
+       const char *phase2_auth = NULL;
+       NMAEapSimpleFlags simple_flags;
+
+       auth_model = gtk_list_store_new (2, G_TYPE_STRING, nma_eap_get_type ());
+
+       if (s_8021x) {
+               if (nm_setting_802_1x_get_phase2_auth (s_8021x))
+                       phase2_auth = nm_setting_802_1x_get_phase2_auth (s_8021x);
+               else if (nm_setting_802_1x_get_phase2_autheap (s_8021x))
+                       phase2_auth = nm_setting_802_1x_get_phase2_autheap (s_8021x);
+       }
+
+       simple_flags = NMA_EAP_SIMPLE_FLAG_PHASE2;
+       if (method->is_editor)
+               simple_flags |= NMA_EAP_SIMPLE_FLAG_IS_EDITOR;
+       if (secrets_only)
+               simple_flags |= NMA_EAP_SIMPLE_FLAG_SECRETS_ONLY;
+
+       em_mschap_v2 = nma_eap_simple_new (method->sec_parent,
+                                          connection,
+                                          NMA_EAP_SIMPLE_TYPE_MSCHAP_V2,
+                                          simple_flags,
+                                          NULL);
+       gtk_list_store_append (auth_model, &iter);
+       gtk_list_store_set (auth_model, &iter,
+                           I_NAME_COLUMN, _("MSCHAPv2"),
+                           I_METHOD_COLUMN, em_mschap_v2,
+                           -1);
+       nma_eap_unref (NMA_EAP (em_mschap_v2));
+
+       /* Check for defaulting to MSCHAPv2 */
+       if (phase2_auth && !strcasecmp (phase2_auth, "mschapv2"))
+               active = 0;
+
+       em_md5 = nma_eap_simple_new (method->sec_parent,
+                                    connection,
+                                    NMA_EAP_SIMPLE_TYPE_MD5,
+                                    simple_flags,
+                                    NULL);
+       gtk_list_store_append (auth_model, &iter);
+       gtk_list_store_set (auth_model, &iter,
+                           I_NAME_COLUMN, _("MD5"),
+                           I_METHOD_COLUMN, em_md5,
+                           -1);
+       nma_eap_unref (NMA_EAP (em_md5));
+
+       /* Check for defaulting to MD5 */
+       if (phase2_auth && !strcasecmp (phase2_auth, "md5"))
+               active = 1;
+
+       em_gtc = nma_eap_simple_new (method->sec_parent,
+                                    connection,
+                                    NMA_EAP_SIMPLE_TYPE_GTC,
+                                    simple_flags,
+                                    NULL);
+       gtk_list_store_append (auth_model, &iter);
+       gtk_list_store_set (auth_model, &iter,
+                           I_NAME_COLUMN, _("GTC"),
+                           I_METHOD_COLUMN, em_gtc,
+                           -1);
+       nma_eap_unref (NMA_EAP (em_gtc));
+
+       /* Check for defaulting to GTC */
+       if (phase2_auth && !strcasecmp (phase2_auth, "gtc"))
+               active = 2;
+
+       combo = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_inner_auth_combo"));
+       g_assert (combo);
+
+       gtk_combo_box_set_model (GTK_COMBO_BOX (combo), GTK_TREE_MODEL (auth_model));
+       g_object_unref (G_OBJECT (auth_model));
+       gtk_combo_box_set_active (GTK_COMBO_BOX (combo), active);
+
+       g_signal_connect (G_OBJECT (combo), "changed",
+                         (GCallback) inner_auth_combo_changed_cb,
+                         method);
+       return combo;
+}
+
+static void
+update_secrets (NMAEap *parent, NMConnection *connection)
+{
+       nma_eap_phase2_update_secrets_helper (parent,
+                                             connection,
+                                             "eap_peap_inner_auth_combo",
+                                             I_METHOD_COLUMN);
+}
+
+NMAEapPEAP *
+nma_eap_peap_new (NMAWs *ws_parent,
+                  NMConnection *connection,
+                  gboolean is_editor,
+                  gboolean secrets_only)
+{
+       NMAEap *parent;
+       NMAEapPEAP *method;
+       GtkWidget *widget;
+       NMSetting8021x *s_8021x = NULL;
+       gboolean ca_not_required = FALSE;
+
+       parent = nma_eap_init (sizeof (NMAEapPEAP),
+                              validate,
+                              add_to_size_group,
+                              fill_connection,
+                              update_secrets,
+                              destroy,
+                              "/org/gnome/libnma/nma-eap-peap.ui",
+                              "eap_peap_notebook",
+                              "eap_peap_anon_identity_entry",
+                              FALSE);
+       if (!parent)
+               return NULL;
+
+       method = (NMAEapPEAP *) parent;
+       method->password_flags_name = NM_SETTING_802_1X_PASSWORD;
+       method->sec_parent = ws_parent;
+       method->is_editor = is_editor;
+
+       if (connection)
+               s_8021x = nm_connection_get_setting_802_1x (connection);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_grid"));
+       g_assert (widget);
+
+       method->ca_cert_chooser = nma_cert_chooser_new ("CA",
+                                                         NMA_CERT_CHOOSER_FLAG_CERT
+                                                       | (secrets_only ? NMA_CERT_CHOOSER_FLAG_PASSWORDS : 
0));
+       gtk_grid_attach (GTK_GRID (widget), method->ca_cert_chooser, 0, 2, 2, 1);
+       gtk_widget_show (method->ca_cert_chooser);
+
+       g_signal_connect (method->ca_cert_chooser,
+                         "cert-validate",
+                         G_CALLBACK (nma_eap_ca_cert_validate_cb),
+                         NULL);
+       g_signal_connect (method->ca_cert_chooser,
+                         "changed",
+                         G_CALLBACK (nma_ws_changed_cb),
+                         ws_parent);
+
+       nma_eap_setup_cert_chooser (NMA_CERT_CHOOSER (method->ca_cert_chooser), s_8021x,
+                                   nm_setting_802_1x_get_ca_cert_scheme,
+                                   nm_setting_802_1x_get_ca_cert_path,
+                                   nm_setting_802_1x_get_ca_cert_uri,
+                                   nm_setting_802_1x_get_ca_cert_password,
+                                   NULL,
+                                   NULL,
+                                   NULL,
+                                   NULL);
+
+       if (connection && nma_eap_ca_cert_ignore_get (parent, connection)) {
+               gchar *ca_cert;
+               NMSetting8021xCKScheme scheme;
+
+               ca_cert = nma_cert_chooser_get_cert (NMA_CERT_CHOOSER (method->ca_cert_chooser), &scheme);
+               if (ca_cert)
+                       g_free (ca_cert);
+               else
+                       ca_not_required = TRUE;
+       }
+
+       if (secrets_only)
+               ca_not_required = TRUE;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, 
"eap_peap_ca_cert_not_required_checkbox"));
+       g_assert (widget);
+       g_signal_connect (G_OBJECT (widget), "toggled",
+                         (GCallback) ca_cert_not_required_toggled,
+                         parent);
+       g_signal_connect (G_OBJECT (widget), "toggled",
+                         (GCallback) nma_ws_changed_cb,
+                         ws_parent);
+       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), ca_not_required);
+
+       widget = inner_auth_combo_init (method, connection, s_8021x, secrets_only);
+       inner_auth_combo_changed_cb (widget, (gpointer) method);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_version_combo"));
+       g_assert (widget);
+       gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
+       if (s_8021x) {
+               const char *peapver;
+
+               peapver = nm_setting_802_1x_get_phase1_peapver (s_8021x);
+               if (peapver) {
+                       /* Index 0 is "Automatic" */
+                       if (!strcmp (peapver, "0"))
+                               gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 1);
+                       else if (!strcmp (peapver, "1"))
+                               gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 2);
+               }
+       }
+       g_signal_connect (G_OBJECT (widget), "changed",
+                         (GCallback) nma_ws_changed_cb,
+                         ws_parent);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_anon_identity_entry"));
+       if (s_8021x && nm_setting_802_1x_get_anonymous_identity (s_8021x))
+               gtk_editable_set_text (GTK_EDITABLE (widget), nm_setting_802_1x_get_anonymous_identity 
(s_8021x));
+       g_signal_connect (G_OBJECT (widget), "changed",
+                         (GCallback) nma_ws_changed_cb,
+                         ws_parent);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_domain_entry"));
+#if LIBNM_BUILD
+       if (s_8021x && nm_setting_802_1x_get_domain_suffix_match (s_8021x))
+               gtk_editable_set_text (GTK_EDITABLE (widget), nm_setting_802_1x_get_domain_suffix_match 
(s_8021x));
+       g_signal_connect (G_OBJECT (widget), "changed",
+                         (GCallback) nma_ws_changed_cb,
+                         ws_parent);
+#else
+       gtk_widget_hide (widget);
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_domain_label"));
+       gtk_widget_hide (widget);
+#endif
+
+       if (secrets_only) {
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, 
"eap_peap_anon_identity_label"));
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, 
"eap_peap_anon_identity_entry"));
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_domain_label"));
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_domain_entry"));
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, 
"eap_peap_ca_cert_not_required_checkbox"));
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_inner_auth_label"));
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_inner_auth_combo"));
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_version_label"));
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_version_combo"));
+               gtk_widget_hide (widget);
+       }
+
+       return method;
+}
diff --git a/src/nma-ws/nma-eap-peap.h b/src/nma-ws/nma-eap-peap.h
new file mode 100644
index 00000000..8f4d88bd
--- /dev/null
+++ b/src/nma-ws/nma-eap-peap.h
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#ifndef NMA_EAP_PEAP_H
+#define NMA_EAP_PEAP_H
+
+#include "nma-ws.h"
+
+typedef struct _NMAEapPEAP NMAEapPEAP;
+
+NMAEapPEAP *nma_eap_peap_new (NMAWs *ws_parent,
+                              NMConnection *connection,
+                              gboolean is_editor,
+                              gboolean secrets_only);
+
+#endif /* NMA_EAP_PEAP_H */
diff --git a/src/nma-ws/nma-eap-peap.ui b/src/nma-ws/nma-eap-peap.ui
new file mode 100644
index 00000000..cdbdac8a
--- /dev/null
+++ b/src/nma-ws/nma-eap-peap.ui
@@ -0,0 +1,215 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface domain="nm-applet">
+  <requires lib="gtk+" version="3.10"/>
+  <object class="GtkListStore" id="model8">
+    <columns>
+      <!-- column-name gchararray -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0"> </col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkListStore" id="model9">
+    <columns>
+      <!-- column-name gchararray -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">Automatic</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Version 0</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Version 1</col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkNotebook" id="eap_peap_notebook">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="show_tabs">False</property>
+    <property name="show_border">False</property>
+    <child>
+      <object class="GtkGrid" id="eap_peap_grid">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="row_spacing">6</property>
+        <property name="column_spacing">6</property>
+        <child>
+          <object class="GtkLabel" id="eap_peap_anon_identity_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Anony_mous identity</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">eap_peap_anon_identity_entry</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="eap_peap_anon_identity_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+            <property name="activates_default">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="eap_peap_ca_cert_not_required_checkbox">
+            <property name="label" translatable="yes">No CA certificate is _required</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="hexpand">True</property>
+            <property name="use_underline">True</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">3</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="eap_peap_version_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">PEAP _version</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">eap_peap_version_combo</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">4</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkComboBox" id="eap_peap_version_combo">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="hexpand">True</property>
+            <property name="model">model9</property>
+            <child>
+              <object class="GtkCellRendererText" id="renderer9"/>
+              <attributes>
+                <attribute name="text">0</attribute>
+              </attributes>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">4</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="eap_peap_inner_auth_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">_Inner authentication</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">eap_peap_inner_auth_combo</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">5</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkComboBox" id="eap_peap_inner_auth_combo">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="hexpand">True</property>
+            <property name="model">model8</property>
+            <child>
+              <object class="GtkCellRendererText" id="renderer8"/>
+              <attributes>
+                <attribute name="text">0</attribute>
+              </attributes>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">5</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox" id="eap_peap_inner_auth_vbox">
+            <property name="orientation">vertical</property>
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">6</property>
+            <property name="width">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="eap_peap_domain_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="tooltip_text" translatable="yes">Suffix of the server certificate 
name.</property>
+            <property name="label" translatable="yes">_Domain</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">eap_peap_domain_entry</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="eap_peap_domain_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+            <property name="activates_default">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+      </object>
+      <packing>
+        <property name="menu_label">eap_peap_grid</property>
+      </packing>
+    </child>
+    <child type="tab">
+      <object class="GtkLabel" id="label61">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+      </object>
+      <packing>
+        <property name="tab_fill">False</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/src/nma-ws/nma-eap-simple.c b/src/nma-ws/nma-eap-simple.c
new file mode 100644
index 00000000..d5f90c52
--- /dev/null
+++ b/src/nma-ws/nma-eap-simple.c
@@ -0,0 +1,483 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+#include "nma-private.h"
+
+#include <ctype.h>
+#include <string.h>
+
+#include "nma-eap.h"
+#include "nma-ws.h"
+#include "helpers.h"
+#include "nma-ui-utils.h"
+#include "utils.h"
+
+struct _NMAEapSimple {
+       NMAEap parent;
+
+       NMAWs *ws_parent;
+
+       const char *password_flags_name;
+       NMAEapSimpleType type;
+       NMAEapSimpleFlags flags;
+
+       gboolean username_requested;
+       gboolean password_requested;
+       gboolean pkey_passphrase_requested;
+       GtkEntry *username_entry;
+       GtkEntry *password_entry;
+       GtkToggleButton *show_password;
+       GtkEntry *pkey_passphrase_entry;
+       GtkToggleButton *show_pkey_passphrase;
+       guint idle_func_id;
+};
+
+static void
+show_password_toggled_cb (GtkToggleButton *button, NMAEapSimple *method)
+{
+       gboolean visible;
+
+       visible = gtk_toggle_button_get_active (button);
+       gtk_entry_set_visibility (method->password_entry, visible);
+}
+
+static void
+show_pkey_passphrase_toggled_cb (GtkToggleButton *button, NMAEapSimple *method)
+{
+       gboolean visible;
+
+       visible = gtk_toggle_button_get_active (button);
+       gtk_entry_set_visibility (method->pkey_passphrase_entry, visible);
+}
+
+static gboolean
+always_ask_selected (GtkEntry *passwd_entry)
+{
+       return !!(  nma_utils_menu_to_secret_flags (GTK_WIDGET (passwd_entry))
+                 & NM_SETTING_SECRET_FLAG_NOT_SAVED);
+}
+
+static gboolean
+validate (NMAEap *parent, GError **error)
+{
+       NMAEapSimple *method = (NMAEapSimple *)parent;
+       const char *text;
+       gboolean ret = TRUE;
+
+       if (method->username_requested) {
+               text = gtk_editable_get_text (GTK_EDITABLE (method->username_entry));
+               if (!text || !strlen (text)) {
+                       widget_set_error (GTK_WIDGET (method->username_entry));
+                       g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("missing EAP username"));
+                       ret = FALSE;
+               } else
+                       widget_unset_error (GTK_WIDGET (method->username_entry));
+       }
+
+       /* Check if the password should always be requested */
+       if (method->password_requested) {
+               if (always_ask_selected (method->password_entry))
+                       widget_unset_error (GTK_WIDGET (method->password_entry));
+               else {
+                       text = gtk_editable_get_text (GTK_EDITABLE (method->password_entry));
+                       if (!text || !strlen (text)) {
+                               widget_set_error (GTK_WIDGET (method->password_entry));
+                               if (ret) {
+                                       g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC,
+                                                            _("missing EAP password"));
+                                       ret = FALSE;
+                               }
+                       } else
+                               widget_unset_error (GTK_WIDGET (method->password_entry));
+               }
+       }
+
+       if (method->pkey_passphrase_requested) {
+               text = gtk_editable_get_text (GTK_EDITABLE (method->pkey_passphrase_entry));
+               if (!text || !strlen (text)) {
+                       widget_set_error (GTK_WIDGET (method->pkey_passphrase_entry));
+                       if (ret) {
+                               g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC,
+                                                    _("missing EAP client Private Key passphrase"));
+                               ret = FALSE;
+                       }
+               } else
+                       widget_unset_error (GTK_WIDGET (method->pkey_passphrase_entry));
+       }
+
+       return ret;
+}
+
+static void
+add_to_size_group (NMAEap *parent, GtkSizeGroup *group)
+{
+       NMAEapSimple *method = (NMAEapSimple *) parent;
+       GtkWidget *widget;
+
+       if (method->username_requested) {
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_simple_username_label"));
+               g_assert (widget);
+               gtk_size_group_add_widget (group, widget);
+       }
+
+       if (method->password_requested) {
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_simple_password_label"));
+               g_assert (widget);
+               gtk_size_group_add_widget (group, widget);
+       }
+
+       if (method->pkey_passphrase_requested) {
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, 
"eap_simple_pkey_passphrase_label"));
+               g_assert (widget);
+               gtk_size_group_add_widget (group, widget);
+       }
+}
+
+typedef struct {
+       const char *name;
+       gboolean autheap_allowed;
+} EapType;
+
+/* Indexed by NMA_EAP_SIMPLE_TYPE_* */
+static const EapType eap_table[NMA_EAP_SIMPLE_TYPE_LAST] = {
+       [NMA_EAP_SIMPLE_TYPE_PAP]             = { "pap",      FALSE },
+       [NMA_EAP_SIMPLE_TYPE_MSCHAP]          = { "mschap",   FALSE },
+       [NMA_EAP_SIMPLE_TYPE_MSCHAP_V2]       = { "mschapv2", TRUE  },
+       [NMA_EAP_SIMPLE_TYPE_PLAIN_MSCHAP_V2] = { "mschapv2", FALSE },
+       [NMA_EAP_SIMPLE_TYPE_MD5]             = { "md5",      TRUE  },
+       [NMA_EAP_SIMPLE_TYPE_PWD]             = { "pwd",      TRUE  },
+       [NMA_EAP_SIMPLE_TYPE_CHAP]            = { "chap",     FALSE },
+       [NMA_EAP_SIMPLE_TYPE_GTC]             = { "gtc",      TRUE  },
+       [NMA_EAP_SIMPLE_TYPE_UNKNOWN]         = { "unknown",  TRUE  },
+};
+
+static void
+fill_connection (NMAEap *parent, NMConnection *connection)
+{
+       NMAEapSimple *method = (NMAEapSimple *) parent;
+       NMSetting8021x *s_8021x;
+       gboolean not_saved = FALSE;
+       NMSettingSecretFlags flags;
+       const EapType *eap_type;
+
+       s_8021x = nm_connection_get_setting_802_1x (connection);
+       g_assert (s_8021x);
+
+       if (!(method->flags & NMA_EAP_SIMPLE_FLAG_SECRETS_ONLY)) {
+               /* If this is the main EAP method, clear any existing methods because the
+                * user-selected one will replace it.
+                */
+               if (parent->phase2 == FALSE)
+                       nm_setting_802_1x_clear_eap_methods (s_8021x);
+
+               eap_type = &eap_table[method->type];
+               if (parent->phase2) {
+                       /* If the outer EAP method (TLS, TTLS, PEAP, etc) allows inner/phase2
+                        * EAP methods (which only TTLS allows) *and* the inner/phase2 method
+                        * supports being an inner EAP method, then set PHASE2_AUTHEAP.
+                        * Otherwise the inner/phase2 method goes into PHASE2_AUTH.
+                        */
+                       if ((method->flags & NMA_EAP_SIMPLE_FLAG_AUTHEAP_ALLOWED) && 
eap_type->autheap_allowed) {
+                               g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, eap_type->name, 
NULL);
+                               g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, NULL, NULL);
+                       } else {
+                               g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, eap_type->name, NULL);
+                               g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, NULL, NULL);
+                       }
+               } else
+                       nm_setting_802_1x_add_eap_method (s_8021x, eap_type->name);
+       }
+
+       if (method->username_requested) {
+               g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY,
+                             gtk_editable_get_text (GTK_EDITABLE (method->username_entry)),
+                             NULL);
+       }
+
+       if (method->password_requested) {
+               /* Save the password always ask setting */
+               not_saved = always_ask_selected (method->password_entry);
+               flags = nma_utils_menu_to_secret_flags (GTK_WIDGET (method->password_entry));
+               nm_setting_set_secret_flags (NM_SETTING (s_8021x), method->password_flags_name, flags, NULL);
+
+               /* Fill the connection's password if we're in the applet so that it'll get
+                * back to NM.  From the editor though, since the connection isn't going
+                * back to NM in response to a GetSecrets() call, we don't save it if the
+                * user checked "Always Ask".
+                */
+               if (!(method->flags & NMA_EAP_SIMPLE_FLAG_IS_EDITOR) || not_saved == FALSE) {
+                       g_object_set (s_8021x, NM_SETTING_802_1X_PASSWORD,
+                                     gtk_editable_get_text (GTK_EDITABLE (method->password_entry)),
+                                     NULL);
+               }
+
+               /* Update secret flags and popup when editing the connection */
+               if (!(method->flags & NMA_EAP_SIMPLE_FLAG_SECRETS_ONLY)) {
+                       GtkWidget *passwd_entry = GTK_WIDGET (gtk_builder_get_object (parent->builder,
+                                                                                     
"eap_simple_password_entry"));
+                       g_assert (passwd_entry);
+
+                       nma_utils_update_password_storage (passwd_entry, flags,
+                                                          NM_SETTING (s_8021x), method->password_flags_name);
+               }
+       }
+
+       if (method->pkey_passphrase_requested) {
+               g_object_set (s_8021x, NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD,
+                             gtk_editable_get_text (GTK_EDITABLE (method->pkey_passphrase_entry)),
+                             NULL);
+       }
+}
+
+static void
+update_secrets (NMAEap *parent, NMConnection *connection)
+{
+       helper_fill_secret_entry (connection,
+                                 parent->builder,
+                                 "eap_simple_password_entry",
+                                 NM_TYPE_SETTING_802_1X,
+                                 (HelperSecretFunc) nm_setting_802_1x_get_password);
+       helper_fill_secret_entry (connection,
+                                 parent->builder,
+                                 "eap_simple_pkey_passphrase_entry",
+                                 NM_TYPE_SETTING_802_1X,
+                                 (HelperSecretFunc) nm_setting_802_1x_get_private_key_password);
+}
+
+static gboolean
+stuff_changed (NMAEapSimple *method)
+{
+       nma_ws_changed_cb (NULL, method->ws_parent);
+       method->idle_func_id = 0;
+       return FALSE;
+}
+
+static void
+password_storage_changed (GObject *entry,
+                          GParamSpec *pspec,
+                          NMAEapSimple *method)
+{
+       gboolean always_ask;
+       gboolean secrets_only = method->flags & NMA_EAP_SIMPLE_FLAG_SECRETS_ONLY;
+
+       always_ask = always_ask_selected (method->password_entry);
+
+       if (always_ask && !secrets_only) {
+               /* we always clear this button and do not restore it
+                * (because we want to hide the password). */
+               gtk_toggle_button_set_active (method->show_password, FALSE);
+       }
+
+       gtk_widget_set_sensitive (GTK_WIDGET (method->show_password),
+                                 !always_ask || secrets_only);
+
+       if (!method->idle_func_id)
+               method->idle_func_id = g_idle_add ((GSourceFunc) stuff_changed, method);
+}
+
+/* Set the UI fields for user, password, always_ask and show_password to the
+ * values as provided by method->ws_parent. */
+static void
+set_userpass_ui (NMAEapSimple *method)
+{
+       if (method->ws_parent->username) {
+               gtk_editable_set_text (GTK_EDITABLE (method->username_entry),
+                                      method->ws_parent->username);
+       } else {
+               gtk_editable_set_text (GTK_EDITABLE (method->username_entry), "");
+       }
+
+       if (method->ws_parent->password && !method->ws_parent->always_ask) {
+               gtk_editable_set_text (GTK_EDITABLE (method->password_entry),
+                                                    method->ws_parent->password);
+       } else {
+               gtk_editable_set_text (GTK_EDITABLE (method->password_entry), "");
+       }
+
+       gtk_toggle_button_set_active (method->show_password, method->ws_parent->show_password);
+       password_storage_changed (NULL, NULL, method);
+}
+
+static void
+widgets_realized (GtkWidget *widget, NMAEapSimple *method)
+{
+       set_userpass_ui (method);
+}
+
+static void
+widgets_unrealized (GtkWidget *widget, NMAEapSimple *method)
+{
+       nma_ws_set_userpass (method->ws_parent,
+                            gtk_editable_get_text (GTK_EDITABLE (method->username_entry)),
+                            gtk_editable_get_text (GTK_EDITABLE (method->password_entry)),
+                            always_ask_selected (method->password_entry),
+                            gtk_toggle_button_get_active (method->show_password));
+}
+
+static void
+destroy (NMAEap *parent)
+{
+       NMAEapSimple *method = (NMAEapSimple *) parent;
+       GtkWidget *widget;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_simple_notebook"));
+       g_assert (widget);
+       g_signal_handlers_disconnect_by_data (widget, method);
+
+       g_signal_handlers_disconnect_by_data (method->username_entry, method->ws_parent);
+       g_signal_handlers_disconnect_by_data (method->password_entry, method->ws_parent);
+       g_signal_handlers_disconnect_by_data (method->password_entry, method);
+       g_signal_handlers_disconnect_by_data (method->show_password, method);
+       g_signal_handlers_disconnect_by_data (method->pkey_passphrase_entry, method->ws_parent);
+       g_signal_handlers_disconnect_by_data (method->show_pkey_passphrase, method);
+
+       nm_clear_g_source (&method->idle_func_id);
+}
+
+static void
+hide_row (GtkWidget **widgets, size_t num)
+{
+       while (num--)
+               gtk_widget_hide (*widgets++);
+}
+
+NMAEapSimple *
+nma_eap_simple_new (NMAWs *ws_parent,
+                    NMConnection *connection,
+                    NMAEapSimpleType type,
+                    NMAEapSimpleFlags flags,
+                    const char *const*hints)
+{
+       NMAEap *parent;
+       NMAEapSimple *method;
+       GtkWidget *widget;
+       NMSetting8021x *s_8021x = NULL;
+       GtkWidget *widget_row[10];
+
+       parent = nma_eap_init (sizeof (NMAEapSimple),
+                              validate,
+                              add_to_size_group,
+                              fill_connection,
+                              update_secrets,
+                              destroy,
+                              "/org/gnome/libnma/nma-eap-simple.ui",
+                              "eap_simple_notebook",
+                              "eap_simple_username_entry",
+                              flags & NMA_EAP_SIMPLE_FLAG_PHASE2);
+       if (!parent)
+               return NULL;
+
+       method = (NMAEapSimple *) parent;
+       method->password_flags_name = NM_SETTING_802_1X_PASSWORD;
+       method->ws_parent = ws_parent;
+       method->flags = flags;
+       method->type = type;
+       g_assert (type < NMA_EAP_SIMPLE_TYPE_LAST);
+       g_assert (   type != NMA_EAP_SIMPLE_TYPE_UNKNOWN
+                 || hints);
+
+       if (hints) {
+               for (; *hints; hints++) {
+                       if (!strcmp (*hints, NM_SETTING_802_1X_IDENTITY))
+                               method->username_requested = TRUE;
+                       else if (!strcmp (*hints, NM_SETTING_802_1X_PASSWORD)) {
+                               method->password_requested = TRUE;
+                               method->password_flags_name = NM_SETTING_802_1X_PASSWORD;
+                       } else if (!strcmp (*hints, NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD))
+                               method->pkey_passphrase_requested = TRUE;
+               }
+       } else {
+               method->username_requested = TRUE;
+               method->password_requested = TRUE;
+       }
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_simple_notebook"));
+       g_assert (widget);
+       g_signal_connect (G_OBJECT (widget), "realize",
+                         (GCallback) widgets_realized,
+                         method);
+       g_signal_connect (G_OBJECT (widget), "unrealize",
+                         (GCallback) widgets_unrealized,
+                         method);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_simple_username_entry"));
+       g_assert (widget);
+       method->username_entry = GTK_ENTRY (widget);
+       g_signal_connect (G_OBJECT (widget), "changed",
+                         (GCallback) nma_ws_changed_cb,
+                         ws_parent);
+
+       if (   (method->flags & NMA_EAP_SIMPLE_FLAG_SECRETS_ONLY)
+           && !method->username_requested)
+               gtk_widget_set_sensitive (widget, FALSE);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_simple_password_entry"));
+       g_assert (widget);
+       method->password_entry = GTK_ENTRY (widget);
+       g_signal_connect (G_OBJECT (widget), "changed",
+                         (GCallback) nma_ws_changed_cb,
+                         ws_parent);
+
+       /* Create password-storage popup menu for password entry under entry's secondary icon */
+       if (connection)
+               s_8021x = nm_connection_get_setting_802_1x (connection);
+       nma_utils_setup_password_storage (widget, 0, (NMSetting *) s_8021x, method->password_flags_name,
+                                         FALSE, flags & NMA_EAP_SIMPLE_FLAG_SECRETS_ONLY);
+
+       g_signal_connect (method->password_entry, "notify::secondary-icon-name",
+                         G_CALLBACK (password_storage_changed),
+                         method);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "show_checkbutton_eapsimple"));
+       g_assert (widget);
+       method->show_password = GTK_TOGGLE_BUTTON (widget);
+       g_signal_connect (G_OBJECT (widget), "toggled",
+                         (GCallback) show_password_toggled_cb,
+                         method);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_simple_pkey_passphrase_entry"));
+       g_assert (widget);
+       method->pkey_passphrase_entry = GTK_ENTRY (widget);
+       g_signal_connect (G_OBJECT (widget), "changed",
+                         (GCallback) nma_ws_changed_cb,
+                         ws_parent);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, 
"eap_simple_show_pkey_passphrase_checkbutton"));
+       g_assert (widget);
+       method->show_pkey_passphrase = GTK_TOGGLE_BUTTON (widget);
+       g_signal_connect (G_OBJECT (widget), "toggled",
+                         (GCallback) show_pkey_passphrase_toggled_cb,
+                         method);
+
+       widget_row[0] = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_simple_username_label"));
+       widget_row[1] = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_simple_username_entry"));
+       if (!method->username_requested)
+               hide_row (widget_row, 2);
+
+       widget_row[0] = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_simple_password_label"));
+       widget_row[1] = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_simple_password_entry"));
+       widget_row[2] = GTK_WIDGET (gtk_builder_get_object (parent->builder, "show_checkbutton_eapsimple"));
+       if (!method->password_requested)
+               hide_row (widget_row, 3);
+
+       widget_row[0] = GTK_WIDGET (gtk_builder_get_object (parent->builder, 
"eap_simple_pkey_passphrase_label"));
+       widget_row[1] = GTK_WIDGET (gtk_builder_get_object (parent->builder, 
"eap_simple_pkey_passphrase_entry"));
+       widget_row[2] = GTK_WIDGET (gtk_builder_get_object (parent->builder, 
"eap_simple_show_pkey_passphrase_checkbutton"));
+       if (!method->pkey_passphrase_requested)
+               hide_row (widget_row, 3);
+
+       /* Initialize the UI fields with the security settings from method->ws_parent.
+        * This will be done again when the widget gets realized. It must be done here as well,
+        * because the outer dialog will ask to 'validate' the connection before the security tab
+        * is shown/realized (to enable the 'Apply' button).
+        * As 'validate' accesses the contents of the UI fields, they must be initialized now, even
+        * if the widgets are not yet visible. */
+       set_userpass_ui (method);
+
+       return method;
+}
diff --git a/src/nma-ws/nma-eap-simple.h b/src/nma-ws/nma-eap-simple.h
new file mode 100644
index 00000000..8676e395
--- /dev/null
+++ b/src/nma-ws/nma-eap-simple.h
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#ifndef NMA_EAP_SIMPLE_H
+#define NMA_EAP_SIMPLE_H
+
+#include "nma-ws.h"
+
+typedef enum {
+       /* NOTE: when updating this table, also update nma_eap_methods[] */
+       NMA_EAP_SIMPLE_TYPE_PAP = 0,
+       NMA_EAP_SIMPLE_TYPE_MSCHAP,
+       NMA_EAP_SIMPLE_TYPE_MSCHAP_V2,
+       NMA_EAP_SIMPLE_TYPE_PLAIN_MSCHAP_V2,
+       NMA_EAP_SIMPLE_TYPE_MD5,
+       NMA_EAP_SIMPLE_TYPE_PWD,
+       NMA_EAP_SIMPLE_TYPE_CHAP,
+       NMA_EAP_SIMPLE_TYPE_GTC,
+       NMA_EAP_SIMPLE_TYPE_UNKNOWN,
+
+       /* Boundary value, do not use */
+       NMA_EAP_SIMPLE_TYPE_LAST
+} NMAEapSimpleType;
+
+typedef enum {
+       NMA_EAP_SIMPLE_FLAG_NONE            = 0x00,
+       /* Indicates the EAP method is an inner/phase2 method */
+       NMA_EAP_SIMPLE_FLAG_PHASE2          = 0x01,
+       /* Set by TTLS to indicate that inner/phase2 EAP is allowed */
+       NMA_EAP_SIMPLE_FLAG_AUTHEAP_ALLOWED = 0x02,
+       /* Set from nm-connection-editor or the GNOME network panel */
+       NMA_EAP_SIMPLE_FLAG_IS_EDITOR       = 0x04,
+       /* Set to indicate that this request is only for secrets */
+       NMA_EAP_SIMPLE_FLAG_SECRETS_ONLY    = 0x08
+} NMAEapSimpleFlags;
+
+typedef struct _NMAEapSimple NMAEapSimple;
+
+NMAEapSimple *nma_eap_simple_new (NMAWs *ws_parent,
+                                  NMConnection *connection,
+                                  NMAEapSimpleType type,
+                                  NMAEapSimpleFlags flags,
+                                  const char *const*hints);
+
+#endif /* NMA_EAP_SIMPLE_H */
diff --git a/src/nma-ws/nma-eap-simple.ui b/src/nma-ws/nma-eap-simple.ui
new file mode 100644
index 00000000..c0206eb2
--- /dev/null
+++ b/src/nma-ws/nma-eap-simple.ui
@@ -0,0 +1,158 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface domain="nm-applet">
+  <requires lib="gtk+" version="3.10"/>
+  <object class="GtkNotebook" id="eap_simple_notebook">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="show_tabs">False</property>
+    <property name="show_border">False</property>
+    <child>
+      <object class="GtkGrid" id="table11">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="valign">start</property>
+        <property name="row_spacing">6</property>
+        <property name="column_spacing">6</property>
+        <child>
+          <object class="GtkLabel" id="eap_simple_username_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">_Username</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">eap_simple_username_entry</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="eap_simple_password_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">_Password</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">eap_simple_password_entry</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="eap_simple_password_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+            <property name="visibility">False</property>
+            <property name="activates_default">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="eap_simple_username_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+            <property name="activates_default">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox" id="vbox5">
+            <property name="orientation">vertical</property>
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <object class="GtkCheckButton" id="show_checkbutton_eapsimple">
+                <property name="label" translatable="yes">Sho_w password</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_underline">True</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="eap_simple_pkey_passphrase_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">P_rivate Key Passphrase</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">eap_simple_pkey_passphrase_entry</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">3</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="eap_simple_pkey_passphrase_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+            <property name="visibility">False</property>
+            <property name="activates_default">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">3</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="eap_simple_show_pkey_passphrase_checkbutton">
+            <property name="label" translatable="yes">Sh_ow passphrase</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="use_underline">True</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">4</property>
+          </packing>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+      </object>
+    </child>
+    <child type="tab">
+      <object class="GtkLabel" id="label53">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+      </object>
+      <packing>
+        <property name="tab_fill">False</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/src/nma-ws/nma-eap-tls.c b/src/nma-ws/nma-eap-tls.c
new file mode 100644
index 00000000..295fdbb9
--- /dev/null
+++ b/src/nma-ws/nma-eap-tls.c
@@ -0,0 +1,517 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ * Lubomir Rintel <lkundrak v3 sk>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+#include "nma-private.h"
+
+#include <ctype.h>
+#include <string.h>
+
+#include "nma-eap.h"
+#include "nma-ws.h"
+#include "helpers.h"
+#include "nma-ui-utils.h"
+#include "nma-cert-chooser.h"
+#include "utils.h"
+
+struct _NMAEapTLS {
+       NMAEap parent;
+
+#if LIBNM_BUILD
+/* libnm-glib doesn't support these. */
+       const char *ca_cert_password_flags_name;
+       const char *client_cert_password_flags_name;
+#endif
+       const char *client_key_password_flags_name;
+
+       gboolean editing_connection;
+       GtkWidget *ca_cert_chooser;
+       GtkWidget *client_cert_chooser;
+};
+
+
+static gboolean
+validate (NMAEap *parent, GError **error)
+{
+       NMAEapTLS *method = (NMAEapTLS *) parent;
+       GtkWidget *widget;
+       const char *identity;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_identity_entry"));
+       g_assert (widget);
+       identity = gtk_editable_get_text (GTK_EDITABLE (widget));
+       if (!identity || !strlen (identity)) {
+               widget_set_error (widget);
+               g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("missing EAP-TLS identity"));
+               return FALSE;
+       } else {
+               widget_unset_error (widget);
+       }
+
+       if (   gtk_widget_get_sensitive (method->ca_cert_chooser)
+           && !nma_cert_chooser_validate (NMA_CERT_CHOOSER (method->ca_cert_chooser), error))
+               return FALSE;
+
+       if (!nma_cert_chooser_validate (NMA_CERT_CHOOSER (method->client_cert_chooser), error))
+               return FALSE;
+
+       return TRUE;
+}
+
+static void
+ca_cert_not_required_toggled (GtkWidget *button, gpointer user_data)
+{
+       NMAEapTLS *method = (NMAEapTLS *) user_data;
+
+       gtk_widget_set_sensitive (method->ca_cert_chooser,
+                                 !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)));
+}
+
+static void
+add_to_size_group (NMAEap *parent, GtkSizeGroup *group)
+{
+       NMAEapTLS *method = (NMAEapTLS *) parent;
+       GtkWidget *widget;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_identity_label"));
+       g_assert (widget);
+       gtk_size_group_add_widget (group, widget);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_domain_label"));
+       g_assert (widget);
+       gtk_size_group_add_widget (group, widget);
+
+       nma_cert_chooser_add_to_size_group (NMA_CERT_CHOOSER (method->client_cert_chooser), group);
+       nma_cert_chooser_add_to_size_group (NMA_CERT_CHOOSER (method->ca_cert_chooser), group);
+}
+
+static void
+fill_connection (NMAEap *parent, NMConnection *connection)
+{
+       NMAEapTLS *method = (NMAEapTLS *) parent;
+       NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+       NMSetting8021x *s_8021x;
+       NMSettingSecretFlags secret_flags;
+       GtkWidget *widget;
+       char *value = NULL;
+       const char *password = NULL;
+       GError *error = NULL;
+       gboolean ca_cert_error = FALSE;
+       NMSetting8021xCKScheme scheme;
+
+       s_8021x = nm_connection_get_setting_802_1x (connection);
+       g_assert (s_8021x);
+
+       if (parent->phase2)
+               g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, "tls", NULL);
+       else
+               nm_setting_802_1x_add_eap_method (s_8021x, "tls");
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_identity_entry"));
+       g_assert (widget);
+       g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, gtk_editable_get_text (GTK_EDITABLE (widget)), 
NULL);
+
+#if LIBNM_BUILD
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_domain_entry"));
+       g_assert (widget);
+       g_object_set (s_8021x,
+                     parent->phase2 ? NM_SETTING_802_1X_PHASE2_DOMAIN_SUFFIX_MATCH : 
NM_SETTING_802_1X_DOMAIN_SUFFIX_MATCH,
+                     gtk_editable_get_text (GTK_EDITABLE (widget)), NULL);
+#endif
+
+       /* TLS private key */
+       password = nma_cert_chooser_get_key_password (NMA_CERT_CHOOSER (method->client_cert_chooser));
+       value = nma_cert_chooser_get_key (NMA_CERT_CHOOSER (method->client_cert_chooser), &scheme);
+
+       if (parent->phase2) {
+               if (!nm_setting_802_1x_set_phase2_private_key (s_8021x, value, password, scheme, &format, 
&error)) {
+                       g_warning ("Couldn't read phase2 private key '%s': %s", value, error ? error->message 
: "(unknown)");
+                       g_clear_error (&error);
+               }
+       } else {
+               if (!nm_setting_802_1x_set_private_key (s_8021x, value, password, scheme, &format, &error)) {
+                       g_warning ("Couldn't read private key '%s': %s", value, error ? error->message : 
"(unknown)");
+                       g_clear_error (&error);
+               }
+       }
+       g_free (value);
+
+#if LIBNM_BUILD
+/* libnm-glib doesn't support these. */
+       /* Save CA certificate PIN and its flags to the connection */
+       secret_flags = nma_cert_chooser_get_cert_password_flags (NMA_CERT_CHOOSER (method->ca_cert_chooser));
+       nm_setting_set_secret_flags (NM_SETTING (s_8021x), method->ca_cert_password_flags_name,
+                                    secret_flags, NULL);
+       if (method->editing_connection) {
+               /* Update secret flags and popup when editing the connection */
+               nma_cert_chooser_update_cert_password_storage (NMA_CERT_CHOOSER (method->ca_cert_chooser),
+                                                              secret_flags, NM_SETTING (s_8021x),
+                                                              method->ca_cert_password_flags_name);
+               g_object_set (s_8021x, method->ca_cert_password_flags_name,
+                             nma_cert_chooser_get_cert_password (NMA_CERT_CHOOSER (method->ca_cert_chooser)),
+                             NULL);
+       }
+
+       /* Save user certificate PIN and its flags flags to the connection */
+       secret_flags = nma_cert_chooser_get_cert_password_flags (NMA_CERT_CHOOSER 
(method->client_cert_chooser));
+       nm_setting_set_secret_flags (NM_SETTING (s_8021x), method->client_cert_password_flags_name,
+                                    secret_flags, NULL);
+       if (method->editing_connection) {
+               nma_cert_chooser_update_cert_password_storage (NMA_CERT_CHOOSER (method->client_cert_chooser),
+                                                              secret_flags, NM_SETTING (s_8021x),
+                                                              method->client_cert_password_flags_name);
+               g_object_set (s_8021x, method->client_cert_password_flags_name,
+                             nma_cert_chooser_get_cert_password (NMA_CERT_CHOOSER 
(method->client_cert_chooser)),
+                             NULL);
+       }
+#endif
+
+       /* Save user private key password flags to the connection */
+       secret_flags = nma_cert_chooser_get_key_password_flags (NMA_CERT_CHOOSER 
(method->client_cert_chooser));
+       nm_setting_set_secret_flags (NM_SETTING (s_8021x), method->client_key_password_flags_name,
+                                    secret_flags, NULL);
+       if (method->editing_connection) {
+               nma_cert_chooser_update_key_password_storage (NMA_CERT_CHOOSER (method->client_cert_chooser),
+                                                             secret_flags, NM_SETTING (s_8021x),
+                                                             method->client_key_password_flags_name);
+       }
+
+       /* TLS client certificate */
+       if (format != NM_SETTING_802_1X_CK_FORMAT_PKCS12) {
+               /* If the key is pkcs#12 nm_setting_802_1x_set_private_key() already
+                * set the client certificate for us.
+                */
+               value = nma_cert_chooser_get_cert (NMA_CERT_CHOOSER (method->client_cert_chooser), &scheme);
+               format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+               if (parent->phase2) {
+                       if (!nm_setting_802_1x_set_phase2_client_cert (s_8021x, value, scheme, &format, 
&error)) {
+                               g_warning ("Couldn't read phase2 client certificate '%s': %s", value, error ? 
error->message : "(unknown)");
+                               g_clear_error (&error);
+                       }
+               } else {
+                       if (!nm_setting_802_1x_set_client_cert (s_8021x, value, scheme, &format, &error)) {
+                               g_warning ("Couldn't read client certificate '%s': %s", value, error ? 
error->message : "(unknown)");
+                               g_clear_error (&error);
+                       }
+               }
+               g_free (value);
+       }
+
+       /* TLS CA certificate */
+       if (gtk_widget_get_sensitive (method->ca_cert_chooser))
+               value = nma_cert_chooser_get_cert (NMA_CERT_CHOOSER (method->ca_cert_chooser), &scheme);
+       else
+               value = NULL;
+       format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+       if (parent->phase2) {
+               if (!nm_setting_802_1x_set_phase2_ca_cert (s_8021x, value, scheme, &format, &error)) {
+                       g_warning ("Couldn't read phase2 CA certificate '%s': %s", value, error ? 
error->message : "(unknown)");
+                       g_clear_error (&error);
+                       ca_cert_error = TRUE;
+               }
+       } else {
+               if (!nm_setting_802_1x_set_ca_cert (s_8021x, value, scheme, &format, &error)) {
+                       g_warning ("Couldn't read CA certificate '%s': %s", value, error ? error->message : 
"(unknown)");
+                       g_clear_error (&error);
+                       ca_cert_error = TRUE;
+               }
+       }
+       nma_eap_ca_cert_ignore_set (parent, connection, value, ca_cert_error);
+       g_free (value);
+}
+
+static GError *
+client_cert_validate_cb (NMACertChooser *cert_chooser, gpointer user_data)
+{
+       NMSetting8021xCKScheme scheme;
+       NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+       gs_unref_object NMSetting8021x *setting = NULL;
+       gs_free char *value = NULL;
+       GError *local = NULL;
+
+       setting = (NMSetting8021x *) nm_setting_802_1x_new ();
+
+       value = nma_cert_chooser_get_cert (cert_chooser, &scheme);
+       if (!value) {
+               return g_error_new_literal (NMA_ERROR, NMA_ERROR_GENERIC,
+                                           _("no user certificate selected"));
+       }
+       if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) {
+               if (!g_file_test (value, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
+                       return g_error_new_literal (NMA_ERROR, NMA_ERROR_GENERIC,
+                                                   _("selected user certificate file does not exist"));
+               }
+       }
+
+       if (!nm_setting_802_1x_set_client_cert (setting, value, scheme, &format, &local))
+               return local;
+
+       return NULL;
+}
+
+static GError *
+client_key_validate_cb (NMACertChooser *cert_chooser, gpointer user_data)
+{
+       NMSetting8021xCKScheme scheme;
+       gs_free char *value = NULL;
+
+
+       value = nma_cert_chooser_get_key (cert_chooser, &scheme);
+       if (!value) {
+               return g_error_new_literal (NMA_ERROR, NMA_ERROR_GENERIC,
+                                           _("no key selected"));
+       }
+       if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) {
+               if (!g_file_test (value, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
+                       return g_error_new_literal (NMA_ERROR, NMA_ERROR_GENERIC,
+                                                   _("selected key file does not exist"));
+               }
+       }
+
+       return NULL;
+}
+
+static GError *
+client_key_password_validate_cb (NMACertChooser *cert_chooser, gpointer user_data)
+{
+       NMSetting8021xCKScheme scheme;
+       NMSettingSecretFlags secret_flags;
+       gs_unref_object NMSetting8021x *setting = NULL;
+       gs_free char *value = NULL;
+       const char *password = NULL;
+       GError *local = NULL;
+
+       secret_flags = nma_cert_chooser_get_key_password_flags (cert_chooser);
+       if (   secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED
+           || secret_flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED)
+               return NULL;
+
+       setting = (NMSetting8021x *) nm_setting_802_1x_new ();
+
+       value = nma_cert_chooser_get_key (cert_chooser, &scheme);
+       password = nma_cert_chooser_get_key_password (cert_chooser);
+       if (!nm_setting_802_1x_set_private_key (setting, value, password, scheme, NULL, &local))
+               return local;
+
+       return NULL;
+}
+
+static void
+client_cert_fixup_pkcs12 (NMACertChooser *cert_chooser, gpointer user_data)
+{
+       NMSetting8021xCKScheme cert_scheme, key_scheme;
+       NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+       gs_free char *cert_value = NULL;
+       gs_free char *key_value = NULL;
+       gs_unref_object NMSetting8021x *setting = NULL;
+
+       setting = (NMSetting8021x *) nm_setting_802_1x_new ();
+
+       cert_value = nma_cert_chooser_get_cert (cert_chooser, &cert_scheme);
+       key_value = nma_cert_chooser_get_key (cert_chooser, &key_scheme);
+
+       if (   !cert_value || key_value
+           || !nm_setting_802_1x_set_client_cert (setting, cert_value, cert_scheme, &format, NULL))
+               return;
+
+       if (format == NM_SETTING_802_1X_CK_FORMAT_PKCS12)
+               nma_cert_chooser_set_key (cert_chooser, cert_value, cert_scheme);
+}
+
+static void
+update_secrets (NMAEap *parent, NMConnection *connection)
+{
+       NMAEapTLS *method = (NMAEapTLS *) parent;
+
+       nma_eap_setup_cert_chooser (NMA_CERT_CHOOSER (method->client_cert_chooser),
+                                   nm_connection_get_setting_802_1x (connection),
+                                   NULL,
+                                   NULL,
+                                   NULL,
+                                   parent->phase2 ? nm_setting_802_1x_get_phase2_client_cert_password : 
nm_setting_802_1x_get_client_cert_password,
+                                   parent->phase2 ? nm_setting_802_1x_get_phase2_private_key_scheme : 
nm_setting_802_1x_get_private_key_scheme,
+                                   parent->phase2 ? nm_setting_802_1x_get_phase2_private_key_path : 
nm_setting_802_1x_get_private_key_path,
+                                   parent->phase2 ? nm_setting_802_1x_get_phase2_private_key_uri : 
nm_setting_802_1x_get_private_key_uri,
+                                   parent->phase2 ? nm_setting_802_1x_get_phase2_private_key_password : 
nm_setting_802_1x_get_private_key_password);
+}
+
+NMAEapTLS *
+nma_eap_tls_new (NMAWs *ws_parent,
+                 NMConnection *connection,
+                 gboolean phase2,
+                 gboolean secrets_only)
+{
+       NMAEapTLS *method;
+       NMAEap *parent;
+       GtkWidget *widget;
+       NMSetting8021x *s_8021x = NULL;
+       gboolean ca_not_required = FALSE;
+
+       parent = nma_eap_init (sizeof (NMAEapTLS),
+                              validate,
+                              add_to_size_group,
+                              fill_connection,
+                              update_secrets,
+                              NULL,
+                              "/org/gnome/libnma/nma-eap-tls.ui",
+                              "eap_tls_notebook",
+                              "eap_tls_identity_entry",
+                              phase2);
+       if (!parent)
+               return NULL;
+
+       method = (NMAEapTLS *) parent;
+#if LIBNM_BUILD
+/* libnm-glib doesn't support these. */
+       method->ca_cert_password_flags_name = phase2
+                                             ? NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD
+                                             : NM_SETTING_802_1X_CA_CERT_PASSWORD;
+       method->client_cert_password_flags_name = phase2
+                                                 ? NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD
+                                                 : NM_SETTING_802_1X_CLIENT_CERT_PASSWORD;
+#endif
+       method->client_key_password_flags_name = phase2
+                                                ? NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD
+                                                : NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD;
+       method->editing_connection = secrets_only ? FALSE : TRUE;
+
+       if (connection)
+               s_8021x = nm_connection_get_setting_802_1x (connection);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, 
"eap_tls_ca_cert_not_required_checkbox"));
+       g_assert (widget);
+       g_signal_connect (G_OBJECT (widget), "toggled",
+                         (GCallback) ca_cert_not_required_toggled,
+                         parent);
+       g_signal_connect (G_OBJECT (widget), "toggled",
+                         (GCallback) nma_ws_changed_cb,
+                         ws_parent);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_identity_entry"));
+       g_assert (widget);
+       g_signal_connect (G_OBJECT (widget), "changed",
+                         (GCallback) nma_ws_changed_cb,
+                         ws_parent);
+       if (s_8021x && nm_setting_802_1x_get_identity (s_8021x))
+               gtk_editable_set_text (GTK_EDITABLE (widget), nm_setting_802_1x_get_identity (s_8021x));
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_domain_entry"));
+       g_assert (widget);
+#if LIBNM_BUILD
+       g_signal_connect (G_OBJECT (widget), "changed",
+                         (GCallback) nma_ws_changed_cb,
+                         ws_parent);
+       if (phase2) {
+               if (s_8021x && nm_setting_802_1x_get_phase2_domain_suffix_match (s_8021x))
+                       gtk_editable_set_text (GTK_EDITABLE (widget), 
nm_setting_802_1x_get_phase2_domain_suffix_match (s_8021x));
+       } else {
+               if (s_8021x && nm_setting_802_1x_get_domain_suffix_match (s_8021x))
+                       gtk_editable_set_text (GTK_EDITABLE (widget), 
nm_setting_802_1x_get_domain_suffix_match (s_8021x));
+       }
+#else
+       gtk_widget_hide (widget);
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_domain_label"));
+       gtk_widget_hide (widget);
+#endif
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_grid"));
+       g_assert (widget);
+
+       method->ca_cert_chooser = nma_cert_chooser_new ("CA",
+                                                         NMA_CERT_CHOOSER_FLAG_CERT
+                                                       | (secrets_only ? NMA_CERT_CHOOSER_FLAG_PASSWORDS : 
0));
+       gtk_grid_attach (GTK_GRID (widget), method->ca_cert_chooser, 0, 2, 2, 1);
+       gtk_widget_show (method->ca_cert_chooser);
+
+       g_signal_connect (method->ca_cert_chooser,
+                         "cert-validate",
+                         G_CALLBACK (nma_eap_ca_cert_validate_cb),
+                         NULL);
+       g_signal_connect (method->ca_cert_chooser,
+                         "changed",
+                         G_CALLBACK (nma_ws_changed_cb),
+                         ws_parent);
+
+       nma_eap_setup_cert_chooser (NMA_CERT_CHOOSER (method->ca_cert_chooser), s_8021x,
+                                   phase2 ? nm_setting_802_1x_get_phase2_ca_cert_scheme : 
nm_setting_802_1x_get_ca_cert_scheme,
+                                   phase2 ? nm_setting_802_1x_get_phase2_ca_cert_path : 
nm_setting_802_1x_get_ca_cert_path,
+                                   phase2 ? nm_setting_802_1x_get_phase2_ca_cert_uri : 
nm_setting_802_1x_get_ca_cert_uri,
+                                   phase2 ? nm_setting_802_1x_get_phase2_ca_cert_password : 
nm_setting_802_1x_get_ca_cert_password,
+                                   NULL,
+                                   NULL,
+                                   NULL,
+                                   NULL);
+
+       if (connection && nma_eap_ca_cert_ignore_get (parent, connection)) {
+               gchar *ca_cert;
+               NMSetting8021xCKScheme scheme;
+
+               ca_cert = nma_cert_chooser_get_cert (NMA_CERT_CHOOSER (method->ca_cert_chooser), &scheme);
+               if (ca_cert)
+                       g_free (ca_cert);
+               else
+                       ca_not_required = TRUE;
+       }
+
+       if (secrets_only)
+               ca_not_required = TRUE;
+
+       method->client_cert_chooser = nma_cert_chooser_new ("User",
+                                                           secrets_only ? NMA_CERT_CHOOSER_FLAG_PASSWORDS : 
0);
+       gtk_grid_attach (GTK_GRID (widget), method->client_cert_chooser, 0, 4, 2, 1);
+       gtk_widget_show (method->client_cert_chooser);
+
+       g_signal_connect (method->client_cert_chooser, "cert-validate",
+                         G_CALLBACK (client_cert_validate_cb),
+                         NULL);
+       g_signal_connect (method->client_cert_chooser,
+                         "key-validate",
+                         G_CALLBACK (client_key_validate_cb),
+                         NULL);
+       g_signal_connect (method->client_cert_chooser,
+                         "key-password-validate",
+                         G_CALLBACK (client_key_password_validate_cb),
+                         NULL);
+       g_signal_connect (method->client_cert_chooser,
+                         "changed",
+                         G_CALLBACK (client_cert_fixup_pkcs12),
+                         ws_parent);
+       g_signal_connect (method->client_cert_chooser,
+                         "changed",
+                         G_CALLBACK (nma_ws_changed_cb),
+                         ws_parent);
+
+       nma_eap_setup_cert_chooser (NMA_CERT_CHOOSER (method->client_cert_chooser), s_8021x,
+                                   phase2 ? nm_setting_802_1x_get_phase2_client_cert_scheme : 
nm_setting_802_1x_get_client_cert_scheme,
+                                   phase2 ? nm_setting_802_1x_get_phase2_client_cert_path : 
nm_setting_802_1x_get_client_cert_path,
+                                   phase2 ? nm_setting_802_1x_get_phase2_client_cert_uri : 
nm_setting_802_1x_get_client_cert_uri,
+                                   phase2 ? nm_setting_802_1x_get_phase2_client_cert_password : 
nm_setting_802_1x_get_client_cert_password,
+                                   phase2 ? nm_setting_802_1x_get_phase2_private_key_scheme : 
nm_setting_802_1x_get_private_key_scheme,
+                                   phase2 ? nm_setting_802_1x_get_phase2_private_key_path : 
nm_setting_802_1x_get_private_key_path,
+                                   phase2 ? nm_setting_802_1x_get_phase2_private_key_uri : 
nm_setting_802_1x_get_private_key_uri,
+                                   phase2 ? nm_setting_802_1x_get_phase2_private_key_password : 
nm_setting_802_1x_get_private_key_password);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, 
"eap_tls_ca_cert_not_required_checkbox"));
+       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), ca_not_required);
+
+       /* Create password-storage popup menus for password entries under their secondary icon */
+#if LIBNM_BUILD
+/* libnm-glib doesn't support these. */
+       nma_cert_chooser_setup_cert_password_storage (NMA_CERT_CHOOSER (method->ca_cert_chooser),
+                                                     0, (NMSetting *) s_8021x, 
method->ca_cert_password_flags_name,
+                                                     FALSE, secrets_only);
+       nma_cert_chooser_setup_cert_password_storage (NMA_CERT_CHOOSER (method->client_cert_chooser),
+                                                     0, (NMSetting *) s_8021x, 
method->client_cert_password_flags_name,
+                                                     FALSE, secrets_only);
+#endif
+       nma_cert_chooser_setup_key_password_storage (NMA_CERT_CHOOSER (method->client_cert_chooser),
+                                                    0, (NMSetting *) s_8021x, 
method->client_key_password_flags_name,
+                                                    FALSE, secrets_only);
+
+       return method;
+}
diff --git a/src/nma-ws/nma-eap-tls.h b/src/nma-ws/nma-eap-tls.h
new file mode 100644
index 00000000..105e0426
--- /dev/null
+++ b/src/nma-ws/nma-eap-tls.h
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#ifndef NMA_EAP_TLS_H
+#define NMA_EAP_TLS_H
+
+#include "nma-ws.h"
+
+typedef struct _NMAEapTLS NMAEapTLS;
+
+NMAEapTLS *nma_eap_tls_new (NMAWs *ws_parent,
+                            NMConnection *connection,
+                            gboolean phase2,
+                            gboolean secrets_only);
+
+#endif /* NMA_EAP_TLS_H */
diff --git a/src/nma-ws/nma-eap-tls.ui b/src/nma-ws/nma-eap-tls.ui
new file mode 100644
index 00000000..acca95cd
--- /dev/null
+++ b/src/nma-ws/nma-eap-tls.ui
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface domain="nm-applet">
+  <requires lib="gtk+" version="3.10"/>
+  <object class="GtkNotebook" id="eap_tls_notebook">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="show_tabs">False</property>
+    <property name="show_border">False</property>
+    <child>
+      <object class="GtkGrid" id="eap_tls_grid">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="row_spacing">6</property>
+        <property name="column_spacing">6</property>
+        <child>
+          <object class="GtkLabel" id="eap_tls_identity_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">I_dentity</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">eap_tls_identity_entry</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="eap_tls_identity_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+            <property name="activates_default">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="eap_tls_ca_cert_not_required_checkbox">
+            <property name="label" translatable="yes">No CA certificate is _required</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="halign">start</property>
+            <property name="hexpand">True</property>
+            <property name="use_underline">True</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">3</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="eap_tls_domain_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="tooltip_text" translatable="yes">Suffix of the server certificate 
name.</property>
+            <property name="label" translatable="yes">_Domain</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">eap_tls_domain_entry</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="eap_tls_domain_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+            <property name="activates_default">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+      </object>
+    </child>
+    <child type="tab">
+      <object class="GtkLabel" id="label34">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+      </object>
+      <packing>
+        <property name="tab_fill">False</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/src/nma-ws/nma-eap-ttls.c b/src/nma-ws/nma-eap-ttls.c
new file mode 100644
index 00000000..6f975d10
--- /dev/null
+++ b/src/nma-ws/nma-eap-ttls.c
@@ -0,0 +1,535 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+#include "nma-private.h"
+
+#include <ctype.h>
+#include <string.h>
+
+#include "nma-eap.h"
+#include "nma-ws.h"
+#include "nma-cert-chooser.h"
+#include "utils.h"
+
+#define I_NAME_COLUMN   0
+#define I_METHOD_COLUMN 1
+
+struct _NMAEapTTLS {
+       NMAEap parent;
+
+       const char *password_flags_name;
+       GtkSizeGroup *size_group;
+       NMAWs *sec_parent;
+       gboolean is_editor;
+
+       GtkWidget *ca_cert_chooser;
+};
+
+static void
+destroy (NMAEap *parent)
+{
+       NMAEapTTLS *method = (NMAEapTTLS *) parent;
+
+       if (method->size_group)
+               g_object_unref (method->size_group);
+}
+
+static gboolean
+validate (NMAEap *parent, GError **error)
+{
+       NMAEapTTLS *method = (NMAEapTTLS *) parent;
+       GtkWidget *widget;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       NMAEap *eap = NULL;
+       gboolean valid = FALSE;
+
+       if (   gtk_widget_get_sensitive (method->ca_cert_chooser)
+           && !nma_cert_chooser_validate (NMA_CERT_CHOOSER (method->ca_cert_chooser), error))
+               return FALSE;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_ttls_inner_auth_combo"));
+       g_assert (widget);
+
+       model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
+       gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter);
+       gtk_tree_model_get (model, &iter, I_METHOD_COLUMN, &eap, -1);
+       g_assert (eap);
+       valid = nma_eap_validate (eap, error);
+       nma_eap_unref (eap);
+       return valid;
+}
+
+static void
+ca_cert_not_required_toggled (GtkWidget *button, gpointer user_data)
+{
+       NMAEapTTLS *method = (NMAEapTTLS *) user_data;
+
+       gtk_widget_set_sensitive (method->ca_cert_chooser,
+                                 !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)));
+}
+
+static void
+add_to_size_group (NMAEap *parent, GtkSizeGroup *group)
+{
+       NMAEapTTLS *method = (NMAEapTTLS *) parent;
+       GtkWidget *widget;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       NMAEap *eap;
+
+       if (method->size_group)
+               g_object_unref (method->size_group);
+       method->size_group = g_object_ref (group);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_ttls_anon_identity_label"));
+       g_assert (widget);
+       gtk_size_group_add_widget (group, widget);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_ttls_domain_label"));
+       g_assert (widget);
+       gtk_size_group_add_widget (group, widget);
+
+       nma_cert_chooser_add_to_size_group (NMA_CERT_CHOOSER (method->ca_cert_chooser), group);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_ttls_inner_auth_label"));
+       g_assert (widget);
+       gtk_size_group_add_widget (group, widget);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_ttls_inner_auth_combo"));
+       g_assert (widget);
+
+       model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
+       gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter);
+       gtk_tree_model_get (model, &iter, I_METHOD_COLUMN, &eap, -1);
+       g_assert (eap);
+       nma_eap_add_to_size_group (eap, group);
+       nma_eap_unref (eap);
+}
+
+static void
+fill_connection (NMAEap *parent, NMConnection *connection)
+{
+       NMAEapTTLS *method = (NMAEapTTLS *) parent;
+       NMSetting8021x *s_8021x;
+       NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+#if LIBNM_BUILD
+       NMSettingSecretFlags secret_flags;
+#endif
+       GtkWidget *widget;
+       const char *text;
+       char *value = NULL;
+       NMAEap *eap = NULL;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       GError *error = NULL;
+       NMSetting8021xCKScheme scheme = NM_SETTING_802_1X_CK_SCHEME_UNKNOWN;
+       gboolean ca_cert_error = FALSE;
+
+       s_8021x = nm_connection_get_setting_802_1x (connection);
+       g_assert (s_8021x);
+
+       nm_setting_802_1x_add_eap_method (s_8021x, "ttls");
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_ttls_anon_identity_entry"));
+       g_assert (widget);
+       text = gtk_editable_get_text (GTK_EDITABLE (widget));
+       if (text && strlen (text))
+               g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, text, NULL);
+
+#if LIBNM_BUILD
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_ttls_domain_entry"));
+       g_assert (widget);
+       text = gtk_editable_get_text (GTK_EDITABLE (widget));
+       if (text && strlen (text))
+               g_object_set (s_8021x, NM_SETTING_802_1X_DOMAIN_SUFFIX_MATCH, text, NULL);
+#endif
+
+#if LIBNM_BUILD
+/* libnm-glib doesn't support this. */
+       /* Save CA certificate PIN and its flags to the connection */
+       secret_flags = nma_cert_chooser_get_cert_password_flags (NMA_CERT_CHOOSER (method->ca_cert_chooser));
+       nm_setting_set_secret_flags (NM_SETTING (s_8021x), NM_SETTING_802_1X_CA_CERT_PASSWORD,
+                                    secret_flags, NULL);
+       if (method->is_editor) {
+               /* Update secret flags and popup when editing the connection */
+               nma_cert_chooser_update_cert_password_storage (NMA_CERT_CHOOSER (method->ca_cert_chooser),
+                                                              secret_flags, NM_SETTING (s_8021x),
+                                                              NM_SETTING_802_1X_CA_CERT_PASSWORD);
+               g_object_set (s_8021x, NM_SETTING_802_1X_CA_CERT_PASSWORD,
+                             nma_cert_chooser_get_cert_password (NMA_CERT_CHOOSER (method->ca_cert_chooser)),
+                             NULL);
+       }
+#endif
+
+       /* TLS CA certificate */
+       if (gtk_widget_get_sensitive (method->ca_cert_chooser))
+               value = nma_cert_chooser_get_cert (NMA_CERT_CHOOSER (method->ca_cert_chooser), &scheme);
+       format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+       if (!nm_setting_802_1x_set_ca_cert (s_8021x, value, scheme, &format, &error)) {
+               g_warning ("Couldn't read CA certificate '%s': %s", value, error ? error->message : 
"(unknown)");
+               g_clear_error (&error);
+               ca_cert_error = TRUE;
+       }
+       nma_eap_ca_cert_ignore_set (parent, connection, value, ca_cert_error);
+       g_free (value);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_ttls_inner_auth_combo"));
+       model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
+       gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter);
+       gtk_tree_model_get (model, &iter, I_METHOD_COLUMN, &eap, -1);
+       g_assert (eap);
+
+       nma_eap_fill_connection (eap, connection);
+       nma_eap_unref (eap);
+}
+
+static void
+inner_auth_combo_changed_cb (GtkWidget *combo, gpointer user_data)
+{
+       NMAEap *parent = (NMAEap *) user_data;
+       NMAEapTTLS *method = (NMAEapTTLS *) parent;
+       GtkWidget *vbox;
+       NMAEap *eap = NULL;
+       GList *elt, *children;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       GtkWidget *eap_widget;
+
+       vbox = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_ttls_inner_auth_vbox"));
+       g_assert (vbox);
+
+       /* Remove any previous wireless security widgets */
+       children = gtk_container_get_children (GTK_CONTAINER (vbox));
+       for (elt = children; elt; elt = g_list_next (elt))
+               gtk_container_remove (GTK_CONTAINER (vbox), GTK_WIDGET (elt->data));
+       g_list_free (children);
+
+       model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
+       gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter);
+       gtk_tree_model_get (model, &iter, I_METHOD_COLUMN, &eap, -1);
+       g_assert (eap);
+
+       eap_widget = nma_eap_get_widget (eap);
+       g_assert (eap_widget);
+       gtk_widget_unparent (eap_widget);
+
+       if (method->size_group)
+               nma_eap_add_to_size_group (eap, method->size_group);
+       gtk_container_add (GTK_CONTAINER (vbox), eap_widget);
+
+       nma_eap_unref (eap);
+
+       nma_ws_changed_cb (combo, method->sec_parent);
+}
+
+static GtkWidget *
+inner_auth_combo_init (NMAEapTTLS *method,
+                       NMConnection *connection,
+                       NMSetting8021x *s_8021x,
+                       gboolean secrets_only)
+{
+       NMAEap *parent = (NMAEap *) method;
+       GtkWidget *combo;
+       GtkListStore *auth_model;
+       GtkTreeIter iter;
+       NMAEapSimple *em_pap;
+       NMAEapSimple *em_mschap;
+       NMAEapSimple *em_mschap_v2;
+       NMAEapSimple *em_plain_mschap_v2;
+       NMAEapSimple *em_chap;
+       NMAEapSimple *em_md5;
+       NMAEapSimple *em_gtc;
+       guint32 active = 0;
+       const char *phase2_auth = NULL;
+       NMAEapSimpleFlags simple_flags;
+
+       auth_model = gtk_list_store_new (2, G_TYPE_STRING, nma_eap_get_type ());
+
+       if (s_8021x) {
+               if (nm_setting_802_1x_get_phase2_auth (s_8021x))
+                       phase2_auth = nm_setting_802_1x_get_phase2_auth (s_8021x);
+               else if (nm_setting_802_1x_get_phase2_autheap (s_8021x))
+                       phase2_auth = nm_setting_802_1x_get_phase2_autheap (s_8021x);
+       }
+
+       simple_flags = NMA_EAP_SIMPLE_FLAG_PHASE2 | NMA_EAP_SIMPLE_FLAG_AUTHEAP_ALLOWED;
+       if (method->is_editor)
+               simple_flags |= NMA_EAP_SIMPLE_FLAG_IS_EDITOR;
+       if (secrets_only)
+               simple_flags |= NMA_EAP_SIMPLE_FLAG_SECRETS_ONLY;
+
+       em_pap = nma_eap_simple_new (method->sec_parent,
+                                    connection,
+                                    NMA_EAP_SIMPLE_TYPE_PAP,
+                                    simple_flags,
+                                    NULL);
+       gtk_list_store_append (auth_model, &iter);
+       gtk_list_store_set (auth_model, &iter,
+                           I_NAME_COLUMN, _("PAP"),
+                           I_METHOD_COLUMN, em_pap,
+                           -1);
+       nma_eap_unref (NMA_EAP (em_pap));
+
+       /* Check for defaulting to PAP */
+       if (phase2_auth && !strcasecmp (phase2_auth, "pap"))
+               active = 0;
+
+       em_mschap = nma_eap_simple_new (method->sec_parent,
+                                       connection,
+                                       NMA_EAP_SIMPLE_TYPE_MSCHAP,
+                                       simple_flags,
+                                       NULL);
+       gtk_list_store_append (auth_model, &iter);
+       gtk_list_store_set (auth_model, &iter,
+                           I_NAME_COLUMN, _("MSCHAP"),
+                           I_METHOD_COLUMN, em_mschap,
+                           -1);
+       nma_eap_unref (NMA_EAP (em_mschap));
+
+       /* Check for defaulting to MSCHAP */
+       if (phase2_auth && !strcasecmp (phase2_auth, "mschap"))
+               active = 1;
+
+       em_mschap_v2 = nma_eap_simple_new (method->sec_parent,
+                                          connection,
+                                          NMA_EAP_SIMPLE_TYPE_MSCHAP_V2,
+                                          simple_flags,
+                                          NULL);
+       gtk_list_store_append (auth_model, &iter);
+       gtk_list_store_set (auth_model, &iter,
+                           I_NAME_COLUMN, _("MSCHAPv2"),
+                           I_METHOD_COLUMN, em_mschap_v2,
+                           -1);
+       nma_eap_unref (NMA_EAP (em_mschap_v2));
+
+       /* Check for defaulting to MSCHAPv2 */
+       if (phase2_auth && !strcasecmp (phase2_auth, "mschapv2") &&
+           nm_setting_802_1x_get_phase2_autheap (s_8021x) != NULL)
+               active = 2;
+
+       em_plain_mschap_v2 = nma_eap_simple_new (method->sec_parent,
+                                                connection,
+                                                NMA_EAP_SIMPLE_TYPE_PLAIN_MSCHAP_V2,
+                                                simple_flags,
+                                                NULL);
+       gtk_list_store_append (auth_model, &iter);
+       gtk_list_store_set (auth_model, &iter,
+                           I_NAME_COLUMN, _("MSCHAPv2 (no EAP)"),
+                           I_METHOD_COLUMN, em_plain_mschap_v2,
+                           -1);
+       nma_eap_unref (NMA_EAP (em_plain_mschap_v2));
+
+       /* Check for defaulting to plain MSCHAPv2 */
+       if (phase2_auth && !strcasecmp (phase2_auth, "mschapv2") &&
+           nm_setting_802_1x_get_phase2_auth (s_8021x) != NULL)
+               active = 3;
+
+       em_chap = nma_eap_simple_new (method->sec_parent,
+                                     connection,
+                                     NMA_EAP_SIMPLE_TYPE_CHAP,
+                                     simple_flags,
+                                     NULL);
+       gtk_list_store_append (auth_model, &iter);
+       gtk_list_store_set (auth_model, &iter,
+                           I_NAME_COLUMN, _("CHAP"),
+                           I_METHOD_COLUMN, em_chap,
+                           -1);
+       nma_eap_unref (NMA_EAP (em_chap));
+
+       /* Check for defaulting to CHAP */
+       if (phase2_auth && !strcasecmp (phase2_auth, "chap"))
+               active = 4;
+
+       em_md5 = nma_eap_simple_new (method->sec_parent,
+                                    connection,
+                                    NMA_EAP_SIMPLE_TYPE_MD5,
+                                    simple_flags,
+                                    NULL);
+       gtk_list_store_append (auth_model, &iter);
+       gtk_list_store_set (auth_model, &iter,
+                           I_NAME_COLUMN, _("MD5"),
+                           I_METHOD_COLUMN, em_md5,
+                           -1);
+       nma_eap_unref (NMA_EAP (em_md5));
+
+       /* Check for defaulting to MD5 */
+       if (phase2_auth && !strcasecmp (phase2_auth, "md5"))
+               active = 5;
+
+       em_gtc = nma_eap_simple_new (method->sec_parent,
+                                    connection,
+                                    NMA_EAP_SIMPLE_TYPE_GTC,
+                                    simple_flags,
+                                    NULL);
+       gtk_list_store_append (auth_model, &iter);
+       gtk_list_store_set (auth_model, &iter,
+                           I_NAME_COLUMN, _("GTC"),
+                           I_METHOD_COLUMN, em_gtc,
+                           -1);
+       nma_eap_unref (NMA_EAP (em_gtc));
+
+       /* Check for defaulting to GTC */
+       if (phase2_auth && !strcasecmp (phase2_auth, "gtc"))
+               active = 6;
+
+       combo = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_ttls_inner_auth_combo"));
+       g_assert (combo);
+
+       gtk_combo_box_set_model (GTK_COMBO_BOX (combo), GTK_TREE_MODEL (auth_model));
+       g_object_unref (G_OBJECT (auth_model));
+       gtk_combo_box_set_active (GTK_COMBO_BOX (combo), active);
+
+       g_signal_connect (G_OBJECT (combo), "changed",
+                         (GCallback) inner_auth_combo_changed_cb,
+                         method);
+       return combo;
+}
+
+static void
+update_secrets (NMAEap *parent, NMConnection *connection)
+{
+       nma_eap_phase2_update_secrets_helper (parent,
+                                             connection,
+                                             "eap_ttls_inner_auth_combo",
+                                             I_METHOD_COLUMN);
+}
+
+NMAEapTTLS *
+nma_eap_ttls_new (NMAWs *ws_parent,
+                     NMConnection *connection,
+                     gboolean is_editor,
+                     gboolean secrets_only)
+{
+       NMAEap *parent;
+       NMAEapTTLS *method;
+       GtkWidget *widget;
+       NMSetting8021x *s_8021x = NULL;
+       gboolean ca_not_required = FALSE;
+
+       parent = nma_eap_init (sizeof (NMAEapTTLS),
+                              validate,
+                              add_to_size_group,
+                              fill_connection,
+                              update_secrets,
+                              destroy,
+                              "/org/gnome/libnma/nma-eap-ttls.ui",
+                              "eap_ttls_notebook",
+                              "eap_ttls_anon_identity_entry",
+                              FALSE);
+       if (!parent)
+               return NULL;
+
+       method = (NMAEapTTLS *) parent;
+       method->password_flags_name = NM_SETTING_802_1X_PASSWORD;
+       method->sec_parent = ws_parent;
+       method->is_editor = is_editor;
+
+       if (connection)
+               s_8021x = nm_connection_get_setting_802_1x (connection);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_ttls_grid"));
+       g_assert (widget);
+
+       method->ca_cert_chooser = nma_cert_chooser_new ("CA",
+                                                         NMA_CERT_CHOOSER_FLAG_CERT
+                                                       | (secrets_only ? NMA_CERT_CHOOSER_FLAG_PASSWORDS : 
0));
+       gtk_grid_attach (GTK_GRID (widget), method->ca_cert_chooser, 0, 2, 2, 1);
+       gtk_widget_show (method->ca_cert_chooser);
+
+       g_signal_connect (method->ca_cert_chooser,
+                         "cert-validate",
+                         G_CALLBACK (nma_eap_ca_cert_validate_cb),
+                         NULL);
+       g_signal_connect (method->ca_cert_chooser,
+                         "changed",
+                         G_CALLBACK (nma_ws_changed_cb),
+                         ws_parent);
+
+       nma_eap_setup_cert_chooser (NMA_CERT_CHOOSER (method->ca_cert_chooser), s_8021x,
+                                   nm_setting_802_1x_get_ca_cert_scheme,
+                                   nm_setting_802_1x_get_ca_cert_path,
+                                   nm_setting_802_1x_get_ca_cert_uri,
+                                   nm_setting_802_1x_get_ca_cert_password,
+                                   NULL,
+                                   NULL,
+                                   NULL,
+                                   NULL);
+
+       if (connection && nma_eap_ca_cert_ignore_get (parent, connection)) {
+               gchar *ca_cert;
+               NMSetting8021xCKScheme scheme;
+
+               ca_cert = nma_cert_chooser_get_cert (NMA_CERT_CHOOSER (method->ca_cert_chooser), &scheme);
+               if (ca_cert)
+                       g_free (ca_cert);
+               else
+                       ca_not_required = TRUE;
+       }
+
+       if (secrets_only)
+               ca_not_required = TRUE;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, 
"eap_ttls_ca_cert_not_required_checkbox"));
+       g_assert (widget);
+       g_signal_connect (G_OBJECT (widget), "toggled",
+                         (GCallback) ca_cert_not_required_toggled,
+                         parent);
+       g_signal_connect (G_OBJECT (widget), "toggled",
+                         (GCallback) nma_ws_changed_cb,
+                         ws_parent);
+       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), ca_not_required);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_ttls_anon_identity_entry"));
+       if (s_8021x && nm_setting_802_1x_get_anonymous_identity (s_8021x))
+               gtk_editable_set_text (GTK_EDITABLE (widget), nm_setting_802_1x_get_anonymous_identity 
(s_8021x));
+       g_signal_connect (G_OBJECT (widget), "changed",
+                         (GCallback) nma_ws_changed_cb,
+                         ws_parent);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_ttls_domain_entry"));
+#if LIBNM_BUILD
+       if (s_8021x && nm_setting_802_1x_get_domain_suffix_match (s_8021x))
+               gtk_editable_set_text (GTK_EDITABLE (widget), nm_setting_802_1x_get_domain_suffix_match 
(s_8021x));
+       g_signal_connect (G_OBJECT (widget), "changed",
+                         (GCallback) nma_ws_changed_cb,
+                         ws_parent);
+#else
+       gtk_widget_hide (widget);
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_ttls_domain_label"));
+       gtk_widget_hide (widget);
+#endif
+
+       widget = inner_auth_combo_init (method, connection, s_8021x, secrets_only);
+       inner_auth_combo_changed_cb (widget, (gpointer) method);
+
+       if (secrets_only) {
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, 
"eap_ttls_anon_identity_label"));
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, 
"eap_ttls_anon_identity_entry"));
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_ttls_domain_label"));
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_ttls_domain_entry"));
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, 
"eap_ttls_ca_cert_not_required_checkbox"));
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_ttls_inner_auth_label"));
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_ttls_inner_auth_combo"));
+               gtk_widget_hide (widget);
+       }
+
+#if LIBNM_BUILD
+       nma_cert_chooser_setup_cert_password_storage (NMA_CERT_CHOOSER (method->ca_cert_chooser),
+                                                     0, (NMSetting *) s_8021x, 
NM_SETTING_802_1X_CA_CERT_PASSWORD,
+                                                     FALSE, secrets_only);
+#endif
+
+       return method;
+}
diff --git a/src/nma-ws/nma-eap-ttls.h b/src/nma-ws/nma-eap-ttls.h
new file mode 100644
index 00000000..034ad3e4
--- /dev/null
+++ b/src/nma-ws/nma-eap-ttls.h
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#ifndef NMA_EAP_TTLS_H
+#define NMA_EAP_TTLS_H
+
+#include "nma-ws.h"
+
+typedef struct _NMAEapTTLS NMAEapTTLS;
+
+NMAEapTTLS *nma_eap_ttls_new (NMAWs *ws_parent,
+                              NMConnection *connection,
+                              gboolean is_editor,
+                              gboolean secrets_only);
+
+#endif /* NMA_EAP_TLS_H */
diff --git a/src/nma-ws/nma-eap-ttls.ui b/src/nma-ws/nma-eap-ttls.ui
new file mode 100644
index 00000000..8cb2b56a
--- /dev/null
+++ b/src/nma-ws/nma-eap-ttls.ui
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface domain="nm-applet">
+  <requires lib="gtk+" version="3.10"/>
+  <object class="GtkListStore" id="model6">
+    <columns>
+      <!-- column-name gchararray -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0"> </col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkNotebook" id="eap_ttls_notebook">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="show_tabs">False</property>
+    <property name="show_border">False</property>
+    <child>
+      <object class="GtkGrid" id="eap_ttls_grid">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="row_spacing">6</property>
+        <property name="column_spacing">6</property>
+        <child>
+          <object class="GtkEntry" id="eap_ttls_anon_identity_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+            <property name="activates_default">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox" id="eap_ttls_inner_auth_vbox">
+            <property name="orientation">vertical</property>
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="spacing">6</property>
+            <child>
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">5</property>
+            <property name="width">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkComboBox" id="eap_ttls_inner_auth_combo">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="hexpand">True</property>
+            <property name="model">model6</property>
+            <child>
+              <object class="GtkCellRendererText" id="renderer6"/>
+              <attributes>
+                <attribute name="text">0</attribute>
+              </attributes>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">4</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="eap_ttls_inner_auth_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">_Inner authentication</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">eap_ttls_inner_auth_combo</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">4</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="eap_ttls_ca_cert_not_required_checkbox">
+            <property name="label" translatable="yes">No CA certificate is _required</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="halign">start</property>
+            <property name="hexpand">True</property>
+            <property name="use_underline">True</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">3</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="eap_ttls_domain_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+            <property name="activates_default">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="eap_ttls_anon_identity_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Anony_mous identity</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">eap_ttls_anon_identity_entry</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="eap_ttls_domain_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="tooltip_text" translatable="yes">Suffix of the server certificate 
name.</property>
+            <property name="label" translatable="yes">_Domain</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">eap_ttls_domain_entry</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+      </object>
+    </child>
+    <child type="tab">
+      <object class="GtkLabel" id="label49">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+      </object>
+      <packing>
+        <property name="tab_fill">False</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/src/nma-ws/nma-eap.c b/src/nma-ws/nma-eap.c
new file mode 100644
index 00000000..5fe3511f
--- /dev/null
+++ b/src/nma-ws/nma-eap.c
@@ -0,0 +1,431 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "nma-eap.h"
+#include "nm-utils.h"
+#include "utils.h"
+#include "helpers.h"
+
+G_DEFINE_BOXED_TYPE (NMAEap, nma_eap, nma_eap_ref, nma_eap_unref)
+
+GtkWidget *
+nma_eap_get_widget (NMAEap *method)
+{
+       g_return_val_if_fail (method != NULL, NULL);
+
+       return method->ui_widget;
+}
+
+gboolean
+nma_eap_validate (NMAEap *method, GError **error)
+{
+       gboolean result;
+
+       g_return_val_if_fail (method != NULL, FALSE);
+
+       g_assert (method->validate);
+       result = (*(method->validate)) (method, error);
+       if (!result && error && !*error)
+               g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("undefined error in 802.1X 
security (wpa-eap)"));
+       return result;
+}
+
+void
+nma_eap_add_to_size_group (NMAEap *method, GtkSizeGroup *group)
+{
+       g_return_if_fail (method != NULL);
+       g_return_if_fail (group != NULL);
+
+       g_assert (method->add_to_size_group);
+       return (*(method->add_to_size_group)) (method, group);
+}
+
+void
+nma_eap_fill_connection (NMAEap *method,
+                         NMConnection *connection)
+{
+       g_return_if_fail (method != NULL);
+       g_return_if_fail (connection != NULL);
+
+       g_assert (method->fill_connection);
+       return (*(method->fill_connection)) (method, connection);
+}
+
+void
+nma_eap_update_secrets (NMAEap *method, NMConnection *connection)
+{
+       g_return_if_fail (method != NULL);
+       g_return_if_fail (connection != NULL);
+
+       if (method->update_secrets)
+               method->update_secrets (method, connection);
+}
+
+void
+nma_eap_phase2_update_secrets_helper (NMAEap *method,
+                                      NMConnection *connection,
+                                      const char *combo_name,
+                                      guint32 column)
+{
+       GtkWidget *combo;
+       GtkTreeIter iter;
+       GtkTreeModel *model;
+
+       g_return_if_fail (method != NULL);
+       g_return_if_fail (connection != NULL);
+       g_return_if_fail (combo_name != NULL);
+
+       combo = GTK_WIDGET (gtk_builder_get_object (method->builder, combo_name));
+       g_assert (combo);
+
+       /* Let each EAP phase2 method try to update its secrets */
+       model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
+       if (gtk_tree_model_get_iter_first (model, &iter)) {
+               do {
+                       NMAEap *eap = NULL;
+
+                       gtk_tree_model_get (model, &iter, column, &eap, -1);
+                       if (eap) {
+                               nma_eap_update_secrets (eap, connection);
+                               nma_eap_unref (eap);
+                       }
+               } while (gtk_tree_model_iter_next (model, &iter));
+       }
+}
+
+NMAEap *
+nma_eap_init (gsize obj_size,
+              NMAEapValidateFunc validate,
+              NMAEapAddToSizeGroupFunc add_to_size_group,
+              NMAEapFillConnectionFunc fill_connection,
+              NMAEapUpdateSecretsFunc update_secrets,
+              NMAEapDestroyFunc destroy,
+              const char *ui_resource,
+              const char *ui_widget_name,
+              const char *default_field,
+              gboolean phase2)
+{
+       NMAEap *method;
+       GError *error = NULL;
+
+       g_return_val_if_fail (obj_size > 0, NULL);
+       g_return_val_if_fail (ui_resource != NULL, NULL);
+       g_return_val_if_fail (ui_widget_name != NULL, NULL);
+
+       method = g_slice_alloc0 (obj_size);
+       g_assert (method);
+
+       method->refcount = 1;
+       method->obj_size = obj_size;
+       method->validate = validate;
+       method->add_to_size_group = add_to_size_group;
+       method->fill_connection = fill_connection;
+       method->update_secrets = update_secrets;
+       method->default_field = default_field;
+       method->phase2 = phase2;
+
+       method->builder = gtk_builder_new ();
+       if (!gtk_builder_add_from_resource (method->builder, ui_resource, &error)) {
+               g_warning ("Couldn't load UI builder resource %s: %s",
+                          ui_resource, error->message);
+               nma_eap_unref (method);
+               return NULL;
+       }
+
+       method->ui_widget = GTK_WIDGET (gtk_builder_get_object (method->builder, ui_widget_name));
+       if (!method->ui_widget) {
+               g_warning ("Couldn't load UI widget '%s' from UI file %s",
+                          ui_widget_name, ui_resource);
+               nma_eap_unref (method);
+               return NULL;
+       }
+       g_object_ref_sink (method->ui_widget);
+
+       method->destroy = destroy;
+
+       return method;
+}
+
+
+NMAEap *
+nma_eap_ref (NMAEap *method)
+{
+       g_return_val_if_fail (method != NULL, NULL);
+       g_return_val_if_fail (method->refcount > 0, NULL);
+
+       method->refcount++;
+       return method;
+}
+
+void
+nma_eap_unref (NMAEap *method)
+{
+       g_return_if_fail (method != NULL);
+       g_return_if_fail (method->refcount > 0);
+
+       method->refcount--;
+       if (method->refcount == 0) {
+               if (method->destroy)
+                       method->destroy (method);
+
+               if (method->builder)
+                       g_object_unref (method->builder);
+               if (method->ui_widget)
+                       g_object_unref (method->ui_widget);
+
+               g_slice_free1 (method->obj_size, method);
+       }
+}
+
+/* Used as both GSettings keys and GObject data tags */
+#define IGNORE_CA_CERT_TAG "ignore-ca-cert"
+#define IGNORE_PHASE2_CA_CERT_TAG "ignore-phase2-ca-cert"
+
+/**
+ * nma_eap_ca_cert_ignore_set:
+ * @method: the #NMAEap object
+ * @connection: the #NMConnection
+ * @filename: the certificate file, if any
+ * @ca_cert_error: %TRUE if an error was encountered loading the given CA
+ * certificate, %FALSE if not or if a CA certificate is not present
+ *
+ * Updates the connection's CA cert ignore value to %TRUE if the "CA certificate
+ * not required" checkbox is checked.  If @ca_cert_error is %TRUE, then the
+ * connection's CA cert ignore value will always be set to %FALSE, because it
+ * means that the user selected an invalid certificate (thus he does not want to
+ * ignore the CA cert)..
+ */
+void
+nma_eap_ca_cert_ignore_set (NMAEap *method,
+                            NMConnection *connection,
+                            const char *filename,
+                            gboolean ca_cert_error)
+{
+       NMSetting8021x *s_8021x;
+       gboolean ignore;
+
+       s_8021x = nm_connection_get_setting_802_1x (connection);
+       if (s_8021x) {
+               ignore = !ca_cert_error && filename == NULL;
+               g_object_set_data (G_OBJECT (s_8021x),
+                                  method->phase2 ? IGNORE_PHASE2_CA_CERT_TAG : IGNORE_CA_CERT_TAG,
+                                  GUINT_TO_POINTER (ignore));
+       }
+}
+
+/**
+ * nma_eap_ca_cert_ignore_get:
+ * @method: the #NMAEap object
+ * @connection: the #NMConnection
+ *
+ * Returns: %TRUE if a missing CA certificate can be ignored, %FALSE if a CA
+ * certificate should be required for the connection to be valid.
+ */
+gboolean
+nma_eap_ca_cert_ignore_get (NMAEap *method, NMConnection *connection)
+{
+       NMSetting8021x *s_8021x;
+
+       s_8021x = nm_connection_get_setting_802_1x (connection);
+       if (s_8021x) {
+               return !!g_object_get_data (G_OBJECT (s_8021x),
+                                           method->phase2 ? IGNORE_PHASE2_CA_CERT_TAG : IGNORE_CA_CERT_TAG);
+       }
+       return FALSE;
+}
+
+static GSettings *
+_get_ca_ignore_settings (NMConnection *connection)
+{
+       GSettings *settings;
+       char *path = NULL;
+       const char *uuid;
+
+       g_return_val_if_fail (connection, NULL);
+
+       uuid = nm_connection_get_uuid (connection);
+       g_return_val_if_fail (uuid && *uuid, NULL);
+
+       path = g_strdup_printf ("/org/gnome/nm-applet/eap/%s/", uuid);
+       settings = g_settings_new_with_path ("org.gnome.nm-applet.eap", path);
+       g_free (path);
+
+       return settings;
+}
+
+/**
+ * nma_eap_ca_cert_ignore_save:
+ * @connection: the connection for which to save CA cert ignore values to GSettings
+ *
+ * Reads the CA cert ignore tags from the 802.1x setting GObject data and saves
+ * then to GSettings if present, using the connection UUID as the index.
+ */
+void
+nma_eap_ca_cert_ignore_save (NMConnection *connection)
+{
+       NMSetting8021x *s_8021x;
+       GSettings *settings;
+       gboolean ignore = FALSE, phase2_ignore = FALSE;
+
+       g_return_if_fail (connection);
+
+       s_8021x = nm_connection_get_setting_802_1x (connection);
+       if (s_8021x) {
+               ignore = !!g_object_get_data (G_OBJECT (s_8021x), IGNORE_CA_CERT_TAG);
+               phase2_ignore = !!g_object_get_data (G_OBJECT (s_8021x), IGNORE_PHASE2_CA_CERT_TAG);
+       }
+
+       settings = _get_ca_ignore_settings (connection);
+       if (!settings)
+               return;
+
+       g_settings_set_boolean (settings, IGNORE_CA_CERT_TAG, ignore);
+       g_settings_set_boolean (settings, IGNORE_PHASE2_CA_CERT_TAG, phase2_ignore);
+       g_object_unref (settings);
+}
+
+/**
+ * nma_eap_ca_cert_ignore_load:
+ * @connection: the connection for which to load CA cert ignore values to GSettings
+ *
+ * Reads the CA cert ignore tags from the 802.1x setting GObject data and saves
+ * then to GSettings if present, using the connection UUID as the index.
+ */
+void
+nma_eap_ca_cert_ignore_load (NMConnection *connection)
+{
+       GSettings *settings;
+       NMSetting8021x *s_8021x;
+       gboolean ignore, phase2_ignore;
+
+       g_return_if_fail (connection);
+
+       s_8021x = nm_connection_get_setting_802_1x (connection);
+       if (!s_8021x)
+               return;
+
+       settings = _get_ca_ignore_settings (connection);
+       if (!settings)
+               return;
+
+       ignore = g_settings_get_boolean (settings, IGNORE_CA_CERT_TAG);
+       phase2_ignore = g_settings_get_boolean (settings, IGNORE_PHASE2_CA_CERT_TAG);
+
+       g_object_set_data (G_OBJECT (s_8021x),
+                          IGNORE_CA_CERT_TAG,
+                          GUINT_TO_POINTER (ignore));
+       g_object_set_data (G_OBJECT (s_8021x),
+                          IGNORE_PHASE2_CA_CERT_TAG,
+                          GUINT_TO_POINTER (phase2_ignore));
+       g_object_unref (settings);
+}
+
+GError *
+nma_eap_ca_cert_validate_cb (NMACertChooser *cert_chooser, gpointer user_data)
+{
+       NMSetting8021xCKScheme scheme;
+        NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+       gs_unref_object NMSetting8021x *setting = NULL;
+       gs_free char *value = NULL;
+       GError *local = NULL;
+
+       setting = (NMSetting8021x *) nm_setting_802_1x_new ();
+
+       value = nma_cert_chooser_get_cert (cert_chooser, &scheme);
+       if (!value) {
+               return g_error_new_literal (NMA_ERROR, NMA_ERROR_GENERIC,
+                                           _("no CA certificate selected"));
+       }
+       if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) {
+               if (!g_file_test (value, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
+                       return g_error_new_literal (NMA_ERROR, NMA_ERROR_GENERIC,
+                                                   _("selected CA certificate file does not exist"));
+               }
+       }
+
+       if (!nm_setting_802_1x_set_ca_cert (setting, value, scheme, &format, &local))
+               return local;
+
+       return NULL;
+}
+
+void
+nma_eap_setup_cert_chooser (NMACertChooser *cert_chooser,
+                            NMSetting8021x *s_8021x,
+                            NMSetting8021xCKScheme (*cert_scheme_func) (NMSetting8021x *setting),
+                            const char *(*cert_path_func) (NMSetting8021x *setting),
+                            const char *(*cert_uri_func) (NMSetting8021x *setting),
+                            const char *(*cert_password_func) (NMSetting8021x *setting),
+                            NMSetting8021xCKScheme (*key_scheme_func) (NMSetting8021x *setting),
+                            const char *(*key_path_func) (NMSetting8021x *setting),
+                            const char *(*key_uri_func) (NMSetting8021x *setting),
+                            const char *(*key_password_func) (NMSetting8021x *setting))
+{
+       NMSetting8021xCKScheme scheme = NM_SETTING_802_1X_CK_SCHEME_UNKNOWN;
+       const char *value = NULL;
+       const char *password = NULL;
+
+
+       if (s_8021x && cert_path_func && cert_uri_func && cert_scheme_func) {
+               scheme = cert_scheme_func (s_8021x);
+               switch (scheme) {
+               case NM_SETTING_802_1X_CK_SCHEME_PATH:
+                       value = cert_path_func (s_8021x);
+                       break;
+#if LIBNM_BUILD
+/* Not available in libnm-glib */
+               case NM_SETTING_802_1X_CK_SCHEME_PKCS11:
+                       value = cert_uri_func (s_8021x);
+                       password = cert_password_func ? cert_password_func (s_8021x) : NULL;
+                       if (password)
+                               nma_cert_chooser_set_cert_password (cert_chooser, password);
+                       break;
+#endif
+               case NM_SETTING_802_1X_CK_SCHEME_UNKNOWN:
+                       /* No CA set. */
+                       break;
+               default:
+                       g_warning ("unhandled certificate scheme %d", scheme);
+               }
+
+       }
+       nma_cert_chooser_set_cert (cert_chooser, value, scheme);
+
+       if (s_8021x && key_path_func && key_uri_func && key_scheme_func) {
+               scheme = key_scheme_func (s_8021x);
+               switch (scheme) {
+               case NM_SETTING_802_1X_CK_SCHEME_PATH:
+                       value = key_path_func (s_8021x);
+                       break;
+#if LIBNM_BUILD
+/* Not available in libnm-glib */
+               case NM_SETTING_802_1X_CK_SCHEME_PKCS11:
+                       value = key_uri_func (s_8021x);
+                       break;
+#endif
+               case NM_SETTING_802_1X_CK_SCHEME_UNKNOWN:
+                       /* No certificate set. */
+                       break;
+               default:
+                       g_warning ("unhandled key scheme %d", scheme);
+               }
+
+               nma_cert_chooser_set_key (cert_chooser, value, scheme);
+       }
+
+       password = s_8021x && key_password_func ? key_password_func (s_8021x) : NULL;
+       if (password)
+               nma_cert_chooser_set_key_password (cert_chooser, key_password_func (s_8021x));
+}
diff --git a/src/nma-ws/nma-eap.h b/src/nma-ws/nma-eap.h
new file mode 100644
index 00000000..95d1b94a
--- /dev/null
+++ b/src/nma-ws/nma-eap.h
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#ifndef NMA_EAP_H
+#define NMA_EAP_H
+
+typedef struct _NMAEap NMAEap;
+
+typedef void        (*NMAEapAddToSizeGroupFunc) (NMAEap *method, GtkSizeGroup *group);
+typedef void        (*NMAEapFillConnectionFunc) (NMAEap *method, NMConnection *connection);
+typedef void        (*NMAEapUpdateSecretsFunc)  (NMAEap *method, NMConnection *connection);
+typedef void        (*NMAEapDestroyFunc)        (NMAEap *method);
+typedef gboolean    (*NMAEapValidateFunc)       (NMAEap *method, GError **error);
+
+struct _NMAEap {
+       guint32 refcount;
+       gsize obj_size;
+
+       GtkBuilder *builder;
+       GtkWidget *ui_widget;
+
+       const char *default_field;
+
+       gboolean phase2;
+       gboolean secrets_only;
+
+       NMAEapAddToSizeGroupFunc add_to_size_group;
+       NMAEapFillConnectionFunc fill_connection;
+       NMAEapUpdateSecretsFunc update_secrets;
+       NMAEapValidateFunc validate;
+       NMAEapDestroyFunc destroy;
+};
+
+#define NMA_EAP(x) ((NMAEap *) x)
+
+
+GtkWidget *nma_eap_get_widget (NMAEap *method);
+
+gboolean nma_eap_validate (NMAEap *method, GError **error);
+
+void nma_eap_add_to_size_group (NMAEap *method, GtkSizeGroup *group);
+
+void nma_eap_fill_connection (NMAEap *method,
+                              NMConnection *connection);
+
+void nma_eap_update_secrets (NMAEap *method, NMConnection *connection);
+
+NMAEap *nma_eap_ref (NMAEap *method);
+
+void nma_eap_unref (NMAEap *method);
+
+GType nma_eap_get_type (void);
+
+/* Below for internal use only */
+
+#include "nma-cert-chooser.h"
+#include "nma-eap-tls.h"
+#include "nma-eap-leap.h"
+#include "nma-eap-fast.h"
+#include "nma-eap-ttls.h"
+#include "nma-eap-peap.h"
+#include "nma-eap-simple.h"
+
+NMAEap *nma_eap_init (gsize obj_size,
+                      NMAEapValidateFunc validate,
+                      NMAEapAddToSizeGroupFunc add_to_size_group,
+                      NMAEapFillConnectionFunc fill_connection,
+                      NMAEapUpdateSecretsFunc update_secrets,
+                      NMAEapDestroyFunc destroy,
+                      const char *ui_resource,
+                      const char *ui_widget_name,
+                      const char *default_field,
+                      gboolean phase2);
+
+void nma_eap_phase2_update_secrets_helper (NMAEap *method,
+                                           NMConnection *connection,
+                                           const char *combo_name,
+                                           guint32 column);
+
+void nma_eap_ca_cert_ignore_set (NMAEap *method,
+                                 NMConnection *connection,
+                                 const char *filename,
+                                 gboolean ca_cert_error);
+gboolean nma_eap_ca_cert_ignore_get (NMAEap *method, NMConnection *connection);
+
+void nma_eap_ca_cert_ignore_save (NMConnection *connection);
+void nma_eap_ca_cert_ignore_load (NMConnection *connection);
+
+GError *nma_eap_ca_cert_validate_cb (NMACertChooser *cert_chooser, gpointer user_data);
+
+#if !LIBNM_BUILD
+/* For mere convenience. These are not available in libnm-glib. */
+#define nm_setting_802_1x_get_ca_cert_password             NULL
+#define nm_setting_802_1x_get_ca_cert_uri                  NULL
+#define nm_setting_802_1x_get_client_cert_password         NULL
+#define nm_setting_802_1x_get_client_cert_uri              NULL
+#define nm_setting_802_1x_get_private_key_uri              NULL
+#define nm_setting_802_1x_get_phase2_ca_cert_password      NULL
+#define nm_setting_802_1x_get_phase2_ca_cert_uri           NULL
+#define nm_setting_802_1x_get_phase2_client_cert_password  NULL
+#define nm_setting_802_1x_get_phase2_client_cert_uri       NULL
+#define nm_setting_802_1x_get_phase2_private_key_uri       NULL
+#endif
+
+void nma_eap_setup_cert_chooser (NMACertChooser *cert_chooser,
+                                 NMSetting8021x *s_8021x,
+                                 NMSetting8021xCKScheme (*cert_scheme_func) (NMSetting8021x *setting),
+                                 const char *(*cert_path_func) (NMSetting8021x *setting),
+                                 const char *(*cert_uri_func) (NMSetting8021x *setting),
+                                 const char *(*cert_password_func) (NMSetting8021x *setting),
+                                 NMSetting8021xCKScheme (*key_scheme_func) (NMSetting8021x *setting),
+                                 const char *(*key_path_func) (NMSetting8021x *setting),
+                                 const char *(*key_uri_func) (NMSetting8021x *setting),
+                                 const char *(*key_password_func) (NMSetting8021x *setting));
+
+#endif /* NMA_EAP_H */
diff --git a/src/nma-ws/nma-ws-dynamic-wep.c b/src/nma-ws/nma-ws-dynamic-wep.c
new file mode 100644
index 00000000..95f27b53
--- /dev/null
+++ b/src/nma-ws/nma-ws-dynamic-wep.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+
+#include <ctype.h>
+#include <string.h>
+
+#include "nma-ws.h"
+#include "nma-eap.h"
+
+struct _NMAWsDynamicWEP {
+       NMAWs parent;
+
+       GtkSizeGroup *size_group;
+};
+
+static void
+destroy (NMAWs *parent)
+{
+       NMAWsDynamicWEP *sec = (NMAWsDynamicWEP *) parent;
+
+       if (sec->size_group)
+               g_object_unref (sec->size_group);
+}
+
+static gboolean
+validate (NMAWs *parent, GError **error)
+{
+       return nma_ws_802_1x_validate (parent, "dynamic_wep_auth_combo", error);
+}
+
+static void
+add_to_size_group (NMAWs *parent, GtkSizeGroup *group)
+{
+       NMAWsDynamicWEP *sec = (NMAWsDynamicWEP *) parent;
+
+       if (sec->size_group)
+               g_object_unref (sec->size_group);
+       sec->size_group = g_object_ref (group);
+
+       nma_ws_802_1x_add_to_size_group (parent,
+                                        sec->size_group,
+                                        "dynamic_wep_auth_label",
+                                        "dynamic_wep_auth_combo");
+}
+
+static void
+fill_connection (NMAWs *parent, NMConnection *connection)
+{
+       NMSettingWirelessSecurity *s_wireless_sec;
+
+       nma_ws_802_1x_fill_connection (parent, "dynamic_wep_auth_combo", connection);
+
+       s_wireless_sec = nm_connection_get_setting_wireless_security (connection);
+       g_assert (s_wireless_sec);
+
+       g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", NULL);
+}
+
+static void
+auth_combo_changed_cb (GtkWidget *combo, gpointer user_data)
+{
+       NMAWs *parent = NMA_WS (user_data);
+       NMAWsDynamicWEP *sec = (NMAWsDynamicWEP *) parent;
+
+       nma_ws_802_1x_auth_combo_changed (combo,
+                                         parent,
+                                         "dynamic_wep_method_vbox",
+                                         sec->size_group);
+}
+
+static void
+update_secrets (NMAWs *parent, NMConnection *connection)
+{
+       nma_ws_802_1x_update_secrets (parent, "dynamic_wep_auth_combo", connection);
+}
+
+NMAWsDynamicWEP *
+nma_ws_dynamic_wep_new (NMConnection *connection,
+                        gboolean is_editor,
+                        gboolean secrets_only)
+{
+       NMAWs *parent;
+       GtkWidget *widget;
+
+       parent = nma_ws_init (sizeof (NMAWsDynamicWEP),
+                             validate,
+                             add_to_size_group,
+                             fill_connection,
+                             update_secrets,
+                             destroy,
+                             "/org/gnome/libnma/nma-ws-dynamic-wep.ui",
+                             "dynamic_wep_notebook",
+                             NULL);
+       if (!parent)
+               return NULL;
+
+       parent->adhoc_compatible = FALSE;
+       parent->hotspot_compatible = FALSE;
+
+       widget = nma_ws_802_1x_auth_combo_init (parent,
+                                               "dynamic_wep_auth_combo",
+                                               "dynamic_wep_auth_label",
+                                               (GCallback) auth_combo_changed_cb,
+                                               connection,
+                                               is_editor,
+                                               secrets_only,
+                                               NULL);
+       auth_combo_changed_cb (widget, (gpointer) parent);
+
+       return (NMAWsDynamicWEP *) parent;
+}
diff --git a/src/nma-ws/nma-ws-dynamic-wep.h b/src/nma-ws/nma-ws-dynamic-wep.h
new file mode 100644
index 00000000..1dfc3f8c
--- /dev/null
+++ b/src/nma-ws/nma-ws-dynamic-wep.h
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#ifndef WS_DYNAMIC_WEP_H
+#define WS_DYNAMIC_WEP_H
+
+typedef struct _NMAWsDynamicWEP NMAWsDynamicWEP;
+
+NMAWsDynamicWEP *nma_ws_dynamic_wep_new (NMConnection *connection,
+                                         gboolean is_editor,
+                                         gboolean secrets_only);
+
+#endif /* WS_DYNAMIC_WEP_H */
diff --git a/src/nma-ws/nma-ws-dynamic-wep.ui b/src/nma-ws/nma-ws-dynamic-wep.ui
new file mode 100644
index 00000000..a538f107
--- /dev/null
+++ b/src/nma-ws/nma-ws-dynamic-wep.ui
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface domain="nm-applet">
+  <requires lib="gtk+" version="3.10"/>
+  <object class="GtkListStore" id="model7">
+    <columns>
+      <!-- column-name gchararray -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0"> </col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkNotebook" id="dynamic_wep_notebook">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="show_tabs">False</property>
+    <property name="show_border">False</property>
+    <child>
+      <object class="GtkGrid" id="table12">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="row_spacing">6</property>
+        <property name="column_spacing">6</property>
+        <child>
+          <object class="GtkLabel" id="dynamic_wep_auth_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Au_thentication</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">dynamic_wep_auth_combo</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkComboBox" id="dynamic_wep_auth_combo">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="hexpand">True</property>
+            <property name="model">model7</property>
+            <child>
+              <object class="GtkCellRendererText" id="renderer7"/>
+              <attributes>
+                <attribute name="text">0</attribute>
+              </attributes>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox" id="dynamic_wep_method_vbox">
+            <property name="orientation">vertical</property>
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="spacing">6</property>
+            <child>
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">1</property>
+            <property name="width">2</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <child type="tab">
+      <object class="GtkLabel" id="label55">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+      </object>
+      <packing>
+        <property name="tab_fill">False</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/src/nma-ws/nma-ws-leap.c b/src/nma-ws/nma-ws-leap.c
new file mode 100644
index 00000000..6c0814e2
--- /dev/null
+++ b/src/nma-ws/nma-ws-leap.c
@@ -0,0 +1,205 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+#include "nma-private.h"
+
+#include <string.h>
+
+#include "nma-ws.h"
+#include "helpers.h"
+#include "nma-ui-utils.h"
+#include "utils.h"
+
+struct _NMAWsLEAP {
+       NMAWs parent;
+       gboolean editing_connection;
+       const char *password_flags_name;
+};
+
+static void
+show_toggled_cb (GtkCheckButton *button, NMAWs *sec)
+{
+       GtkWidget *widget;
+       gboolean visible;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (sec->builder, "leap_password_entry"));
+       g_assert (widget);
+
+       visible = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+       gtk_entry_set_visibility (GTK_ENTRY (widget), visible);
+}
+
+static gboolean
+validate (NMAWs *parent, GError **error)
+{
+       GtkWidget *entry;
+       NMSettingSecretFlags secret_flags;
+       const char *text;
+       gboolean ret = TRUE;
+
+       entry = GTK_WIDGET (gtk_builder_get_object (parent->builder, "leap_username_entry"));
+       g_assert (entry);
+       text = gtk_editable_get_text (GTK_EDITABLE (entry));
+       if (!text || !strlen (text)) {
+               widget_set_error (entry);
+               g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("missing leap-username"));
+               ret = FALSE;
+       } else
+               widget_unset_error (entry);
+
+       entry = GTK_WIDGET (gtk_builder_get_object (parent->builder, "leap_password_entry"));
+       g_assert (entry);
+
+       secret_flags = nma_utils_menu_to_secret_flags (entry);
+       text = gtk_editable_get_text (GTK_EDITABLE (entry));
+
+       if (   secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED
+           || secret_flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED
+           || (text && strlen (text))) {
+               widget_unset_error (entry);
+       } else {
+               widget_set_error (entry);
+               if (ret) {
+                       g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("missing leap-password"));
+                       ret = FALSE;
+               }
+       }
+
+       return ret;
+}
+
+static void
+add_to_size_group (NMAWs *parent, GtkSizeGroup *group)
+{
+       GtkWidget *widget;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "leap_username_label"));
+       gtk_size_group_add_widget (group, widget);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "leap_password_label"));
+       gtk_size_group_add_widget (group, widget);
+}
+
+static void
+fill_connection (NMAWs *parent, NMConnection *connection)
+{
+       NMAWsLEAP *sec = (NMAWsLEAP *) parent;
+       NMSettingWirelessSecurity *s_wireless_sec;
+       NMSettingSecretFlags secret_flags;
+       GtkWidget *widget, *passwd_entry;
+       const char *leap_password = NULL, *leap_username = NULL;
+
+       /* Blow away the old security setting by adding a clear one */
+       s_wireless_sec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+       nm_connection_add_setting (connection, (NMSetting *) s_wireless_sec);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "leap_username_entry"));
+       leap_username = gtk_editable_get_text (GTK_EDITABLE (widget));
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "leap_password_entry"));
+       passwd_entry = widget;
+       leap_password = gtk_editable_get_text (GTK_EDITABLE (widget));
+
+       g_object_set (s_wireless_sec,
+                     NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x",
+                     NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap",
+                     NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, leap_username,
+                     NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD, leap_password,
+                     NULL);
+
+       /* Save LEAP_PASSWORD_FLAGS to the connection */
+       secret_flags = nma_utils_menu_to_secret_flags (passwd_entry);
+       nm_setting_set_secret_flags (NM_SETTING (s_wireless_sec), sec->password_flags_name,
+                                    secret_flags, NULL);
+
+       /* Update secret flags and popup when editing the connection */
+       if (sec->editing_connection)
+               nma_utils_update_password_storage (passwd_entry, secret_flags,
+                                                  NM_SETTING (s_wireless_sec), sec->password_flags_name);
+}
+
+static void
+update_secrets (NMAWs *parent, NMConnection *connection)
+{
+       helper_fill_secret_entry (connection,
+                                 parent->builder,
+                                 "leap_password_entry",
+                                 NM_TYPE_SETTING_WIRELESS_SECURITY,
+                                 (HelperSecretFunc) nm_setting_wireless_security_get_leap_password);
+}
+
+NMAWsLEAP *
+nma_ws_leap_new (NMConnection *connection, gboolean secrets_only)
+{
+       NMAWs *parent;
+       NMAWsLEAP *sec;
+       GtkWidget *widget;
+       NMSettingWirelessSecurity *wsec = NULL;
+
+       parent = nma_ws_init (sizeof (NMAWsLEAP),
+                             validate,
+                             add_to_size_group,
+                             fill_connection,
+                             update_secrets,
+                             NULL,
+                             "/org/gnome/libnma/nma-ws-leap.ui",
+                             "leap_notebook",
+                             "leap_username_entry");
+       if (!parent)
+               return NULL;
+
+       if (connection) {
+               wsec = nm_connection_get_setting_wireless_security (connection);
+               if (wsec) {
+                       const char *auth_alg;
+
+                       /* Ignore if wireless security doesn't specify LEAP */
+                       auth_alg = nm_setting_wireless_security_get_auth_alg (wsec);
+                       if (!auth_alg || strcmp (auth_alg, "leap"))
+                               wsec = NULL;
+               }
+       }
+
+       parent->adhoc_compatible = FALSE;
+       parent->hotspot_compatible = FALSE;
+       sec = (NMAWsLEAP *) parent;
+       sec->editing_connection = secrets_only ? FALSE : TRUE;
+       sec->password_flags_name = NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "leap_password_entry"));
+       g_assert (widget);
+       g_signal_connect (G_OBJECT (widget), "changed",
+                         (GCallback) nma_ws_changed_cb,
+                         sec);
+
+       /* Create password-storage popup menu for password entry under entry's secondary icon */
+       nma_utils_setup_password_storage (widget, 0, (NMSetting *) wsec, sec->password_flags_name,
+                                         FALSE, secrets_only);
+
+       if (wsec)
+               update_secrets (NMA_WS (sec), connection);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "leap_username_entry"));
+       g_assert (widget);
+       g_signal_connect (G_OBJECT (widget), "changed",
+                         (GCallback) nma_ws_changed_cb,
+                         sec);
+       if (wsec)
+               gtk_editable_set_text (GTK_EDITABLE (widget), nm_setting_wireless_security_get_leap_username 
(wsec));
+
+       if (secrets_only)
+               gtk_widget_hide (widget);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "show_checkbutton_leap"));
+       g_assert (widget);
+       g_signal_connect (G_OBJECT (widget), "toggled",
+                         (GCallback) show_toggled_cb,
+                         sec);
+
+       return sec;
+}
diff --git a/src/nma-ws/nma-ws-leap.h b/src/nma-ws/nma-ws-leap.h
new file mode 100644
index 00000000..29f12602
--- /dev/null
+++ b/src/nma-ws/nma-ws-leap.h
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#ifndef WS_LEAP_H
+#define WS_LEAP_H
+
+typedef struct _NMAWsLEAP NMAWsLEAP;
+
+NMAWsLEAP *nma_ws_leap_new (NMConnection *connection, gboolean secrets_only);
+
+#endif /* WS_LEAP_H */
diff --git a/src/nma-ws/nma-ws-leap.ui b/src/nma-ws/nma-ws-leap.ui
new file mode 100644
index 00000000..a93121d6
--- /dev/null
+++ b/src/nma-ws/nma-ws-leap.ui
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface domain="nm-applet">
+  <requires lib="gtk+" version="3.10"/>
+  <object class="GtkNotebook" id="leap_notebook">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="show_tabs">False</property>
+    <property name="show_border">False</property>
+    <child>
+      <object class="GtkGrid" id="table5">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="valign">start</property>
+        <property name="row_spacing">6</property>
+        <property name="column_spacing">6</property>
+        <child>
+          <object class="GtkLabel" id="leap_username_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">_Username</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">leap_username_entry</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="leap_password_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">_Password</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">leap_password_entry</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="leap_password_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+            <property name="visibility">False</property>
+            <property name="activates_default">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="show_checkbutton_leap">
+            <property name="label" translatable="yes">Sho_w password</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="hexpand">True</property>
+            <property name="use_underline">True</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="leap_username_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+            <property name="activates_default">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+      </object>
+    </child>
+    <child type="tab">
+      <object class="GtkLabel" id="GtkLabel1">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+      </object>
+      <packing>
+        <property name="tab_fill">False</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/src/nma-ws/nma-ws-sae.c b/src/nma-ws/nma-ws-sae.c
new file mode 100644
index 00000000..3ac2b95b
--- /dev/null
+++ b/src/nma-ws/nma-ws-sae.c
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+#include "nma-private.h"
+
+#include <ctype.h>
+#include <string.h>
+
+#include "nma-ws.h"
+#include "helpers.h"
+#include "nma-ui-utils.h"
+#include "utils.h"
+
+#define WPA_PMK_LEN 32
+
+struct _NMAWsSAE {
+       NMAWs parent;
+
+       gboolean editing_connection;
+       const char *password_flags_name;
+};
+
+static void
+show_toggled_cb (GtkCheckButton *button, NMAWs *sec)
+{
+       GtkWidget *widget;
+       gboolean visible;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (sec->builder, "psk_entry"));
+       g_assert (widget);
+
+       visible = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+       gtk_entry_set_visibility (GTK_ENTRY (widget), visible);
+}
+
+static gboolean
+validate (NMAWs *parent, GError **error)
+{
+       GtkWidget *entry;
+       NMSettingSecretFlags secret_flags;
+       const char *key;
+
+       entry = GTK_WIDGET (gtk_builder_get_object (parent->builder, "psk_entry"));
+       g_assert (entry);
+
+       secret_flags = nma_utils_menu_to_secret_flags (entry);
+       key = gtk_editable_get_text (GTK_EDITABLE (entry));
+
+        if (   secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED
+            || secret_flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED) {
+               /* All good. */
+       } else if (key == NULL || key[0] == '\0') {
+               widget_set_error (entry);
+               g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("missing password"));
+               return FALSE;
+       }
+       widget_unset_error (entry);
+
+       return TRUE;
+}
+
+static void
+add_to_size_group (NMAWs *parent, GtkSizeGroup *group)
+{
+       GtkWidget *widget;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "sae_type_label"));
+       gtk_size_group_add_widget (group, widget);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "sae_label"));
+       gtk_size_group_add_widget (group, widget);
+}
+
+static void
+fill_connection (NMAWs *parent, NMConnection *connection)
+{
+       NMAWsSAE *sae = (NMAWsSAE *) parent;
+       GtkWidget *widget, *passwd_entry;
+       const char *key;
+       NMSettingWireless *s_wireless;
+       NMSettingWirelessSecurity *s_wireless_sec;
+       NMSettingSecretFlags secret_flags;
+       const char *mode;
+       gboolean is_adhoc = FALSE;
+
+       s_wireless = nm_connection_get_setting_wireless (connection);
+       g_assert (s_wireless);
+
+       mode = nm_setting_wireless_get_mode (s_wireless);
+       if (mode && !strcmp (mode, "adhoc"))
+               is_adhoc = TRUE;
+
+       /* Blow away the old security setting by adding a clear one */
+       s_wireless_sec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+       nm_connection_add_setting (connection, (NMSetting *) s_wireless_sec);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "psk_entry"));
+       passwd_entry = widget;
+       key = gtk_editable_get_text (GTK_EDITABLE (widget));
+       g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_PSK, key, NULL);
+
+       /* Save PSK_FLAGS to the connection */
+       secret_flags = nma_utils_menu_to_secret_flags (passwd_entry);
+       nm_setting_set_secret_flags (NM_SETTING (s_wireless_sec), NM_SETTING_WIRELESS_SECURITY_PSK,
+                                    secret_flags, NULL);
+
+       /* Update secret flags and popup when editing the connection */
+       if (sae->editing_connection)
+               nma_utils_update_password_storage (passwd_entry, secret_flags,
+                                                  NM_SETTING (s_wireless_sec), sae->password_flags_name);
+
+       nma_ws_clear_ciphers (connection);
+       if (is_adhoc) {
+               /* Ad-Hoc settings as specified by the supplicant */
+               g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "sae", NULL);
+               nm_setting_wireless_security_add_proto (s_wireless_sec, "rsn");
+               nm_setting_wireless_security_add_pairwise (s_wireless_sec, "ccmp");
+               nm_setting_wireless_security_add_group (s_wireless_sec, "ccmp");
+       } else {
+               g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "sae", NULL);
+
+               /* Just leave ciphers and protocol empty, the supplicant will
+                * figure that out magically based on the AP IEs and card capabilities.
+                */
+       }
+}
+
+static void
+update_secrets (NMAWs *parent, NMConnection *connection)
+{
+       helper_fill_secret_entry (connection,
+                                 parent->builder,
+                                 "psk_entry",
+                                 NM_TYPE_SETTING_WIRELESS_SECURITY,
+                                 (HelperSecretFunc) nm_setting_wireless_security_get_psk);
+}
+
+NMAWsSAE *
+nma_ws_sae_new (NMConnection *connection, gboolean secrets_only)
+{
+       NMAWs *parent;
+       NMAWsSAE *sec;
+       NMSetting *setting = NULL;
+       GtkWidget *widget;
+
+       parent = nma_ws_init (sizeof (NMAWsSAE),
+                             validate,
+                             add_to_size_group,
+                             fill_connection,
+                             update_secrets,
+                             NULL,
+                             "/org/gnome/libnma/nma-ws-sae.ui",
+                             "sae_notebook",
+                             "psk_entry");
+       if (!parent)
+               return NULL;
+
+       parent->adhoc_compatible = TRUE;
+       sec = (NMAWsSAE *) parent;
+       sec->editing_connection = secrets_only ? FALSE : TRUE;
+       sec->password_flags_name = NM_SETTING_WIRELESS_SECURITY_PSK;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "psk_entry"));
+       g_assert (widget);
+       g_signal_connect (G_OBJECT (widget), "changed",
+                         (GCallback) nma_ws_changed_cb,
+                         sec);
+       gtk_editable_set_width_chars (GTK_EDITABLE (widget), 28);
+
+       /* Create password-storage popup menu for password entry under entry's secondary icon */
+       if (connection)
+               setting = (NMSetting *) nm_connection_get_setting_wireless_security (connection);
+       nma_utils_setup_password_storage (widget, 0, setting, sec->password_flags_name,
+                                         FALSE, secrets_only);
+
+       /* Fill secrets, if any */
+       if (connection)
+               update_secrets (NMA_WS (sec), connection);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "show_checkbutton_sae"));
+       g_assert (widget);
+       g_signal_connect (G_OBJECT (widget), "toggled",
+                         (GCallback) show_toggled_cb,
+                         sec);
+
+       /* Hide WPA/RSN for now since this can be autodetected by NM and the
+        * supplicant when connecting to the AP.
+        */
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "sae_type_combo"));
+       g_assert (widget);
+       gtk_widget_hide (widget);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "sae_type_label"));
+       g_assert (widget);
+       gtk_widget_hide (widget);
+
+       return sec;
+}
diff --git a/src/nma-ws/nma-ws-sae.h b/src/nma-ws/nma-ws-sae.h
new file mode 100644
index 00000000..05e0de88
--- /dev/null
+++ b/src/nma-ws/nma-ws-sae.h
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#ifndef WS_SAE_H
+#define WS_SAE_H
+
+/* For compatibility with NetworkManager-1.20 and earlier. */
+#define NMU_SEC_SAE 9
+
+typedef struct _NMAWsSAE NMAWsSAE;
+
+NMAWsSAE *nma_ws_sae_new (NMConnection *connection, gboolean secrets_only);
+
+#endif /* WS_SAE_H */
diff --git a/src/nma-ws/nma-ws-sae.ui b/src/nma-ws/nma-ws-sae.ui
new file mode 100644
index 00000000..8f0d0413
--- /dev/null
+++ b/src/nma-ws/nma-ws-sae.ui
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface domain="nm-applet">
+  <requires lib="gtk+" version="3.10"/>
+  <object class="GtkNotebook" id="sae_notebook">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="show_tabs">False</property>
+    <property name="show_border">False</property>
+    <child>
+      <object class="GtkGrid" id="sae_table">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="row_spacing">6</property>
+        <property name="column_spacing">6</property>
+        <child>
+          <object class="GtkLabel" id="sae_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">_Password</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">psk_entry</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="psk_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+            <property name="max_length">64</property>
+            <property name="visibility">False</property>
+            <property name="activates_default">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="sae_type_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">_Type</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">sae_type_combo</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="show_checkbutton_sae">
+            <property name="label" translatable="yes">Sho_w password</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="hexpand">True</property>
+            <property name="use_underline">True</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkComboBox" id="sae_type_combo">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+      </object>
+    </child>
+    <child type="tab">
+      <object class="GtkLabel" id="GtkLabel2">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+      </object>
+      <packing>
+        <property name="tab_fill">False</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/src/nma-ws/nma-ws-wep-key.c b/src/nma-ws/nma-ws-wep-key.c
new file mode 100644
index 00000000..221bf8da
--- /dev/null
+++ b/src/nma-ws/nma-ws-wep-key.c
@@ -0,0 +1,353 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+#include "nma-private.h"
+
+#include <string.h>
+
+#include "nma-ws.h"
+#include "utils.h"
+#include "helpers.h"
+#include "nma-ui-utils.h"
+
+struct _NMAWsWEPKey {
+       NMAWs parent;
+
+       gboolean editing_connection;
+       const char *password_flags_name;
+
+       NMWepKeyType type;
+       char keys[4][65];
+       guint8 cur_index;
+};
+
+static void
+show_toggled_cb (GtkCheckButton *button, NMAWs *sec)
+{
+       GtkWidget *widget;
+       gboolean visible;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (sec->builder, "wep_key_entry"));
+       g_assert (widget);
+
+       visible = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+       gtk_entry_set_visibility (GTK_ENTRY (widget), visible);
+}
+
+static void
+key_index_combo_changed_cb (GtkWidget *combo, NMAWs *parent)
+{
+       NMAWsWEPKey *sec = (NMAWsWEPKey *) parent;
+       GtkWidget *entry;
+       const char *key;
+       int key_index;
+
+       /* Save WEP key for old key index */
+       entry = GTK_WIDGET (gtk_builder_get_object (parent->builder, "wep_key_entry"));
+       key = gtk_editable_get_text (GTK_EDITABLE (entry));
+       if (key)
+               g_strlcpy (sec->keys[sec->cur_index], key, sizeof (sec->keys[sec->cur_index]));
+       else
+               memset (sec->keys[sec->cur_index], 0, sizeof (sec->keys[sec->cur_index]));
+
+       key_index = gtk_combo_box_get_active (GTK_COMBO_BOX (combo));
+       g_return_if_fail (key_index <= 3);
+       g_return_if_fail (key_index >= 0);
+
+       /* Populate entry with key from new index */
+       gtk_editable_set_text (GTK_EDITABLE (entry), sec->keys[key_index]);
+       sec->cur_index = key_index;
+
+       nma_ws_changed_cb (combo, parent);
+}
+
+static void
+destroy (NMAWs *parent)
+{
+       NMAWsWEPKey *sec = (NMAWsWEPKey *) parent;
+       int i;
+
+       for (i = 0; i < 4; i++)
+               memset (sec->keys[i], 0, sizeof (sec->keys[i]));
+}
+
+static gboolean
+validate (NMAWs *parent, GError **error)
+{
+       NMAWsWEPKey *sec = (NMAWsWEPKey *) parent;
+       NMSettingSecretFlags secret_flags;
+       GtkWidget *entry;
+       const char *key;
+       int i;
+
+       entry = GTK_WIDGET (gtk_builder_get_object (parent->builder, "wep_key_entry"));
+       g_assert (entry);
+
+       secret_flags = nma_utils_menu_to_secret_flags (entry);
+       key = gtk_editable_get_text (GTK_EDITABLE (entry));
+
+        if (   secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED
+            || secret_flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED) {
+               /* All good. */
+       } else if (!key) {
+               widget_set_error (entry);
+               g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("missing wep-key"));
+               return FALSE;
+       } else if (sec->type == NM_WEP_KEY_TYPE_KEY) {
+               if ((strlen (key) == 10) || (strlen (key) == 26)) {
+                       for (i = 0; i < strlen (key); i++) {
+                               if (!g_ascii_isxdigit (key[i])) {
+                                       widget_set_error (entry);
+                                       g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, _("invalid wep-key: 
key with a length of %zu must contain only hex-digits"), strlen (key));
+                                       return FALSE;
+                               }
+                       }
+               } else if ((strlen (key) == 5) || (strlen (key) == 13)) {
+                       for (i = 0; i < strlen (key); i++) {
+                               if (!utils_char_is_ascii_print (key[i])) {
+                                       widget_set_error (entry);
+                                       g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, _("invalid wep-key: 
key with a length of %zu must contain only ascii characters"), strlen (key));
+                                       return FALSE;
+                               }
+                       }
+               } else {
+                       widget_set_error (entry);
+                       g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, _("invalid wep-key: wrong key 
length %zu. A key must be either of length 5/13 (ascii) or 10/26 (hex)"), strlen (key));
+                       return FALSE;
+               }
+       } else if (sec->type == NM_WEP_KEY_TYPE_PASSPHRASE) {
+               if (!*key || (strlen (key) > 64)) {
+                       widget_set_error (entry);
+                       if (!*key)
+                               g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("invalid wep-key: 
passphrase must be non-empty"));
+                       else
+                               g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("invalid wep-key: 
passphrase must be shorter than 64 characters"));
+                       return FALSE;
+               }
+       }
+       widget_unset_error (entry);
+
+       return TRUE;
+}
+
+static void
+add_to_size_group (NMAWs *parent, GtkSizeGroup *group)
+{
+       GtkWidget *widget;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "auth_method_label"));
+       gtk_size_group_add_widget (group, widget);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "wep_key_label"));
+       gtk_size_group_add_widget (group, widget);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "key_index_label"));
+       gtk_size_group_add_widget (group, widget);
+}
+
+static void
+fill_connection (NMAWs *parent, NMConnection *connection)
+{
+       NMAWsWEPKey *sec = (NMAWsWEPKey *) parent;
+       NMSettingWirelessSecurity *s_wsec;
+       NMSettingSecretFlags secret_flags;
+       GtkWidget *widget, *passwd_entry;
+       gint auth_alg;
+       const char *key;
+       int i;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "auth_method_combo"));
+       auth_alg = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "wep_key_entry"));
+       passwd_entry = widget;
+       key = gtk_editable_get_text (GTK_EDITABLE (widget));
+       g_strlcpy (sec->keys[sec->cur_index], key, sizeof (sec->keys[sec->cur_index]));
+
+       /* Blow away the old security setting by adding a clear one */
+       s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+       nm_connection_add_setting (connection, (NMSetting *) s_wsec);
+
+       g_object_set (s_wsec,
+                     NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none",
+                     NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, sec->cur_index,
+                     NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, (auth_alg == 1) ? "shared" : "open",
+                     NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, sec->type,
+                     NULL);
+
+       for (i = 0; i < 4; i++) {
+               if (strlen (sec->keys[i]))
+                       nm_setting_wireless_security_set_wep_key (s_wsec, i, sec->keys[i]);
+       }
+
+       /* Save WEP_KEY_FLAGS to the connection */
+       secret_flags = nma_utils_menu_to_secret_flags (passwd_entry);
+       g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS, secret_flags, NULL);
+
+       /* Update secret flags and popup when editing the connection */
+       if (sec->editing_connection)
+               nma_utils_update_password_storage (passwd_entry, secret_flags,
+                                                  NM_SETTING (s_wsec), sec->password_flags_name);
+}
+
+static void
+wep_entry_filter_cb (GtkEditable *editable,
+                     gchar *text,
+                     gint length,
+                     gint *position,
+                     gpointer data)
+{
+       NMAWsWEPKey *sec = (NMAWsWEPKey *) data;
+
+       if (sec->type == NM_WEP_KEY_TYPE_KEY) {
+               utils_filter_editable_on_insert_text (editable,
+                                                     text, length, position, data,
+                                                     utils_char_is_ascii_print,
+                                                     wep_entry_filter_cb);
+       }
+}
+
+static void
+update_secrets (NMAWs *parent, NMConnection *connection)
+{
+       NMAWsWEPKey *sec = (NMAWsWEPKey *) parent;
+       NMSettingWirelessSecurity *s_wsec;
+       GtkEditable *entry;
+       const char *tmp;
+       int i;
+
+       s_wsec = nm_connection_get_setting_wireless_security (connection);
+       for (i = 0; s_wsec && i < 4; i++) {
+               tmp = nm_setting_wireless_security_get_wep_key (s_wsec, i);
+               if (tmp)
+                       g_strlcpy (sec->keys[i], tmp, sizeof (sec->keys[i]));
+       }
+
+       entry = GTK_EDITABLE (gtk_builder_get_object (parent->builder, "wep_key_entry"));
+       if (strlen (sec->keys[sec->cur_index]))
+               gtk_editable_set_text (entry, sec->keys[sec->cur_index]);
+}
+
+NMAWsWEPKey *
+nma_ws_wep_key_new (NMConnection *connection,
+                    NMWepKeyType type,
+                    gboolean adhoc_create,
+                    gboolean secrets_only)
+{
+       NMAWs *parent;
+       NMAWsWEPKey *sec;
+       GtkWidget *widget;
+       NMSettingWirelessSecurity *s_wsec = NULL;
+       NMSetting *setting = NULL;
+       guint8 default_key_idx = 0;
+       gboolean is_adhoc = adhoc_create;
+       gboolean is_shared_key = FALSE;
+
+       parent = nma_ws_init (sizeof (NMAWsWEPKey),
+                             validate,
+                             add_to_size_group,
+                             fill_connection,
+                             update_secrets,
+                             destroy,
+                             "/org/gnome/libnma/nma-ws-wep-key.ui",
+                             "wep_key_notebook",
+                             "wep_key_entry");
+       if (!parent)
+               return NULL;
+
+       sec = (NMAWsWEPKey *) parent;
+       sec->editing_connection = secrets_only ? FALSE : TRUE;
+       sec->password_flags_name = NM_SETTING_WIRELESS_SECURITY_WEP_KEY0;
+       sec->type = type;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "wep_key_entry"));
+       g_assert (widget);
+       gtk_editable_set_width_chars (GTK_EDITABLE (widget), 28);
+
+       /* Create password-storage popup menu for password entry under entry's secondary icon */
+       if (connection)
+               setting = (NMSetting *) nm_connection_get_setting_wireless_security (connection);
+       nma_utils_setup_password_storage (widget, 0, setting, sec->password_flags_name,
+                                         FALSE, secrets_only);
+
+       if (connection) {
+               NMSettingWireless *s_wireless;
+               const char *mode, *auth_alg;
+
+               s_wireless = nm_connection_get_setting_wireless (connection);
+               mode = s_wireless ? nm_setting_wireless_get_mode (s_wireless) : NULL;
+               if (mode && !strcmp (mode, "adhoc"))
+                       is_adhoc = TRUE;
+
+               s_wsec = nm_connection_get_setting_wireless_security (connection);
+               if (s_wsec) {
+                       auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
+                       if (auth_alg && !strcmp (auth_alg, "shared"))
+                               is_shared_key = TRUE;
+               }
+       }
+
+       g_signal_connect (G_OBJECT (widget), "changed",
+                         (GCallback) nma_ws_changed_cb,
+                         sec);
+       g_signal_connect (G_OBJECT (widget), "insert-text",
+                         (GCallback) wep_entry_filter_cb,
+                         sec);
+       if (sec->type == NM_WEP_KEY_TYPE_KEY)
+               gtk_entry_set_max_length (GTK_ENTRY (widget), 26);
+       else if (sec->type == NM_WEP_KEY_TYPE_PASSPHRASE)
+               gtk_entry_set_max_length (GTK_ENTRY (widget), 64);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "key_index_combo"));
+       if (connection && s_wsec)
+               default_key_idx = nm_setting_wireless_security_get_wep_tx_keyidx (s_wsec);
+
+       gtk_combo_box_set_active (GTK_COMBO_BOX (widget), default_key_idx);
+       sec->cur_index = default_key_idx;
+       g_signal_connect (G_OBJECT (widget), "changed",
+                         (GCallback) key_index_combo_changed_cb,
+                         sec);
+
+       /* Key index is useless with adhoc networks */
+       if (is_adhoc || secrets_only) {
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "key_index_label"));
+               gtk_widget_hide (widget);
+       }
+
+       /* Fill the key entry with the key for that index */
+       if (connection)
+               update_secrets (NMA_WS (sec), connection);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "show_checkbutton_wep"));
+       g_assert (widget);
+       g_signal_connect (G_OBJECT (widget), "toggled",
+                         (GCallback) show_toggled_cb,
+                         sec);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "auth_method_combo"));
+       gtk_combo_box_set_active (GTK_COMBO_BOX (widget), is_shared_key ? 1 : 0);
+
+       g_signal_connect (G_OBJECT (widget), "changed",
+                         (GCallback) nma_ws_changed_cb,
+                         sec);
+
+       /* Don't show auth method for adhoc (which always uses open-system) or
+        * when in "simple" mode.
+        */
+       if (is_adhoc || secrets_only) {
+               /* Ad-Hoc connections can't use Shared Key auth */
+               if (is_adhoc)
+                       gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
+               gtk_widget_hide (widget);
+               widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "auth_method_label"));
+               gtk_widget_hide (widget);
+       }
+
+       return sec;
+}
diff --git a/src/nma-ws/nma-ws-wep-key.h b/src/nma-ws/nma-ws-wep-key.h
new file mode 100644
index 00000000..98ecb111
--- /dev/null
+++ b/src/nma-ws/nma-ws-wep-key.h
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#ifndef WS_WEP_KEY_H
+#define WS_WEP_KEY_H
+
+typedef struct _NMAWsWEPKey NMAWsWEPKey;
+
+NMAWsWEPKey *nma_ws_wep_key_new (NMConnection *connection,
+                                 NMWepKeyType type,
+                                 gboolean adhoc_create,
+                                 gboolean secrets_only);
+
+#endif /* WS_WEP_KEY_H */
diff --git a/src/nma-ws/nma-ws-wep-key.ui b/src/nma-ws/nma-ws-wep-key.ui
new file mode 100644
index 00000000..44ccd180
--- /dev/null
+++ b/src/nma-ws/nma-ws-wep-key.ui
@@ -0,0 +1,172 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface domain="nm-applet">
+  <requires lib="gtk+" version="3.10"/>
+  <object class="GtkListStore" id="model3">
+    <columns>
+      <!-- column-name gchararray -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">Open System</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Shared Key</col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkListStore" id="model4">
+    <columns>
+      <!-- column-name gchararray -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">1 (Default)</col>
+      </row>
+      <row>
+        <col id="0">2</col>
+      </row>
+      <row>
+        <col id="0">3</col>
+      </row>
+      <row>
+        <col id="0">4</col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkNotebook" id="wep_key_notebook">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="show_tabs">False</property>
+    <property name="show_border">False</property>
+    <child>
+      <object class="GtkGrid" id="table6">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="row_spacing">6</property>
+        <property name="column_spacing">6</property>
+        <child>
+          <object class="GtkLabel" id="wep_key_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">_Key</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">wep_key_entry</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="wep_key_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+            <property name="max_length">64</property>
+            <property name="visibility">False</property>
+            <property name="activates_default">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="show_checkbutton_wep">
+            <property name="label" translatable="yes">Sho_w key</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="hexpand">True</property>
+            <property name="use_underline">True</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="auth_method_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Au_thentication</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">auth_method_combo</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">3</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkComboBox" id="auth_method_combo">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="hexpand">True</property>
+            <property name="model">model3</property>
+            <child>
+              <object class="GtkCellRendererText" id="renderer3"/>
+              <attributes>
+                <attribute name="text">0</attribute>
+              </attributes>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">3</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="key_index_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">WEP inde_x</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">key_index_combo</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkComboBox" id="key_index_combo">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="hexpand">True</property>
+            <property name="model">model4</property>
+            <child>
+              <object class="GtkCellRendererText" id="renderer4"/>
+              <attributes>
+                <attribute name="text">0</attribute>
+              </attributes>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+      </object>
+    </child>
+    <child type="tab">
+      <object class="GtkLabel" id="label23">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+      </object>
+      <packing>
+        <property name="tab_fill">False</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/src/nma-ws/nma-ws-wpa-eap.c b/src/nma-ws/nma-ws-wpa-eap.c
new file mode 100644
index 00000000..81193840
--- /dev/null
+++ b/src/nma-ws/nma-ws-wpa-eap.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+
+#include <ctype.h>
+#include <string.h>
+
+#include "nma-ws.h"
+#include "nma-eap.h"
+
+struct _NMAWsWPAEAP {
+       NMAWs parent;
+
+       GtkSizeGroup *size_group;
+};
+
+
+static void
+destroy (NMAWs *parent)
+{
+       NMAWsWPAEAP *sec = (NMAWsWPAEAP *) parent;
+
+       if (sec->size_group)
+               g_object_unref (sec->size_group);
+}
+
+static gboolean
+validate (NMAWs *parent, GError **error)
+{
+       return nma_ws_802_1x_validate (parent, "wpa_eap_auth_combo", error);
+}
+
+static void
+add_to_size_group (NMAWs *parent, GtkSizeGroup *group)
+{
+       NMAWsWPAEAP *sec = (NMAWsWPAEAP *) parent;
+
+       if (sec->size_group)
+               g_object_unref (sec->size_group);
+       sec->size_group = g_object_ref (group);
+
+       nma_ws_802_1x_add_to_size_group (parent,
+                                        sec->size_group,
+                                        "wpa_eap_auth_label",
+                                        "wpa_eap_auth_combo");
+}
+
+static void
+fill_connection (NMAWs *parent, NMConnection *connection)
+{
+       NMSettingWirelessSecurity *s_wireless_sec;
+
+       nma_ws_802_1x_fill_connection (parent, "wpa_eap_auth_combo", connection);
+
+       s_wireless_sec = nm_connection_get_setting_wireless_security (connection);
+       g_assert (s_wireless_sec);
+
+       g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap", NULL);
+}
+
+static void
+auth_combo_changed_cb (GtkWidget *combo, gpointer user_data)
+{
+       NMAWs *parent = NMA_WS (user_data);
+       NMAWsWPAEAP *sec = (NMAWsWPAEAP *) parent;
+
+       nma_ws_802_1x_auth_combo_changed (combo,
+                                         parent,
+                                         "wpa_nma_eap_vbox",
+                                         sec->size_group);
+}
+
+static void
+update_secrets (NMAWs *parent, NMConnection *connection)
+{
+       nma_ws_802_1x_update_secrets (parent, "wpa_eap_auth_combo", connection);
+}
+
+NMAWsWPAEAP *
+nma_ws_wpa_eap_new (NMConnection *connection,
+                    gboolean is_editor,
+                    gboolean secrets_only,
+                    const char *const*secrets_hints)
+{
+       NMAWs *parent;
+       GtkWidget *widget;
+
+       parent = nma_ws_init (sizeof (NMAWsWPAEAP),
+                             validate,
+                             add_to_size_group,
+                             fill_connection,
+                             update_secrets,
+                             destroy,
+                             "/org/gnome/libnma/nma-ws-wpa-eap.ui",
+                             "wpa_eap_notebook",
+                             NULL);
+       if (!parent)
+               return NULL;
+
+       parent->adhoc_compatible = FALSE;
+       parent->hotspot_compatible = FALSE;
+
+       widget = nma_ws_802_1x_auth_combo_init (parent,
+                                               "wpa_eap_auth_combo",
+                                               "wpa_eap_auth_label",
+                                               (GCallback) auth_combo_changed_cb,
+                                               connection,
+                                               is_editor,
+                                               secrets_only,
+                                               secrets_hints);
+       auth_combo_changed_cb (widget, parent);
+
+       return (NMAWsWPAEAP *) parent;
+}
diff --git a/src/nma-ws/nma-ws-wpa-eap.h b/src/nma-ws/nma-ws-wpa-eap.h
new file mode 100644
index 00000000..e3b39beb
--- /dev/null
+++ b/src/nma-ws/nma-ws-wpa-eap.h
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#ifndef WS_WPA_EAP_H
+#define WS_WPA_EAP_H
+
+typedef struct _NMAWsWPAEAP NMAWsWPAEAP;
+
+NMAWsWPAEAP *nma_ws_wpa_eap_new (NMConnection *connection,
+                                 gboolean is_editor,
+                                 gboolean secrets_only,
+                                 const char *const*secrets_hints);
+
+#endif /* WS_WPA_EAP_H */
diff --git a/src/nma-ws/nma-ws-wpa-eap.ui b/src/nma-ws/nma-ws-wpa-eap.ui
new file mode 100644
index 00000000..42e6f0e3
--- /dev/null
+++ b/src/nma-ws/nma-ws-wpa-eap.ui
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface domain="nm-applet">
+  <requires lib="gtk+" version="3.10"/>
+  <object class="GtkListStore" id="model5">
+    <columns>
+      <!-- column-name gchararray -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0"> </col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkNotebook" id="wpa_eap_notebook">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="show_tabs">False</property>
+    <property name="show_border">False</property>
+    <child>
+      <object class="GtkGrid" id="wpa_eap_table">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="row_spacing">6</property>
+        <property name="column_spacing">6</property>
+        <child>
+          <object class="GtkLabel" id="wpa_eap_auth_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Au_thentication</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">wpa_eap_auth_combo</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkComboBox" id="wpa_eap_auth_combo">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="hexpand">True</property>
+            <property name="model">model5</property>
+            <child>
+              <object class="GtkCellRendererText" id="renderer5"/>
+              <attributes>
+                <attribute name="text">0</attribute>
+              </attributes>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox" id="wpa_nma_eap_vbox">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="hexpand">True</property>
+            <property name="orientation">vertical</property>
+            <child>
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">1</property>
+            <property name="width">2</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <child type="tab">
+      <object class="GtkLabel" id="GtkLabel3">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+      </object>
+      <packing>
+        <property name="tab_fill">False</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/src/nma-ws/nma-ws-wpa-psk.c b/src/nma-ws/nma-ws-wpa-psk.c
new file mode 100644
index 00000000..d3a8aab1
--- /dev/null
+++ b/src/nma-ws/nma-ws-wpa-psk.c
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+#include "nma-private.h"
+
+#include <ctype.h>
+#include <string.h>
+
+#include "nma-ws.h"
+#include "helpers.h"
+#include "nma-ui-utils.h"
+#include "utils.h"
+
+#define WPA_PMK_LEN 32
+
+struct _NMAWsWPAPSK {
+       NMAWs parent;
+
+       gboolean editing_connection;
+       const char *password_flags_name;
+};
+
+static void
+show_toggled_cb (GtkCheckButton *button, NMAWs *sec)
+{
+       GtkWidget *widget;
+       gboolean visible;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (sec->builder, "wpa_psk_entry"));
+       g_assert (widget);
+
+       visible = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+       gtk_entry_set_visibility (GTK_ENTRY (widget), visible);
+}
+
+static gboolean
+validate (NMAWs *parent, GError **error)
+{
+       GtkWidget *entry;
+       NMSettingSecretFlags secret_flags;
+       const char *key;
+       gsize len;
+       int i;
+
+       entry = GTK_WIDGET (gtk_builder_get_object (parent->builder, "wpa_psk_entry"));
+       g_assert (entry);
+
+       secret_flags = nma_utils_menu_to_secret_flags (entry);
+       key = gtk_editable_get_text (GTK_EDITABLE (entry));
+       len = key ? strlen (key) : 0;
+
+        if (   secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED
+            || secret_flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED) {
+               /* All good. */
+       } else if ((len < 8) || (len > 64)) {
+               widget_set_error (entry);
+               g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, _("invalid wpa-psk: invalid key-length %zu. 
Must be [8,63] bytes or 64 hex digits"), len);
+               return FALSE;
+       } else if (len == 64) {
+               /* Hex PSK */
+               for (i = 0; i < len; i++) {
+                       if (!isxdigit (key[i])) {
+                               widget_set_error (entry);
+                               g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("invalid wpa-psk: 
cannot interpret key with 64 bytes as hex"));
+                               return FALSE;
+                       }
+               }
+       }
+       widget_unset_error (entry);
+
+       /* passphrase can be between 8 and 63 characters inclusive */
+
+       return TRUE;
+}
+
+static void
+add_to_size_group (NMAWs *parent, GtkSizeGroup *group)
+{
+       GtkWidget *widget;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "wpa_psk_type_label"));
+       gtk_size_group_add_widget (group, widget);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "wpa_psk_label"));
+       gtk_size_group_add_widget (group, widget);
+}
+
+static void
+fill_connection (NMAWs *parent, NMConnection *connection)
+{
+       NMAWsWPAPSK *wpa_psk = (NMAWsWPAPSK *) parent;
+       GtkWidget *widget, *passwd_entry;
+       const char *key;
+       NMSettingWireless *s_wireless;
+       NMSettingWirelessSecurity *s_wireless_sec;
+       NMSettingSecretFlags secret_flags;
+       const char *mode;
+       gboolean is_adhoc = FALSE;
+
+       s_wireless = nm_connection_get_setting_wireless (connection);
+       g_assert (s_wireless);
+
+       mode = nm_setting_wireless_get_mode (s_wireless);
+       if (mode && !strcmp (mode, "adhoc"))
+               is_adhoc = TRUE;
+
+       /* Blow away the old security setting by adding a clear one */
+       s_wireless_sec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+       nm_connection_add_setting (connection, (NMSetting *) s_wireless_sec);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "wpa_psk_entry"));
+       passwd_entry = widget;
+       key = gtk_editable_get_text (GTK_EDITABLE (widget));
+       g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_PSK, key, NULL);
+
+       /* Save PSK_FLAGS to the connection */
+       secret_flags = nma_utils_menu_to_secret_flags (passwd_entry);
+       nm_setting_set_secret_flags (NM_SETTING (s_wireless_sec), NM_SETTING_WIRELESS_SECURITY_PSK,
+                                    secret_flags, NULL);
+
+       /* Update secret flags and popup when editing the connection */
+       if (wpa_psk->editing_connection)
+               nma_utils_update_password_storage (passwd_entry, secret_flags,
+                                                  NM_SETTING (s_wireless_sec), wpa_psk->password_flags_name);
+
+       nma_ws_clear_ciphers (connection);
+       if (is_adhoc) {
+               /* Ad-Hoc settings as specified by the supplicant */
+               g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", NULL);
+               nm_setting_wireless_security_add_proto (s_wireless_sec, "rsn");
+               nm_setting_wireless_security_add_pairwise (s_wireless_sec, "ccmp");
+               nm_setting_wireless_security_add_group (s_wireless_sec, "ccmp");
+       } else {
+               g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", NULL);
+
+               /* Just leave ciphers and protocol empty, the supplicant will
+                * figure that out magically based on the AP IEs and card capabilities.
+                */
+       }
+}
+
+static void
+update_secrets (NMAWs *parent, NMConnection *connection)
+{
+       helper_fill_secret_entry (connection,
+                                 parent->builder,
+                                 "wpa_psk_entry",
+                                 NM_TYPE_SETTING_WIRELESS_SECURITY,
+                                 (HelperSecretFunc) nm_setting_wireless_security_get_psk);
+}
+
+NMAWsWPAPSK *
+nma_ws_wpa_psk_new (NMConnection *connection, gboolean secrets_only)
+{
+       NMAWs *parent;
+       NMAWsWPAPSK *sec;
+       NMSetting *setting = NULL;
+       GtkWidget *widget;
+
+       parent = nma_ws_init (sizeof (NMAWsWPAPSK),
+                             validate,
+                             add_to_size_group,
+                             fill_connection,
+                             update_secrets,
+                             NULL,
+                             "/org/gnome/libnma/nma-ws-wpa-psk.ui",
+                             "wpa_psk_notebook",
+                             "wpa_psk_entry");
+       if (!parent)
+               return NULL;
+
+       parent->adhoc_compatible = TRUE;
+       sec = (NMAWsWPAPSK *) parent;
+       sec->editing_connection = secrets_only ? FALSE : TRUE;
+       sec->password_flags_name = NM_SETTING_WIRELESS_SECURITY_PSK;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "wpa_psk_entry"));
+       g_assert (widget);
+       g_signal_connect (G_OBJECT (widget), "changed",
+                         (GCallback) nma_ws_changed_cb,
+                         sec);
+       gtk_editable_set_width_chars (GTK_EDITABLE (widget), 28);
+
+       /* Create password-storage popup menu for password entry under entry's secondary icon */
+       if (connection)
+               setting = (NMSetting *) nm_connection_get_setting_wireless_security (connection);
+       nma_utils_setup_password_storage (widget, 0, setting, sec->password_flags_name,
+                                         FALSE, secrets_only);
+
+       /* Fill secrets, if any */
+       if (connection)
+               update_secrets (NMA_WS (sec), connection);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "show_checkbutton_wpa"));
+       g_assert (widget);
+       g_signal_connect (G_OBJECT (widget), "toggled",
+                         (GCallback) show_toggled_cb,
+                         sec);
+
+       /* Hide WPA/RSN for now since this can be autodetected by NM and the
+        * supplicant when connecting to the AP.
+        */
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "wpa_psk_type_combo"));
+       g_assert (widget);
+       gtk_widget_hide (widget);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "wpa_psk_type_label"));
+       g_assert (widget);
+       gtk_widget_hide (widget);
+
+       return sec;
+}
diff --git a/src/nma-ws/nma-ws-wpa-psk.h b/src/nma-ws/nma-ws-wpa-psk.h
new file mode 100644
index 00000000..216853dd
--- /dev/null
+++ b/src/nma-ws/nma-ws-wpa-psk.h
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#ifndef WS_WPA_PSK_H
+#define WS_WPA_PSK_H
+
+typedef struct _NMAWsWPAPSK NMAWsWPAPSK;
+
+NMAWsWPAPSK *nma_ws_wpa_psk_new (NMConnection *connection, gboolean secrets_only);
+
+#endif /* WS_WEP_KEY_H */
diff --git a/src/nma-ws/nma-ws-wpa-psk.ui b/src/nma-ws/nma-ws-wpa-psk.ui
new file mode 100644
index 00000000..ace15468
--- /dev/null
+++ b/src/nma-ws/nma-ws-wpa-psk.ui
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface domain="nm-applet">
+  <requires lib="gtk+" version="3.10"/>
+  <object class="GtkNotebook" id="wpa_psk_notebook">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="show_tabs">False</property>
+    <property name="show_border">False</property>
+    <child>
+      <object class="GtkGrid" id="wpa_psk_table">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="row_spacing">6</property>
+        <property name="column_spacing">6</property>
+        <child>
+          <object class="GtkLabel" id="wpa_psk_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">_Password</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">wpa_psk_entry</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="wpa_psk_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+            <property name="max_length">64</property>
+            <property name="visibility">False</property>
+            <property name="activates_default">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="wpa_psk_type_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">_Type</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">wpa_psk_type_combo</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="show_checkbutton_wpa">
+            <property name="label" translatable="yes">Sho_w password</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="hexpand">True</property>
+            <property name="use_underline">True</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkComboBox" id="wpa_psk_type_combo">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+      </object>
+    </child>
+    <child type="tab">
+      <object class="GtkLabel" id="GtkLabel2">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+      </object>
+      <packing>
+        <property name="tab_fill">False</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/src/nma-ws/nma-ws.c b/src/nma-ws/nma-ws.c
new file mode 100644
index 00000000..9f0cb94d
--- /dev/null
+++ b/src/nma-ws/nma-ws.c
@@ -0,0 +1,593 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+
+#include <string.h>
+
+#include "nma-ws.h"
+#include "nma-eap.h"
+#include "utils.h"
+
+G_DEFINE_BOXED_TYPE (NMAWs, nma_ws, nma_ws_ref, nma_ws_unref)
+
+GtkWidget *
+nma_ws_get_widget (NMAWs *sec)
+{
+       g_return_val_if_fail (sec != NULL, NULL);
+
+       return sec->ui_widget;
+}
+
+void
+nma_ws_set_changed_notify (NMAWs *sec,
+                           NMAWsChangedFunc func,
+                           gpointer user_data)
+{
+       g_return_if_fail (sec != NULL);
+
+       sec->changed_notify = func;
+       sec->changed_notify_data = user_data;
+}
+
+void
+nma_ws_changed_cb (GtkWidget *ignored, gpointer user_data)
+{
+       NMAWs *sec = NMA_WS (user_data);
+
+       if (sec->changed_notify)
+               (*(sec->changed_notify)) (sec, sec->changed_notify_data);
+}
+
+gboolean
+nma_ws_validate (NMAWs *sec, GError **error)
+{
+       gboolean result;
+
+       g_return_val_if_fail (sec != NULL, FALSE);
+       g_return_val_if_fail (!error || !*error, FALSE);
+
+       g_assert (sec->validate);
+       result = (*(sec->validate)) (sec, error);
+       if (!result && error && !*error)
+               g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("Unknown error validating 802.1X 
security"));
+       return result;
+}
+
+void
+nma_ws_add_to_size_group (NMAWs *sec, GtkSizeGroup *group)
+{
+       g_return_if_fail (sec != NULL);
+       g_return_if_fail (group != NULL);
+
+       g_assert (sec->add_to_size_group);
+       return (*(sec->add_to_size_group)) (sec, group);
+}
+
+void
+nma_ws_fill_connection (NMAWs *sec,
+                        NMConnection *connection)
+{
+       g_return_if_fail (sec != NULL);
+       g_return_if_fail (connection != NULL);
+
+       g_assert (sec->fill_connection);
+       return (*(sec->fill_connection)) (sec, connection);
+}
+
+void
+nma_ws_update_secrets (NMAWs *sec, NMConnection *connection)
+{
+       g_return_if_fail (sec != NULL);
+       g_return_if_fail (connection != NULL);
+
+       if (sec->update_secrets)
+               sec->update_secrets (sec, connection);
+}
+
+NMAWs *
+nma_ws_ref (NMAWs *sec)
+{
+       g_return_val_if_fail (sec != NULL, NULL);
+       g_return_val_if_fail (sec->refcount > 0, NULL);
+
+       sec->refcount++;
+       return sec;
+}
+
+void
+nma_ws_unref (NMAWs *sec)
+{
+       g_return_if_fail (sec != NULL);
+       g_return_if_fail (sec->refcount > 0);
+
+       sec->refcount--;
+       if (sec->refcount == 0) {
+               if (sec->destroy)
+                       sec->destroy (sec);
+
+               g_free (sec->username);
+               if (sec->password) {
+                       memset (sec->password, 0, strlen (sec->password));
+                       g_free (sec->password);
+               }
+
+               if (sec->builder)
+                       g_object_unref (sec->builder);
+               if (sec->ui_widget)
+                       g_object_unref (sec->ui_widget);
+               g_slice_free1 (sec->obj_size, sec);
+       }
+}
+
+NMAWs *
+nma_ws_init (gsize obj_size,
+             NMAWsValidateFunc validate,
+             NMAWsAddToSizeGroupFunc add_to_size_group,
+             NMAWsFillConnectionFunc fill_connection,
+             NMAWsUpdateSecretsFunc update_secrets,
+             NMAWsDestroyFunc destroy,
+             const char *ui_resource,
+             const char *ui_widget_name,
+             const char *default_field)
+{
+       NMAWs *sec;
+       GError *error = NULL;
+
+       g_return_val_if_fail (obj_size > 0, NULL);
+       g_return_val_if_fail (ui_resource != NULL, NULL);
+       g_return_val_if_fail (ui_widget_name != NULL, NULL);
+
+       sec = g_slice_alloc0 (obj_size);
+       g_assert (sec);
+
+       sec->refcount = 1;
+       sec->obj_size = obj_size;
+
+       sec->validate = validate;
+       sec->add_to_size_group = add_to_size_group;
+       sec->fill_connection = fill_connection;
+       sec->update_secrets = update_secrets;
+       sec->default_field = default_field;
+
+       sec->builder = gtk_builder_new ();
+       if (!gtk_builder_add_from_resource (sec->builder, ui_resource, &error)) {
+               g_warning ("Couldn't load UI builder resource %s: %s",
+                          ui_resource, error->message);
+               g_error_free (error);
+               nma_ws_unref (sec);
+               return NULL;
+       }
+
+       sec->ui_widget = GTK_WIDGET (gtk_builder_get_object (sec->builder, ui_widget_name));
+       if (!sec->ui_widget) {
+               g_warning ("Couldn't load UI widget '%s' from UI file %s",
+                          ui_widget_name, ui_resource);
+               nma_ws_unref (sec);
+               return NULL;
+       }
+       g_object_ref_sink (sec->ui_widget);
+
+       sec->destroy = destroy;
+       sec->adhoc_compatible = TRUE;
+       sec->hotspot_compatible = TRUE;
+
+       return sec;
+}
+
+gboolean
+nma_ws_adhoc_compatible (NMAWs *sec)
+{
+       g_return_val_if_fail (sec != NULL, FALSE);
+
+       return sec->adhoc_compatible;
+}
+
+gboolean
+nma_ws_hotspot_compatible (NMAWs *sec)
+{
+       g_return_val_if_fail (sec != NULL, FALSE);
+
+       return sec->hotspot_compatible;
+}
+
+void
+nma_ws_set_userpass (NMAWs *sec,
+                     const char *user,
+                     const char *password,
+                     gboolean always_ask,
+                     gboolean show_password)
+{
+       g_free (sec->username);
+       sec->username = g_strdup (user);
+
+       if (sec->password) {
+               memset (sec->password, 0, strlen (sec->password));
+               g_free (sec->password);
+       }
+       sec->password = g_strdup (password);
+
+       if (always_ask != (gboolean) -1)
+               sec->always_ask = always_ask;
+       sec->show_password = show_password;
+}
+
+void
+nma_ws_set_userpass_802_1x (NMAWs *sec,
+                            NMConnection *connection)
+{
+       const char *user = NULL, *password = NULL;
+       gboolean always_ask = FALSE, show_password = FALSE;
+       NMSetting8021x  *setting;
+       NMSettingSecretFlags flags;
+
+       if (!connection)
+               goto set;
+
+       setting = nm_connection_get_setting_802_1x (connection);
+       if (!setting)
+               goto set;
+
+       user = nm_setting_802_1x_get_identity (setting);
+       password = nm_setting_802_1x_get_password (setting);
+
+       if (nm_setting_get_secret_flags (NM_SETTING (setting), NM_SETTING_802_1X_PASSWORD, &flags, NULL))
+               always_ask = !!(flags & NM_SETTING_SECRET_FLAG_NOT_SAVED);
+
+set:
+       nma_ws_set_userpass (sec, user, password, always_ask, show_password);
+}
+
+void
+nma_ws_clear_ciphers (NMConnection *connection)
+{
+       NMSettingWirelessSecurity *s_wireless_sec;
+
+       g_return_if_fail (connection != NULL);
+
+       s_wireless_sec = nm_connection_get_setting_wireless_security (connection);
+       g_assert (s_wireless_sec);
+
+       nm_setting_wireless_security_clear_protos (s_wireless_sec);
+       nm_setting_wireless_security_clear_pairwise (s_wireless_sec);
+       nm_setting_wireless_security_clear_groups (s_wireless_sec);
+}
+
+void
+nma_ws_802_1x_add_to_size_group (NMAWs *sec,
+                                 GtkSizeGroup *size_group,
+                                 const char *label_name,
+                                 const char *combo_name)
+{
+       GtkWidget *widget;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       NMAEap *eap;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (sec->builder, label_name));
+       g_assert (widget);
+       gtk_size_group_add_widget (size_group, widget);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (sec->builder, combo_name));
+       g_assert (widget);
+
+       model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
+       gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter);
+       gtk_tree_model_get (model, &iter, AUTH_METHOD_COLUMN, &eap, -1);
+       g_assert (eap);
+       nma_eap_add_to_size_group (eap, size_group);
+       nma_eap_unref (eap);
+}
+
+gboolean
+nma_ws_802_1x_validate (NMAWs *sec, const char *combo_name, GError **error)
+{
+       GtkWidget *widget;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       NMAEap *eap = NULL;
+       gboolean valid = FALSE;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (sec->builder, combo_name));
+       g_assert (widget);
+
+       model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
+       gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter);
+       gtk_tree_model_get (model, &iter, AUTH_METHOD_COLUMN, &eap, -1);
+       g_assert (eap);
+       valid = nma_eap_validate (eap, error);
+       nma_eap_unref (eap);
+       return valid;
+}
+
+void
+nma_ws_802_1x_auth_combo_changed (GtkWidget *combo,
+                                  NMAWs *sec,
+                                  const char *vbox_name,
+                                  GtkSizeGroup *size_group)
+{
+       GtkWidget *vbox;
+       NMAEap *eap = NULL;
+       GList *elt, *children;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       GtkWidget *eap_widget;
+       GtkWidget *eap_default_widget = NULL;
+
+       vbox = GTK_WIDGET (gtk_builder_get_object (sec->builder, vbox_name));
+       g_assert (vbox);
+
+       /* Remove any previous wireless security widgets */
+       children = gtk_container_get_children (GTK_CONTAINER (vbox));
+       for (elt = children; elt; elt = g_list_next (elt))
+               gtk_container_remove (GTK_CONTAINER (vbox), GTK_WIDGET (elt->data));
+
+       model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
+       gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter);
+       gtk_tree_model_get (model, &iter, AUTH_METHOD_COLUMN, &eap, -1);
+       g_assert (eap);
+
+       eap_widget = nma_eap_get_widget (eap);
+       g_assert (eap_widget);
+       gtk_widget_unparent (eap_widget);
+
+       if (size_group)
+               nma_eap_add_to_size_group (eap, size_group);
+       gtk_container_add (GTK_CONTAINER (vbox), eap_widget);
+
+       /* Refocus the EAP method's default widget */
+       if (eap->default_field) {
+               eap_default_widget = GTK_WIDGET (gtk_builder_get_object (eap->builder, eap->default_field));
+               if (eap_default_widget)
+                       gtk_widget_grab_focus (eap_default_widget);
+       }
+
+       nma_eap_unref (eap);
+
+       nma_ws_changed_cb (combo, NMA_WS (sec));
+}
+
+GtkWidget *
+nma_ws_802_1x_auth_combo_init (NMAWs *sec,
+                               const char *combo_name,
+                               const char *combo_label,
+                               GCallback auth_combo_changed_cb,
+                               NMConnection *connection,
+                               gboolean is_editor,
+                               gboolean secrets_only,
+                               const char *const*secrets_hints)
+{
+       GtkWidget *combo, *widget;
+       GtkListStore *auth_model;
+       GtkTreeIter iter;
+       NMAEapSimple *em_md5;
+       NMAEapTLS *em_tls;
+       NMAEapLEAP *em_leap;
+       NMAEapSimple *em_pwd;
+       NMAEapFAST *em_fast;
+       NMAEapTTLS *em_ttls;
+       NMAEapPEAP *em_peap;
+       const char *default_method = NULL, *ctype = NULL;
+       int active = -1, item = 0;
+       gboolean wired = FALSE;
+       NMAEapSimpleFlags simple_flags = NMA_EAP_SIMPLE_FLAG_NONE;
+
+       /* Grab the default EAP method out of the security object */
+       if (connection) {
+               NMSettingConnection *s_con;
+               NMSetting8021x *s_8021x;
+
+               s_con = nm_connection_get_setting_connection (connection);
+               if (s_con)
+                       ctype = nm_setting_connection_get_connection_type (s_con);
+               if (   (g_strcmp0 (ctype, NM_SETTING_WIRED_SETTING_NAME) == 0)
+                   || nm_connection_get_setting_wired (connection))
+                       wired = TRUE;
+
+               s_8021x = nm_connection_get_setting_802_1x (connection);
+               if (s_8021x && nm_setting_802_1x_get_num_eap_methods (s_8021x))
+                       default_method = nm_setting_802_1x_get_eap_method (s_8021x, 0);
+       }
+
+       /* initialize NMAWs userpass from connection (clear if no connection) */
+       nma_ws_set_userpass_802_1x (sec, connection);
+
+       auth_model = gtk_list_store_new (2, G_TYPE_STRING, nma_eap_get_type ());
+
+       if (is_editor)
+               simple_flags |= NMA_EAP_SIMPLE_FLAG_IS_EDITOR;
+       if (secrets_only)
+               simple_flags |= NMA_EAP_SIMPLE_FLAG_SECRETS_ONLY;
+
+       if (wired) {
+               em_md5 = nma_eap_simple_new (sec, connection, NMA_EAP_SIMPLE_TYPE_MD5, simple_flags, NULL);
+               gtk_list_store_append (auth_model, &iter);
+               gtk_list_store_set (auth_model, &iter,
+                                   AUTH_NAME_COLUMN, _("MD5"),
+                                   AUTH_METHOD_COLUMN, em_md5,
+                                   -1);
+               nma_eap_unref (NMA_EAP (em_md5));
+               if (default_method && (active < 0) && !strcmp (default_method, "md5"))
+                       active = item;
+               item++;
+       }
+
+       em_tls = nma_eap_tls_new (sec, connection, FALSE, secrets_only);
+       gtk_list_store_append (auth_model, &iter);
+       gtk_list_store_set (auth_model, &iter,
+                           AUTH_NAME_COLUMN, _("TLS"),
+                           AUTH_METHOD_COLUMN, em_tls,
+                           -1);
+       nma_eap_unref (NMA_EAP (em_tls));
+       if (default_method && (active < 0) && !strcmp (default_method, "tls"))
+               active = item;
+       item++;
+
+       if (!wired) {
+               em_leap = nma_eap_leap_new (sec, connection, secrets_only);
+               gtk_list_store_append (auth_model, &iter);
+               gtk_list_store_set (auth_model, &iter,
+                                   AUTH_NAME_COLUMN, _("LEAP"),
+                                   AUTH_METHOD_COLUMN, em_leap,
+                                   -1);
+               nma_eap_unref (NMA_EAP (em_leap));
+               if (default_method && (active < 0) && !strcmp (default_method, "leap"))
+                       active = item;
+               item++;
+       }
+
+       em_pwd = nma_eap_simple_new (sec, connection, NMA_EAP_SIMPLE_TYPE_PWD, simple_flags, NULL);
+       gtk_list_store_append (auth_model, &iter);
+       gtk_list_store_set (auth_model, &iter,
+                           AUTH_NAME_COLUMN, _("PWD"),
+                           AUTH_METHOD_COLUMN, em_pwd,
+                           -1);
+       nma_eap_unref (NMA_EAP (em_pwd));
+       if (default_method && (active < 0) && !strcmp (default_method, "pwd"))
+               active = item;
+       item++;
+
+       em_fast = nma_eap_fast_new (sec, connection, is_editor, secrets_only);
+       gtk_list_store_append (auth_model, &iter);
+       gtk_list_store_set (auth_model, &iter,
+                           AUTH_NAME_COLUMN, _("FAST"),
+                           AUTH_METHOD_COLUMN, em_fast,
+                           -1);
+       nma_eap_unref (NMA_EAP (em_fast));
+       if (default_method && (active < 0) && !strcmp (default_method, "fast"))
+               active = item;
+       item++;
+
+       em_ttls = nma_eap_ttls_new (sec, connection, is_editor, secrets_only);
+       gtk_list_store_append (auth_model, &iter);
+       gtk_list_store_set (auth_model, &iter,
+                           AUTH_NAME_COLUMN, _("Tunneled TLS"),
+                           AUTH_METHOD_COLUMN, em_ttls,
+                           -1);
+       nma_eap_unref (NMA_EAP (em_ttls));
+       if (default_method && (active < 0) && !strcmp (default_method, "ttls"))
+               active = item;
+       item++;
+
+       em_peap = nma_eap_peap_new (sec, connection, is_editor, secrets_only);
+       gtk_list_store_append (auth_model, &iter);
+       gtk_list_store_set (auth_model, &iter,
+                           AUTH_NAME_COLUMN, _("Protected EAP (PEAP)"),
+                           AUTH_METHOD_COLUMN, em_peap,
+                           -1);
+       nma_eap_unref (NMA_EAP (em_peap));
+       if (default_method && (active < 0) && !strcmp (default_method, "peap"))
+               active = item;
+       item++;
+
+       if (secrets_hints && secrets_hints[0]) {
+               NMAEapSimple *em_hints;
+
+               em_hints = nma_eap_simple_new (sec, connection, NMA_EAP_SIMPLE_TYPE_UNKNOWN,
+                                                 simple_flags, secrets_hints);
+               gtk_list_store_append (auth_model, &iter);
+               gtk_list_store_set (auth_model, &iter,
+                                   AUTH_NAME_COLUMN, _("Unknown"),
+                                   AUTH_METHOD_COLUMN, em_hints,
+                                   -1);
+               nma_eap_unref (NMA_EAP (em_hints));
+               active = item;
+               item++;
+       } else if (default_method && !strcmp (default_method, "external")) {
+               NMAEapSimple *em_extern;
+               const char *empty_hints[] = { NULL };
+
+               em_extern = nma_eap_simple_new (sec, connection, NMA_EAP_SIMPLE_TYPE_UNKNOWN,
+                                                  simple_flags, empty_hints);
+               gtk_list_store_append (auth_model, &iter);
+               gtk_list_store_set (auth_model, &iter,
+                                   AUTH_NAME_COLUMN, _("Externally configured"),
+                                   AUTH_METHOD_COLUMN, em_extern,
+                                   -1);
+               nma_eap_unref (NMA_EAP (em_extern));
+                       active = item;
+               item++;
+       }
+
+       combo = GTK_WIDGET (gtk_builder_get_object (sec->builder, combo_name));
+       g_assert (combo);
+
+       gtk_combo_box_set_model (GTK_COMBO_BOX (combo), GTK_TREE_MODEL (auth_model));
+       g_object_unref (G_OBJECT (auth_model));
+       gtk_combo_box_set_active (GTK_COMBO_BOX (combo), active < 0 ? 0 : (guint32) active);
+
+       g_signal_connect (G_OBJECT (combo), "changed", auth_combo_changed_cb, sec);
+
+       if (secrets_only) {
+               gtk_widget_hide (combo);
+               widget = GTK_WIDGET (gtk_builder_get_object (sec->builder, combo_label));
+               gtk_widget_hide (widget);
+       }
+
+       return combo;
+}
+
+void
+nma_ws_802_1x_fill_connection (NMAWs *sec,
+                               const char *combo_name,
+                               NMConnection *connection)
+{
+       GtkWidget *widget;
+       NMSettingWirelessSecurity *s_wireless_sec;
+       NMSetting8021x *s_8021x;
+       NMAEap *eap = NULL;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+
+       /* Get the NMAEap object */
+       widget = GTK_WIDGET (gtk_builder_get_object (sec->builder, combo_name));
+       model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
+       gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter);
+       gtk_tree_model_get (model, &iter, AUTH_METHOD_COLUMN, &eap, -1);
+       g_assert (eap);
+
+       /* Blow away the old wireless security setting by adding a clear one */
+       s_wireless_sec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+       nm_connection_add_setting (connection, (NMSetting *) s_wireless_sec);
+
+       /* Blow away the old 802.1x setting by adding a clear one */
+       s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
+       nm_connection_add_setting (connection, (NMSetting *) s_8021x);
+
+       nma_eap_fill_connection (eap, connection);
+       nma_eap_unref (eap);
+}
+
+void
+nma_ws_802_1x_update_secrets (NMAWs *sec,
+                              const char *combo_name,
+                              NMConnection *connection)
+{
+       GtkWidget *widget;
+       NMAEap *eap = NULL;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+
+       g_return_if_fail (sec != NULL);
+       g_return_if_fail (combo_name != NULL);
+       g_return_if_fail (connection != NULL);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (sec->builder, combo_name));
+       g_return_if_fail (widget != NULL);
+       model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
+
+       /* Let each EAP method try to update its secrets */
+       if (gtk_tree_model_get_iter_first (model, &iter)) {
+               do {
+                       gtk_tree_model_get (model, &iter, AUTH_METHOD_COLUMN, &eap, -1);
+                       if (eap) {
+                               nma_eap_update_secrets (eap, connection);
+                               nma_eap_unref (eap);
+                       }
+               } while (gtk_tree_model_iter_next (model, &iter));
+       }
+}
diff --git a/src/nma-ws/nma-ws.h b/src/nma-ws/nma-ws.h
new file mode 100644
index 00000000..660bc3b4
--- /dev/null
+++ b/src/nma-ws/nma-ws.h
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#ifndef NMA_WS_H
+#define NMA_WS_H
+
+typedef struct _NMAWs NMAWs;
+GType nma_ws_get_type (void);
+
+#define NMA_TYPE_WS (nma_ws_get_type ())
+#define NMA_WS(x) ((NMAWs *) x)
+
+typedef void (*NMAWsChangedFunc) (NMAWs *sec, gpointer user_data);
+
+typedef void (*NMAWsAddToSizeGroupFunc) (NMAWs *sec, GtkSizeGroup *group);
+typedef void (*NMAWsFillConnectionFunc) (NMAWs *sec, NMConnection *connection);
+typedef void (*NMAWsUpdateSecretsFunc)  (NMAWs *sec, NMConnection *connection);
+typedef void (*NMAWsDestroyFunc)        (NMAWs *sec);
+typedef gboolean (*NMAWsValidateFunc)   (NMAWs *sec, GError **error);
+typedef GtkWidget * (*NMAWsNagUserFunc) (NMAWs *sec);
+
+struct _NMAWs {
+       guint32 refcount;
+       gsize obj_size;
+       GtkBuilder *builder;
+       GtkWidget *ui_widget;
+       NMAWsChangedFunc changed_notify;
+       gpointer changed_notify_data;
+       const char *default_field;
+       gboolean adhoc_compatible;
+       gboolean hotspot_compatible;
+
+       char *username, *password;
+       gboolean always_ask, show_password;
+
+       NMAWsAddToSizeGroupFunc add_to_size_group;
+       NMAWsFillConnectionFunc fill_connection;
+       NMAWsUpdateSecretsFunc update_secrets;
+       NMAWsValidateFunc validate;
+       NMAWsDestroyFunc destroy;
+};
+
+GtkWidget *nma_ws_get_widget (NMAWs *sec);
+
+void nma_ws_set_changed_notify (NMAWs *sec,
+                                NMAWsChangedFunc func,
+                                gpointer user_data);
+
+gboolean nma_ws_validate (NMAWs *sec, GError **error);
+
+void nma_ws_add_to_size_group (NMAWs *sec,
+                               GtkSizeGroup *group);
+
+void nma_ws_fill_connection (NMAWs *sec,
+                             NMConnection *connection);
+
+void nma_ws_update_secrets (NMAWs *sec,
+                            NMConnection *connection);
+
+gboolean nma_ws_adhoc_compatible (NMAWs *sec);
+
+gboolean nma_ws_hotspot_compatible (NMAWs *sec);
+
+void nma_ws_set_userpass (NMAWs *sec,
+                          const char *user,
+                          const char *password,
+                          gboolean always_ask,
+                          gboolean show_password);
+void nma_ws_set_userpass_802_1x (NMAWs *sec,
+                                 NMConnection *connection);
+
+NMAWs *nma_ws_ref (NMAWs *sec);
+
+void nma_ws_unref (NMAWs *sec);
+
+/* Below for internal use only */
+
+#include "nma-ws-sae.h"
+#include "nma-ws-wep-key.h"
+#include "nma-ws-wpa-psk.h"
+#include "nma-ws-leap.h"
+#include "nma-ws-wpa-eap.h"
+#include "nma-ws-dynamic-wep.h"
+
+NMAWs *nma_ws_init (gsize obj_size,
+                    NMAWsValidateFunc validate,
+                    NMAWsAddToSizeGroupFunc add_to_size_group,
+                    NMAWsFillConnectionFunc fill_connection,
+                    NMAWsUpdateSecretsFunc update_secrets,
+                    NMAWsDestroyFunc destroy,
+                    const char *ui_resource,
+                    const char *ui_widget_name,
+                    const char *default_field);
+
+void nma_ws_changed_cb (GtkWidget *entry, gpointer user_data);
+
+void nma_ws_clear_ciphers (NMConnection *connection);
+
+#define AUTH_NAME_COLUMN   0
+#define AUTH_METHOD_COLUMN 1
+
+GtkWidget *nma_ws_802_1x_auth_combo_init (NMAWs *sec,
+                                          const char *combo_name,
+                                          const char *combo_label,
+                                          GCallback auth_combo_changed_cb,
+                                          NMConnection *connection,
+                                          gboolean is_editor,
+                                          gboolean secrets_only,
+                                          const char *const*secrets_hints);
+
+void nma_ws_802_1x_auth_combo_changed (GtkWidget *combo,
+                                       NMAWs *sec,
+                                       const char *vbox_name,
+                                       GtkSizeGroup *size_group);
+
+gboolean nma_ws_802_1x_validate (NMAWs *sec, const char *combo_name, GError **error);
+
+void nma_ws_802_1x_add_to_size_group (NMAWs *sec,
+                                      GtkSizeGroup *size_group,
+                                      const char *label_name,
+                                      const char *combo_name);
+
+void nma_ws_802_1x_fill_connection (NMAWs *sec,
+                                    const char *combo_name,
+                                    NMConnection *connection);
+
+void nma_ws_802_1x_update_secrets (NMAWs *sec,
+                                   const char *combo_name,
+                                   NMConnection *connection);
+
+#endif /* NMA_WS_H */
diff --git a/src/nma.gresource.xml b/src/nma.gresource.xml
index cfe41a7f..569aa275 100644
--- a/src/nma.gresource.xml
+++ b/src/nma.gresource.xml
@@ -7,5 +7,17 @@
                <file preprocess="xml-stripblanks">nma-mobile-wizard.ui</file>
                <file preprocess="xml-stripblanks">nma-vpn-password-dialog.ui</file>
                <file preprocess="xml-stripblanks">nma-bar-code-widget.ui</file>
+                <file preprocess="xml-stripblanks" 
alias="nma-ws-dynamic-wep.ui">nma-ws/nma-ws-dynamic-wep.ui</file>
+                <file preprocess="xml-stripblanks" alias="nma-ws-leap.ui">nma-ws/nma-ws-leap.ui</file>
+                <file preprocess="xml-stripblanks" alias="nma-ws-sae.ui">nma-ws/nma-ws-sae.ui</file>
+                <file preprocess="xml-stripblanks" alias="nma-ws-wep-key.ui">nma-ws/nma-ws-wep-key.ui</file>
+                <file preprocess="xml-stripblanks" alias="nma-ws-wpa-eap.ui">nma-ws/nma-ws-wpa-eap.ui</file>
+                <file preprocess="xml-stripblanks" alias="nma-ws-wpa-psk.ui">nma-ws/nma-ws-wpa-psk.ui</file>
+                <file preprocess="xml-stripblanks" alias="nma-eap-fast.ui">nma-ws/nma-eap-fast.ui</file>
+                <file preprocess="xml-stripblanks" alias="nma-eap-leap.ui">nma-ws/nma-eap-leap.ui</file>
+                <file preprocess="xml-stripblanks" alias="nma-eap-peap.ui">nma-ws/nma-eap-peap.ui</file>
+                <file preprocess="xml-stripblanks" alias="nma-eap-simple.ui">nma-ws/nma-eap-simple.ui</file>
+                <file preprocess="xml-stripblanks" alias="nma-eap-tls.ui">nma-ws/nma-eap-tls.ui</file>
+                <file preprocess="xml-stripblanks" alias="nma-eap-ttls.ui">nma-ws/nma-eap-ttls.ui</file>
        </gresource>
 </gresources>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]